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