1*1918Swnj /* ts.c 4.2 12/17/80 */ 21900Swnj 31900Swnj #include "../conf/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" 191900Swnj 201900Swnj struct device { 21*1918Swnj u_short tsdb; 22*1918Swnj u_short tssr; 231900Swnj }; 241900Swnj 251900Swnj struct buf tstab; 261900Swnj struct buf rtsbuf; 271900Swnj struct buf ctsbuf; 281900Swnj 291900Swnj #define INF 1000000000 301900Swnj 31*1918Swnj u_short ts_uba; 321900Swnj long ts_iouba; 331900Swnj char ts_flags; 341900Swnj char ts_openf; 351900Swnj daddr_t ts_blkno; 361900Swnj daddr_t ts_nxrec; 371900Swnj 381900Swnj /* status message */ 391900Swnj struct sts { 40*1918Swnj u_short s_sts; 41*1918Swnj u_short xs0; 42*1918Swnj u_short xs1; 43*1918Swnj u_short xs2; 44*1918Swnj u_short xs3; 451900Swnj }; 461900Swnj 471900Swnj /* Error codes in stat 0 */ 481900Swnj #define TMK 0100000 491900Swnj #define RLS 040000 501900Swnj #define ONL 0100 511900Swnj #define WLE 04000 521900Swnj 531900Swnj /* command message */ 541900Swnj struct cmd { 55*1918Swnj u_short c_cmd; 56*1918Swnj u_short c_loba; 57*1918Swnj u_short c_hiba; 58*1918Swnj u_short c_size; 591900Swnj }; 601900Swnj 611900Swnj #define ACK 0100000 621900Swnj #define CVC 040000 631900Swnj #define IE 0200 641900Swnj #define READ 01 651900Swnj #define REREAD 01001 661900Swnj 671900Swnj #define SETCHR 04 681900Swnj 691900Swnj #define WRITE 05 701900Swnj #define REWRITE 01005 711900Swnj 721900Swnj #define SFORW 010 731900Swnj #define SREV 0410 741900Swnj #define REW 02010 751900Swnj 761900Swnj #define WTM 011 771900Swnj 781900Swnj #define GSTAT 017 791900Swnj 801900Swnj /* characteristics data */ 811900Swnj struct charac { 82*1918Swnj u_short char_loba; 83*1918Swnj u_short char_hiba; 84*1918Swnj u_short char_size; 85*1918Swnj u_short char_mode; 861900Swnj }; 871900Swnj 881900Swnj /* All the packets, collected */ 891900Swnj struct tsmesg { 901900Swnj struct cmd ts_cmd; 911900Swnj struct sts ts_sts; 921900Swnj struct charac ts_char; 931900Swnj int align; /* Should force alignment */ 941900Swnj } ts; 951900Swnj 961900Swnj /* Bits in (unibus) status register */ 971900Swnj #define SC 0100000 981900Swnj #define SSR 0200 991900Swnj #define OFL 0100 1001900Swnj #define NBA 02000 1011900Swnj 1021900Swnj /* states */ 1031900Swnj #define SIO 1 1041900Swnj #define SSFOR 2 1051900Swnj #define SSREV 3 1061900Swnj #define SRETRY 4 1071900Swnj #define SCOM 5 1081900Swnj #define SOK 6 1091900Swnj 1101900Swnj #define H_WRITTEN 1 1111900Swnj 1121900Swnj tsopen(dev, flag) 1131900Swnj { 1141900Swnj register struct device *tsaddr = TSADDR; 1151900Swnj static struct tsmesg *ubaddr; 1161900Swnj 1171900Swnj tstab.b_flags |= B_TAPE; 1181900Swnj if (ts_openf) { 1191900Swnj u.u_error = ENXIO; 1201900Swnj return; 1211900Swnj } 1221900Swnj if (ubaddr==0 || tsaddr->tssr&(OFL|NBA) || (tsaddr->tssr&SSR)==0) { 1231900Swnj long i = 0; 1241900Swnj tsaddr->tssr = 0; 1251900Swnj while ((tsaddr->tssr & SSR)==0) { 1261900Swnj if (++i > 1000000) { 1271900Swnj printf("Tape unready\n"); 1281900Swnj u.u_error = ENXIO; 1291900Swnj return; 1301900Swnj } 1311900Swnj } 1321900Swnj } 1331900Swnj if (tsaddr->tssr&OFL) { 1341900Swnj printf("Tape offline\n"); 1351900Swnj u.u_error = ENXIO; 1361900Swnj return; 1371900Swnj } 1381900Swnj if (tsaddr->tssr&NBA) { 1391900Swnj ctsbuf.b_un.b_addr = (caddr_t) &ts; 1401900Swnj ctsbuf.b_bcount = sizeof(ts); 1411900Swnj if (ubaddr == 0) 1421900Swnj ubaddr = (struct tsmesg *)ubasetup(&ctsbuf, 0); 143*1918Swnj ts_uba = (u_short)((long)ubaddr + (((long)ubaddr >> 16) & 03)); 1441900Swnj ts.ts_char.char_loba = (int)&ubaddr->ts_sts; 145*1918Swnj ts.ts_char.char_hiba = (u_short)((long)&ubaddr->ts_sts >> 16) & 03; 1461900Swnj ts.ts_char.char_size = sizeof(ts.ts_sts); 1471900Swnj ts.ts_char.char_mode = 0400; /* Stop on 2 tape marks */ 1481900Swnj ts.ts_cmd.c_cmd = ACK + 04; /* write characteristics */ 1491900Swnj ts.ts_cmd.c_loba = (int)&ubaddr->ts_char; 150*1918Swnj ts.ts_cmd.c_hiba = (u_short)((long)&ubaddr->ts_sts >> 16) & 03; 1511900Swnj ts.ts_cmd.c_size = sizeof(ts.ts_sts); 1521900Swnj tsaddr->tsdb = ts_uba; 1531900Swnj } 1541900Swnj ts_blkno = 0; 1551900Swnj ts_nxrec = INF; 1561900Swnj ts_flags = 0; 1571900Swnj if (u.u_error==0) 1581900Swnj ts_openf++; 1591900Swnj } 1601900Swnj 1611900Swnj tsclose(dev, flag) 1621900Swnj { 1631900Swnj 1641900Swnj if (flag == FWRITE || ((flag&FWRITE) && (ts_flags&H_WRITTEN))) { 1651900Swnj tscommand(WTM); 1661900Swnj tscommand(WTM); 1671900Swnj tscommand(SREV); 1681900Swnj } 1691900Swnj if ((minor(dev)&4) == 0) 1701900Swnj tscommand(REW); 1711900Swnj ts_openf = 0; 1721900Swnj } 1731900Swnj 1741900Swnj tscommand(com) 1751900Swnj { 1761900Swnj register struct buf *bp; 1771900Swnj 1781900Swnj bp = &ctsbuf; 1791900Swnj spl5(); 1801900Swnj while(bp->b_flags&B_BUSY) { 1811900Swnj bp->b_flags |= B_WANTED; 1821900Swnj sleep((caddr_t)bp, PRIBIO); 1831900Swnj } 1841900Swnj spl0(); 1851900Swnj bp->b_resid = com; 1861900Swnj bp->b_blkno = 0; 1871900Swnj bp->b_flags = B_BUSY|B_READ; 1881900Swnj tsstrategy(bp); 1891900Swnj iowait(bp); 1901900Swnj if(bp->b_flags&B_WANTED) 1911900Swnj wakeup((caddr_t)bp); 1921900Swnj bp->b_flags = 0; 1931900Swnj return(bp->b_resid); 1941900Swnj } 1951900Swnj 1961900Swnj tsstrategy(bp) 1971900Swnj register struct buf *bp; 1981900Swnj { 1991900Swnj register daddr_t *p; 2001900Swnj 2011900Swnj if(bp != &ctsbuf) { 2021900Swnj p = &ts_nxrec; 2031900Swnj if(dbtofsb(bp->b_blkno) > *p) { 2041900Swnj bp->b_flags |= B_ERROR; 2051900Swnj bp->b_error = ENXIO; 2061900Swnj iodone(bp); 2071900Swnj return; 2081900Swnj } 2091900Swnj if(dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) { 2101900Swnj bp->b_resid = bp->b_bcount; 2111900Swnj iodone(bp); 2121900Swnj return; 2131900Swnj } 2141900Swnj if ((bp->b_flags&B_READ)==0) { 2151900Swnj *p = dbtofsb(bp->b_blkno) + 1; 2161900Swnj ts_flags |= H_WRITTEN; 2171900Swnj } 2181900Swnj } 2191900Swnj bp->av_forw = NULL; 2201900Swnj spl5(); 2211900Swnj if (tstab.b_actf == NULL) 2221900Swnj tstab.b_actf = bp; 2231900Swnj else 2241900Swnj tstab.b_actl->av_forw = bp; 2251900Swnj tstab.b_actl = bp; 2261900Swnj if (tstab.b_active==0) 2271900Swnj tsstart(); 2281900Swnj spl0(); 2291900Swnj } 2301900Swnj 2311900Swnj tsstart() 2321900Swnj { 2331900Swnj register struct buf *bp; 2341900Swnj register struct device *tsaddr = TSADDR; 2351900Swnj daddr_t blkno; 2361900Swnj 2371900Swnj loop: 2381900Swnj if ((bp = tstab.b_actf) == NULL) 2391900Swnj return; 2401900Swnj blkno = ts_blkno; 2411900Swnj if (ts_openf < 0 || dbtofsb(bp->b_blkno) > ts_nxrec) 2421900Swnj goto abort; 2431900Swnj if (bp == &ctsbuf) { 2441900Swnj tstab.b_active = SCOM; 2451900Swnj ts.ts_cmd.c_cmd = ACK+CVC+IE+bp->b_resid; 2461900Swnj ts.ts_cmd.c_loba = 1; /* count always 1 */ 2471900Swnj } else if (blkno == dbtofsb(bp->b_blkno)) { 2481900Swnj tstab.b_active = SIO; 2491900Swnj ts_iouba = ubasetup(bp, 1); 250*1918Swnj ts.ts_cmd.c_loba = (u_short)ts_iouba; 251*1918Swnj ts.ts_cmd.c_hiba = (u_short)(ts_iouba >> 16) & 03; 2521900Swnj ts.ts_cmd.c_size = bp->b_bcount; 2531900Swnj if(bp->b_flags & B_READ) 2541900Swnj ts.ts_cmd.c_cmd = ACK+CVC+IE+READ; 2551900Swnj else 2561900Swnj ts.ts_cmd.c_cmd = ACK+CVC+IE+WRITE; 2571900Swnj } else { 2581900Swnj if (blkno < dbtofsb(bp->b_blkno)) { 2591900Swnj tstab.b_active = SSFOR; 2601900Swnj ts.ts_cmd.c_cmd = ACK+CVC+IE+SFORW; 2611900Swnj ts.ts_cmd.c_loba = dbtofsb(bp->b_blkno) - blkno; 2621900Swnj } else { 2631900Swnj tstab.b_active = SSREV; 2641900Swnj ts.ts_cmd.c_cmd = ACK+CVC+IE+SREV; 2651900Swnj ts.ts_cmd.c_loba = blkno - dbtofsb(bp->b_blkno); 2661900Swnj } 2671900Swnj } 2681900Swnj tsaddr->tsdb = ts_uba; 2691900Swnj return; 2701900Swnj 2711900Swnj abort: 2721900Swnj bp->b_flags |= B_ERROR; 2731900Swnj 2741900Swnj next: 2751900Swnj tstab.b_active = 0; 2761900Swnj tstab.b_actf = bp->av_forw; 2771900Swnj iodone(bp); 2781900Swnj goto loop; 2791900Swnj } 2801900Swnj 2811900Swnj tsintr() 2821900Swnj { 2831900Swnj register struct buf *bp; 2841900Swnj register struct device *tsaddr = TSADDR; 2851900Swnj register err, errclass, state; 2861900Swnj 2871900Swnj if ((bp = tstab.b_actf)==NULL) 2881900Swnj return; 2891900Swnj state = tstab.b_active; 2901900Swnj tstab.b_active = 0; 2911900Swnj err = tsaddr->tssr & 016; 2921900Swnj if ((tsaddr->tssr & SC) == 0) 2931900Swnj err = 0; 2941900Swnj errclass = 0; 2951900Swnj switch (err) { 2961900Swnj case 014: /* unrecoverable */ 2971900Swnj case 016: /* fatal */ 2981900Swnj case 002: /* attention (shouldn't happen) */ 2991900Swnj case 012: /* "recoverable", but shouldn't happen */ 3001900Swnj errclass = 2; 3011900Swnj break; 3021900Swnj 3031900Swnj case 0: /* all OK */ 3041900Swnj break; 3051900Swnj 3061900Swnj case 004: /* status alert */ 3071900Swnj if (ts.ts_sts.xs0&RLS && bp==&rtsbuf) /* short record */ 3081900Swnj break; 3091900Swnj if (ts.ts_sts.xs0 & TMK) { /* tape mark */ 3101900Swnj ts.ts_sts.rbpcr = bp->b_bcount; 3111900Swnj break; 3121900Swnj } 3131900Swnj errclass = 1; 3141900Swnj break; 3151900Swnj 3161900Swnj case 010: /* recoverable, tape moved */ 3171900Swnj if (state==SIO && ++bp->b_errcnt < 10) { 3181900Swnj ts.ts_cmd.c_cmd |= 01000; /* redo bit */ 3191900Swnj tstab.b_active = SIO; 3201900Swnj tsaddr->tsdb = ts_uba; 3211900Swnj return; 3221900Swnj } 3231900Swnj errclass = 1; 3241900Swnj break; 3251900Swnj 3261900Swnj case 006: /* Function reject */ 3271900Swnj if (state==SIO && ts.ts_sts.xs0 & WLE) 3281900Swnj printf("Tape needs a ring\n"); 3291900Swnj if ((ts.ts_sts.xs0&ONL) == 0) /* tape offline */ 3301900Swnj printf("Tape offline\n"); 3311900Swnj errclass = 2; 3321900Swnj } 3331900Swnj if (errclass) 3341900Swnj printf("tp: %o %o %o %o %o %o %o %o\n", tsaddr->tssr, 3351900Swnj ts.ts_sts.s_sts, ts.ts_sts.len, ts.ts_sts.rbpcr, 3361900Swnj ts.ts_sts.xs0, ts.ts_sts.xs1, ts.ts_sts.xs2, ts.ts_sts.xs3); 3371900Swnj switch(state) { 3381900Swnj case SIO: 3391900Swnj ts_blkno++; 3401900Swnj if (ts_iouba) 3411900Swnj ubafree(ts_iouba); 3421900Swnj else 3431900Swnj printf("uba alloc botch\n"); 3441900Swnj ts_iouba = 0; 3451900Swnj case SCOM: 3461900Swnj tstab.b_errcnt = 0; 3471900Swnj tstab.b_actf = bp->av_forw; 3481900Swnj bp->b_resid = ts.ts_sts.rbpcr; 3491900Swnj iodone(bp); 3501900Swnj break; 3511900Swnj 3521900Swnj case SSFOR: 3531900Swnj case SSREV: 3541900Swnj ts_blkno = dbtofsb(bp->b_blkno); 3551900Swnj break; 3561900Swnj 3571900Swnj default: 3581900Swnj printf("Unknown tape interrupt\n"); 3591900Swnj errclass = 2; 3601900Swnj break; 3611900Swnj } 3621900Swnj if (errclass > 1) { 3631900Swnj while (bp = tstab.b_actf) { 3641900Swnj bp->b_flags |= B_ERROR; 3651900Swnj iodone(bp); 3661900Swnj tstab.b_actf = bp->av_forw; 3671900Swnj } 3681900Swnj } 3691900Swnj tsstart(); 3701900Swnj } 3711900Swnj 3721900Swnj tsread(dev) 3731900Swnj { 3741900Swnj tsphys(dev); 3751900Swnj physio(tsstrategy, &rtsbuf, dev, B_READ, minphys); 3761900Swnj } 3771900Swnj 3781900Swnj tswrite(dev) 3791900Swnj { 3801900Swnj tsphys(dev); 3811900Swnj physio(tsstrategy, &rtsbuf, dev, B_WRITE, minphys); 3821900Swnj } 3831900Swnj 3841900Swnj tsphys(dev) 3851900Swnj { 3861900Swnj register unit; 3871900Swnj daddr_t a; 3881900Swnj 3891900Swnj a = u.u_offset >> 9; 3901900Swnj ts_blkno = dbtofsb(a); 3911900Swnj ts_nxrec = dbtofsb(a)+1; 3921900Swnj } 393*1918Swnj 394*1918Swnj #define UBMAP (int *)0xf30800 395*1918Swnj 396*1918Swnj int dtsinfo; 397*1918Swnj 398*1918Swnj twall(start, num) 399*1918Swnj { 400*1918Swnj register struct device *tsaddr = TSPHYS; 401*1918Swnj register int *ubap = UBMAP; 402*1918Swnj register int p, i; 403*1918Swnj 404*1918Swnj tsinit(); 405*1918Swnj /* dump mem */ 406*1918Swnj p = PG_V; 407*1918Swnj i = 0; 408*1918Swnj while (i<num) { 409*1918Swnj *(ubap) = p|i++; 410*1918Swnj *(ubap+1) = p|i; 411*1918Swnj dts.ts_cmd.c_loba = 0; 412*1918Swnj dts.ts_cmd.c_hiba = 0; 413*1918Swnj dts.ts_cmd.c_size = NBPG; 414*1918Swnj dts.ts_cmd.c_cmd = ACK+CVC+WRITE; 415*1918Swnj tsaddr->tsdb = dtsinfo; 416*1918Swnj twait(); 417*1918Swnj } 418*1918Swnj printf("done\n"); 419*1918Swnj } 420*1918Swnj 421*1918Swnj tsinit() 422*1918Swnj { 423*1918Swnj register struct device *tsaddr = TSPHYS; 424*1918Swnj register struct tsmesg *tsm; 425*1918Swnj register int *ubap = UBMAP; 426*1918Swnj register i; 427*1918Swnj 428*1918Swnj tsaddr->tssr = 0; 429*1918Swnj while ((tsaddr->tssr&SSR)==0) 430*1918Swnj ; 431*1918Swnj i = (int)&dts; 432*1918Swnj i &= 0xefffff; 433*1918Swnj dtsinfo = ((i&0777)|02000); 434*1918Swnj tsm = (struct tsmesg *)dtsinfo; 435*1918Swnj i >>= 9; 436*1918Swnj i |= PG_V; 437*1918Swnj *(ubap+2) = i; 438*1918Swnj *(ubap+3) = i+1; 439*1918Swnj dts.ts_cmd.c_cmd = ACK + 04; 440*1918Swnj dts.ts_cmd.c_loba = &tsm->ts_char; 441*1918Swnj dts.ts_cmd.c_hiba = 0; 442*1918Swnj dts.ts_cmd.c_size = sizeof(dts.ts_char); 443*1918Swnj dts.ts_char.char_loba = &tsm->ts_sts; 444*1918Swnj dts.ts_char.char_hiba = 0; 445*1918Swnj dts.ts_char.char_size = sizeof(dts.ts_sts); 446*1918Swnj dts.ts_char.char_mode = 0400; 447*1918Swnj tsaddr->tsdb = dtsinfo; 448*1918Swnj twait(); 449*1918Swnj } 450*1918Swnj 451*1918Swnj teof() 452*1918Swnj { 453*1918Swnj 454*1918Swnj dtscommand(WTM); 455*1918Swnj } 456*1918Swnj 457*1918Swnj rewind() 458*1918Swnj { 459*1918Swnj 460*1918Swnj dtscommand(REW); 461*1918Swnj } 462*1918Swnj 463*1918Swnj dtscommand(com) 464*1918Swnj { 465*1918Swnj register struct device *tsaddr = TSPHYS; 466*1918Swnj 467*1918Swnj dts.ts_cmd.c_cmd = ACK+CVC+com; 468*1918Swnj dts.ts_cmd.c_loba = 1; 469*1918Swnj tsaddr->tsdb = dtsinfo; 470*1918Swnj twait(); 471*1918Swnj } 472*1918Swnj 473*1918Swnj twait() 474*1918Swnj { 475*1918Swnj register struct device *tsaddr = TSPHYS; 476*1918Swnj register i; 477*1918Swnj 478*1918Swnj while ((tsaddr->tssr&SSR)==0) 479*1918Swnj ; 480*1918Swnj i = tsaddr->tssr; 481*1918Swnj if (i&SC) 482*1918Swnj printf("tssr %x ", i); 483*1918Swnj } 4841900Swnj #endif 485