1*2363Swnj /* tm.c 4.8 02/07/81 */ 21919Swnj 31940Swnj #include "tm.h" 41919Swnj #if NTM > 0 51919Swnj /* 61919Swnj * TM tape driver 71919Swnj */ 82324Skre #define DELAY(N) { register int d; d = N; while (--d > 0); } 91919Swnj #include "../h/param.h" 101919Swnj #include "../h/buf.h" 111919Swnj #include "../h/dir.h" 121919Swnj #include "../h/conf.h" 131919Swnj #include "../h/user.h" 141919Swnj #include "../h/file.h" 151919Swnj #include "../h/map.h" 161919Swnj #include "../h/pte.h" 171919Swnj #include "../h/uba.h" 181919Swnj #include "../h/mtio.h" 191919Swnj #include "../h/ioctl.h" 201919Swnj #include "../h/vm.h" 21*2363Swnj #include "../h/cmap.h" 221919Swnj 231919Swnj struct device { 241919Swnj u_short tmer; 251919Swnj u_short tmcs; 261919Swnj short tmbc; 271919Swnj u_short tmba; 281919Swnj short tmdb; 291919Swnj short tmrd; 301919Swnj }; 311919Swnj 321919Swnj #define b_repcnt b_bcount 331919Swnj #define b_command b_resid 341919Swnj 351919Swnj struct buf tmtab; 361919Swnj struct buf ctmbuf; 371919Swnj struct buf rtmbuf; 381919Swnj 391919Swnj int tm_ubinfo; 401919Swnj 411919Swnj /* bits in minor device */ 421919Swnj #define T_NOREWIND 04 431919Swnj #define T_1600BPI 08 441919Swnj 451919Swnj #define INF (daddr_t)1000000L 461919Swnj 471919Swnj /* 481919Swnj * Really only handle one tape drive... if you have more than one, 491919Swnj * you can make all these arrays and change the obvious things, but 501919Swnj * it is not clear what happens when some drives are transferring while 511919Swnj * others rewind, so we don't pretend that this driver handles multiple 521919Swnj * tape drives. 531919Swnj */ 541919Swnj char t_openf; 551919Swnj daddr_t t_blkno; 561919Swnj char t_flags; 571919Swnj daddr_t t_nxrec; 581919Swnj u_short t_erreg; 591919Swnj u_short t_dsreg; 601919Swnj short t_resid; 611919Swnj 621919Swnj /* bits in tmcs */ 631919Swnj #define GO 01 641919Swnj #define OFFL 0 651919Swnj #define RCOM 02 661919Swnj #define WCOM 04 671919Swnj #define WEOF 06 681919Swnj #define SFORW 010 691919Swnj #define SREV 012 701919Swnj #define WIRG 014 711919Swnj #define REW 016 721919Swnj #define IENABLE 0100 731919Swnj #define CUR 0200 741919Swnj #define NOP IENABLE 751919Swnj #define DCLR 010000 761919Swnj #define D800 060000 771919Swnj #define ERROR 0100000 781919Swnj 791919Swnj /* bits in tmer */ 801919Swnj #define TUR 1 811919Swnj #define RWS 02 821919Swnj #define WRL 04 831919Swnj #define SDWN 010 841919Swnj #define BOT 040 851919Swnj #define SELR 0100 861919Swnj #define NXM 0200 871919Swnj #define TMBTE 0400 881919Swnj #define RLE 01000 891919Swnj #define EOT 02000 901919Swnj #define BGL 04000 911919Swnj #define PAE 010000 921919Swnj #define CRE 020000 931919Swnj #define EOF 040000 941919Swnj #define ILC 0100000 951919Swnj 961919Swnj #define HARD (ILC|EOT) 971919Swnj #define SOFT (CRE|PAE|BGL|RLE|TMBTE|NXM) 981919Swnj 991919Swnj #define SSEEK 1 /* seeking */ 1001919Swnj #define SIO 2 /* doing seq i/o */ 1011919Swnj #define SCOM 3 /* sending control command */ 1021919Swnj 1031919Swnj #define LASTIOW 1 /* last op was a write */ 1041919Swnj #define WAITREW 2 /* someone is waiting for a rewind */ 1051919Swnj 1061919Swnj tmopen(dev, flag) 1071919Swnj dev_t dev; 1081919Swnj int flag; 1091919Swnj { 1101919Swnj register ds, unit; 1111919Swnj 1121919Swnj tmtab.b_flags |= B_TAPE; 1131919Swnj unit = minor(dev)&03; 1141919Swnj if (unit >= NTM || t_openf) { 1151919Swnj u.u_error = ENXIO; /* out of range or open */ 1161919Swnj return; 1171919Swnj } 1181919Swnj tcommand(dev, NOP, 1); 1191919Swnj if ((t_erreg&SELR) == 0) { 1201919Swnj u.u_error = EIO; /* offline */ 1211919Swnj return; 1221919Swnj } 1231919Swnj t_openf = 1; 1241919Swnj if (t_erreg&RWS) 1251919Swnj tmwaitrws(dev); /* wait for rewind complete */ 1261919Swnj while (t_erreg&SDWN) 1271919Swnj tcommand(dev, NOP, 1); /* await settle down */ 1281919Swnj if ((t_erreg&TUR)==0 || 1291919Swnj ((flag&(FREAD|FWRITE)) == FWRITE && (t_erreg&WRL))) { 1301919Swnj TMADDR->tmcs = DCLR|GO; 1311919Swnj u.u_error = EIO; /* offline or write protect */ 1321919Swnj } 1331919Swnj if (u.u_error != 0) { 1341919Swnj t_openf = 0; 1351919Swnj return; 1361919Swnj } 1371919Swnj t_blkno = (daddr_t)0; 1381919Swnj t_nxrec = INF; 1391919Swnj t_flags = 0; 1401919Swnj t_openf = 1; 1411919Swnj } 1421919Swnj 1431919Swnj tmwaitrws(dev) 1441919Swnj register dev; 1451919Swnj { 1461919Swnj 1471919Swnj spl5(); 1481919Swnj for (;;) { 1491928Swnj if ((TMADDR->tmer&RWS) == 0) { 1501919Swnj spl0(); /* rewind complete */ 1511919Swnj return; 1521919Swnj } 1531919Swnj t_flags |= WAITREW; 1541919Swnj sleep((caddr_t)&t_flags, PRIBIO); 1551919Swnj } 1561919Swnj } 1571919Swnj 1581919Swnj tmclose(dev, flag) 1591919Swnj register dev_t dev; 1601919Swnj register flag; 1611919Swnj { 1621919Swnj 1631919Swnj if (flag == FWRITE || ((flag&FWRITE) && (t_flags&LASTIOW))) { 1641919Swnj tcommand(dev, WEOF, 1); 1651919Swnj tcommand(dev, WEOF, 1); 1661919Swnj tcommand(dev, SREV, 1); 1671919Swnj } 1681919Swnj if ((minor(dev)&T_NOREWIND) == 0) 1691919Swnj tcommand(dev, REW, 1); 1701919Swnj t_openf = 0; 1711919Swnj } 1721919Swnj 1731919Swnj tcommand(dev, com, count) 1741919Swnj dev_t dev; 1751919Swnj int com, count; 1761919Swnj { 1771919Swnj register struct buf *bp; 1781919Swnj 1791919Swnj bp = &ctmbuf; 1801919Swnj (void) spl5(); 1811919Swnj while (bp->b_flags&B_BUSY) { 1821919Swnj bp->b_flags |= B_WANTED; 1831919Swnj sleep((caddr_t)bp, PRIBIO); 1841919Swnj } 1851919Swnj bp->b_flags = B_BUSY|B_READ; 1861919Swnj (void) spl0(); 1871919Swnj bp->b_dev = dev; 1881919Swnj bp->b_repcnt = -count; 1891919Swnj bp->b_command = com; 1901919Swnj bp->b_blkno = 0; 1911919Swnj tmstrategy(bp); 1921919Swnj iowait(bp); 1931919Swnj if (bp->b_flags&B_WANTED) 1941919Swnj wakeup((caddr_t)bp); 1951919Swnj bp->b_flags &= B_ERROR; 1961919Swnj } 1971919Swnj 1981919Swnj tmstrategy(bp) 1991919Swnj register struct buf *bp; 2001919Swnj { 2011919Swnj register daddr_t *p; 2021919Swnj 2031928Swnj tmwaitrws(bp->b_dev); 2041919Swnj if (bp != &ctmbuf) { 2051919Swnj p = &t_nxrec; 2061919Swnj if (dbtofsb(bp->b_blkno) > *p) { 2071919Swnj bp->b_flags |= B_ERROR; 2081919Swnj bp->b_error = ENXIO; /* past EOF */ 2091919Swnj iodone(bp); 2101919Swnj return; 2111919Swnj } else if (dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) { 2121919Swnj bp->b_resid = bp->b_bcount; 2131919Swnj clrbuf(bp); /* at EOF */ 2141919Swnj iodone(bp); 2151919Swnj return; 2161919Swnj } else if ((bp->b_flags&B_READ) == 0) 2171919Swnj *p = dbtofsb(bp->b_blkno) + 1; /* write sets EOF */ 2181919Swnj } 2191919Swnj bp->av_forw = NULL; 2201919Swnj (void) spl5(); 2211919Swnj if (tmtab.b_actf == NULL) 2221919Swnj tmtab.b_actf = bp; 2231919Swnj else 2241919Swnj tmtab.b_actl->av_forw = bp; 2251919Swnj tmtab.b_actl = bp; 2261919Swnj if (tmtab.b_active == 0) 2271919Swnj tmstart(); 2281919Swnj (void) spl0(); 2291919Swnj } 2301919Swnj 2311919Swnj tmstart() 2321919Swnj { 2331919Swnj register struct buf *bp; 2341919Swnj register cmd; 2351919Swnj register daddr_t blkno; 2362054Swnj int s; 2371919Swnj 2381919Swnj loop: 2391919Swnj if ((bp = tmtab.b_actf) == 0) 2401919Swnj return; 2411919Swnj t_dsreg = TMADDR->tmcs; 2421919Swnj t_erreg = TMADDR->tmer; 2431919Swnj t_resid = TMADDR->tmbc; 2441919Swnj t_flags &= ~LASTIOW; 2451919Swnj if (t_openf < 0 || (TMADDR->tmcs&CUR) == 0) { 2461919Swnj /* t_openf = -1; ??? */ 2471919Swnj bp->b_flags |= B_ERROR; /* hard error'ed or !SELR */ 2481919Swnj goto next; 2491919Swnj } 2501919Swnj cmd = IENABLE | GO; 2511919Swnj if ((minor(bp->b_dev) & T_1600BPI) == 0) 2521919Swnj cmd |= D800; 2531919Swnj if (bp == &ctmbuf) { 2541919Swnj if (bp->b_command == NOP) 2551919Swnj goto next; /* just get status */ 2561919Swnj else { 2571919Swnj cmd |= bp->b_command; 2581919Swnj tmtab.b_active = SCOM; 2591919Swnj if (bp->b_command == SFORW || bp->b_command == SREV) 2601919Swnj TMADDR->tmbc = bp->b_repcnt; 2611919Swnj TMADDR->tmcs = cmd; 2621919Swnj return; 2631919Swnj } 2641919Swnj } 2651919Swnj if ((blkno = t_blkno) == dbtofsb(bp->b_blkno)) { 2661919Swnj TMADDR->tmbc = -bp->b_bcount; 2672054Swnj s = spl6(); 2681919Swnj if (tm_ubinfo == 0) 2691919Swnj tm_ubinfo = ubasetup(bp,1); 2702054Swnj splx(s); 2711919Swnj if ((bp->b_flags&B_READ) == 0) { 2721919Swnj if (tmtab.b_errcnt) 2731919Swnj cmd |= WIRG; 2741919Swnj else 2751919Swnj cmd |= WCOM; 2761919Swnj } else 2771919Swnj cmd |= RCOM; 2781919Swnj cmd |= (tm_ubinfo >> 12) & 0x30; 2791919Swnj tmtab.b_active = SIO; 2801919Swnj TMADDR->tmba = tm_ubinfo; 2811919Swnj TMADDR->tmcs = cmd; 2821919Swnj return; 2831919Swnj } 2841919Swnj tmtab.b_active = SSEEK; 2851919Swnj if (blkno < dbtofsb(bp->b_blkno)) { 2861919Swnj cmd |= SFORW; 2871919Swnj TMADDR->tmbc = blkno - dbtofsb(bp->b_blkno); 2881919Swnj } else { 2891919Swnj cmd |= SREV; 2901919Swnj TMADDR->tmbc = dbtofsb(bp->b_blkno) - blkno; 2911919Swnj } 2921919Swnj TMADDR->tmcs = cmd; 2931919Swnj return; 2941919Swnj 2951919Swnj next: 2962054Swnj ubarelse(&tm_ubinfo); 2971919Swnj tmtab.b_actf = bp->av_forw; 2981919Swnj iodone(bp); 2991919Swnj goto loop; 3001919Swnj } 3011919Swnj 3021919Swnj tmintr() 3031919Swnj { 3041919Swnj register struct buf *bp; 3051919Swnj register state; 3061919Swnj 3071919Swnj if (t_flags&WAITREW && (TMADDR->tmer&RWS) == 0) { 3081919Swnj t_flags &= ~WAITREW; 3091919Swnj wakeup((caddr_t)&t_flags); 3101919Swnj } 3111919Swnj if ((bp = tmtab.b_actf) == NULL) 3121919Swnj return; 3131919Swnj t_dsreg = TMADDR->tmcs; 3141919Swnj t_erreg = TMADDR->tmer; 3151919Swnj t_resid = TMADDR->tmbc; 3161919Swnj if ((bp->b_flags & B_READ) == 0) 3171919Swnj t_flags |= LASTIOW; 3181919Swnj state = tmtab.b_active; 3191919Swnj tmtab.b_active = 0; 3201919Swnj if (TMADDR->tmcs&ERROR) { 3211919Swnj while(TMADDR->tmer & SDWN) 3221919Swnj ; /* await settle down */ 3231919Swnj if (TMADDR->tmer&EOF) { 3241919Swnj tmseteof(bp); /* set blkno and nxrec */ 3251919Swnj state = SCOM; 3261919Swnj TMADDR->tmbc = -bp->b_bcount; 3271919Swnj goto errout; 3281919Swnj } 3291919Swnj if ((bp->b_flags&B_READ) && (TMADDR->tmer&(HARD|SOFT)) == RLE) 3301919Swnj goto out; 3311919Swnj if ((TMADDR->tmer&HARD)==0 && state==SIO) { 3321928Swnj if (++tmtab.b_errcnt < 7) { 3331919Swnj if((TMADDR->tmer&SOFT) == NXM) 3341919Swnj printf("TM UBA late error\n"); 3351919Swnj else 3361928Swnj t_blkno += 2; /* ???????? */ 3372054Swnj ubarelse(&tm_ubinfo); 3381919Swnj tmstart(); 3391919Swnj return; 3401919Swnj } 3411919Swnj } else if (t_openf>0 && bp != &rtmbuf) 3421919Swnj t_openf = -1; 3431928Swnj deverror(bp, t_erreg, t_dsreg); 3441919Swnj bp->b_flags |= B_ERROR; 3451919Swnj state = SIO; 3461919Swnj } 3471919Swnj out: 3481919Swnj switch (state) { 3491919Swnj 3501919Swnj case SIO: 3511919Swnj t_blkno++; 3521919Swnj /* fall into ... */ 3531919Swnj 3541919Swnj case SCOM: 3551919Swnj if (bp == &ctmbuf) { 3561919Swnj switch (bp->b_command) { 3571919Swnj case SFORW: 3581919Swnj t_blkno -= bp->b_repcnt; 3591919Swnj break; 3601919Swnj 3611919Swnj case SREV: 3621919Swnj t_blkno += bp->b_repcnt; 3631919Swnj break; 3641919Swnj 3651919Swnj default: 3661919Swnj if (++bp->b_repcnt < 0) { 3671919Swnj tmstart(); /* continue */ 3681919Swnj return; 3691919Swnj } 3701919Swnj } 3711919Swnj } 3721919Swnj errout: 3731919Swnj tmtab.b_errcnt = 0; 3741919Swnj tmtab.b_actf = bp->av_forw; 3751919Swnj bp->b_resid = -TMADDR->tmbc; 3762054Swnj ubarelse(&tm_ubinfo); 3771919Swnj iodone(bp); 3781919Swnj break; 3791919Swnj 3801919Swnj case SSEEK: 3811919Swnj t_blkno = dbtofsb(bp->b_blkno); 3821919Swnj break; 3831919Swnj 3841919Swnj default: 3851919Swnj return; 3861919Swnj } 3871919Swnj tmstart(); 3881919Swnj } 3891919Swnj 3901919Swnj tmseteof(bp) 3911919Swnj register struct buf *bp; 3921919Swnj { 3931919Swnj 3941919Swnj if (bp == &ctmbuf) { 3951919Swnj if (t_blkno > dbtofsb(bp->b_blkno)) { 3961919Swnj /* reversing */ 3971919Swnj t_nxrec = dbtofsb(bp->b_blkno) - TMADDR->tmbc; 3981919Swnj t_blkno = t_nxrec; 3991919Swnj } else { 4001919Swnj /* spacing forward */ 4011919Swnj t_blkno = dbtofsb(bp->b_blkno) + TMADDR->tmbc; 4021919Swnj t_nxrec = t_blkno - 1; 4031919Swnj } 4041919Swnj return; 4051919Swnj } 4061919Swnj /* eof on read */ 4071919Swnj t_nxrec = dbtofsb(bp->b_blkno); 4081919Swnj } 4091919Swnj 4101919Swnj tmread(dev) 4111919Swnj { 4121919Swnj 4131919Swnj tmphys(dev); 4141919Swnj physio(tmstrategy, &rtmbuf, dev, B_READ, minphys); 4151919Swnj } 4161919Swnj 4171919Swnj tmwrite(dev) 4181919Swnj { 4191919Swnj 4201919Swnj tmphys(dev); 4211919Swnj physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys); 4221919Swnj } 4231919Swnj 4241919Swnj tmphys(dev) 4251919Swnj { 4261919Swnj register daddr_t a; 4271919Swnj 4281919Swnj a = dbtofsb(u.u_offset >> 9); 4291919Swnj t_blkno = a; 4301919Swnj t_nxrec = a + 1; 4311919Swnj } 4321919Swnj 4331919Swnj /*ARGSUSED*/ 4341919Swnj tmioctl(dev, cmd, addr, flag) 4351919Swnj caddr_t addr; 4361919Swnj dev_t dev; 4371919Swnj { 4381919Swnj register callcount; 4391919Swnj int fcount; 4401919Swnj struct mtop mtop; 4411919Swnj struct mtget mtget; 4421919Swnj /* we depend of the values and order of the MT codes here */ 4432324Skre static tmops[] = {WEOF, SFORW, SREV, SFORW, SREV, REW, OFFL, NOP}; 4441919Swnj 4451919Swnj switch(cmd) { 4461919Swnj case MTIOCTOP: /* tape operation */ 4471919Swnj if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) { 4481919Swnj u.u_error = EFAULT; 4491919Swnj return; 4501919Swnj } 4511919Swnj switch(mtop.mt_op) { 4521919Swnj case MTWEOF: case MTFSF: case MTBSF: 4531919Swnj callcount = mtop.mt_count; 4541919Swnj fcount = INF; 4551919Swnj break; 4561919Swnj case MTFSR: case MTBSR: 4571919Swnj callcount = 1; 4581919Swnj fcount = mtop.mt_count; 4591919Swnj break; 4602324Skre case MTREW: case MTOFFL: case MTNOP: 4611919Swnj callcount = 1; 4621919Swnj fcount = 1; 4631919Swnj break; 4641919Swnj default: 4651919Swnj u.u_error = ENXIO; 4661919Swnj return; 4671919Swnj } 4681919Swnj if (callcount <= 0 || fcount <= 0) 4691919Swnj u.u_error = ENXIO; 4701919Swnj else while (--callcount >= 0) { 4711919Swnj tcommand(dev, tmops[mtop.mt_op], fcount); 4721919Swnj if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) && 4731919Swnj ctmbuf.b_resid) { 4741919Swnj u.u_error = EIO; 4751919Swnj break; 4761919Swnj } 4771919Swnj if ((ctmbuf.b_flags&B_ERROR) || t_erreg&BOT) 4781919Swnj break; 4791919Swnj } 4801919Swnj geterror(&ctmbuf); 4811919Swnj return; 4821919Swnj case MTIOCGET: 4831919Swnj mtget.mt_dsreg = t_dsreg; 4841919Swnj mtget.mt_erreg = t_erreg; 4851919Swnj mtget.mt_resid = t_resid; 4861919Swnj if (copyout((caddr_t)&mtget, addr, sizeof(mtget))) 4871919Swnj u.u_error = EFAULT; 4881919Swnj return; 4891919Swnj default: 4901919Swnj u.u_error = ENXIO; 4911919Swnj } 4921919Swnj } 4931919Swnj 4941919Swnj #define DBSIZE 20 4951919Swnj 496*2363Swnj tmdump() 497*2363Swnj { 498*2363Swnj 499*2363Swnj tmwall((char *)0, maxfree); /* write out memory */ 500*2363Swnj tmeof(); 501*2363Swnj tmeof(); 502*2363Swnj tmrewind(); 503*2363Swnj tmwait(); 504*2363Swnj } 505*2363Swnj 506*2363Swnj tmwall(start, num) 5071919Swnj int start, num; 5081919Swnj { 5091919Swnj #if VAX==780 5101919Swnj register struct uba_regs *up = (struct uba_regs *)PHYSUBA0; 5111919Swnj #endif 5122297Swnj int blk, bdp; 5131919Swnj 5141919Swnj #if VAX==780 5151919Swnj up->uba_cr = ADINIT; 5161919Swnj up->uba_cr = IFS|BRIE|USEFIE|SUEFIE; 5171919Swnj while ((up->uba_cnfgr & UBIC) == 0) 5181919Swnj ; 5191919Swnj #endif 5202324Skre DELAY(1000000); 521*2363Swnj tmwait(); 5222324Skre TMPHYS->tmcs = DCLR | GO; 5231919Swnj while (num > 0) { 5241919Swnj blk = num > DBSIZE ? DBSIZE : num; 5251919Swnj tmdwrite(start, blk); 5261919Swnj start += blk; 5271919Swnj num -= blk; 5281919Swnj } 5292297Swnj bdp = 1; /* crud to fool c compiler */ 5302297Swnj ((struct uba_regs *)PHYSUBA0)->uba_dpr[bdp] |= BNE; 531*2363Swnj return (0); 5321919Swnj } 5331919Swnj 5341919Swnj tmdwrite(buf, num) 5351919Swnj register buf, num; 5361919Swnj { 5371919Swnj register int *io, npf; 5382297Swnj int bdp; 5391928Swnj 540*2363Swnj tmwait(); 5412297Swnj bdp = 1; /* more dastardly tricks on pcc */ 5422297Swnj ((struct uba_regs *)PHYSUBA0)->uba_dpr[bdp] |= BNE; 5431919Swnj io = (int *)((struct uba_regs *)PHYSUBA0)->uba_map; 5441919Swnj npf = num+1; 5451928Swnj while (--npf != 0) 5461919Swnj *io++ = (int)(buf++ | (1<<21) | MRV); 5471919Swnj *io = 0; 5481919Swnj TMPHYS->tmbc = -(num*NBPG); 5491919Swnj TMPHYS->tmba = 0; 5502324Skre TMPHYS->tmcs = WCOM | GO; 5511919Swnj } 5521919Swnj 553*2363Swnj tmwait() 5541919Swnj { 5551928Swnj register s; 5561919Swnj 5571919Swnj do 5581919Swnj s = TMPHYS->tmcs; 5591919Swnj while ((s & CUR) == 0); 5601919Swnj } 5611919Swnj 562*2363Swnj tmrewind() 5631919Swnj { 5641919Swnj 565*2363Swnj tmwait(); 5661919Swnj TMPHYS->tmcs = REW | GO; 5671919Swnj } 5681919Swnj 569*2363Swnj tmeof() 5701919Swnj { 5711919Swnj 572*2363Swnj tmwait(); 5732324Skre TMPHYS->tmcs = WEOF | GO; 5741919Swnj } 5751919Swnj #endif 576