1*2324Skre /* tm.c 4.7 01/31/81 */ 21919Swnj 31940Swnj #include "tm.h" 41919Swnj #if NTM > 0 51919Swnj /* 61919Swnj * TM tape driver 71919Swnj */ 8*2324Skre #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" 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 (;;) { 1481928Swnj 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 2021928Swnj 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; 2352054Swnj int s; 2361919Swnj 2371919Swnj loop: 2381919Swnj if ((bp = tmtab.b_actf) == 0) 2391919Swnj return; 2401919Swnj t_dsreg = TMADDR->tmcs; 2411919Swnj t_erreg = TMADDR->tmer; 2421919Swnj t_resid = TMADDR->tmbc; 2431919Swnj t_flags &= ~LASTIOW; 2441919Swnj if (t_openf < 0 || (TMADDR->tmcs&CUR) == 0) { 2451919Swnj /* t_openf = -1; ??? */ 2461919Swnj bp->b_flags |= B_ERROR; /* hard error'ed or !SELR */ 2471919Swnj goto next; 2481919Swnj } 2491919Swnj cmd = IENABLE | GO; 2501919Swnj if ((minor(bp->b_dev) & T_1600BPI) == 0) 2511919Swnj cmd |= D800; 2521919Swnj if (bp == &ctmbuf) { 2531919Swnj if (bp->b_command == NOP) 2541919Swnj goto next; /* just get status */ 2551919Swnj else { 2561919Swnj cmd |= bp->b_command; 2571919Swnj tmtab.b_active = SCOM; 2581919Swnj if (bp->b_command == SFORW || bp->b_command == SREV) 2591919Swnj TMADDR->tmbc = bp->b_repcnt; 2601919Swnj TMADDR->tmcs = cmd; 2611919Swnj return; 2621919Swnj } 2631919Swnj } 2641919Swnj if ((blkno = t_blkno) == dbtofsb(bp->b_blkno)) { 2651919Swnj TMADDR->tmbc = -bp->b_bcount; 2662054Swnj s = spl6(); 2671919Swnj if (tm_ubinfo == 0) 2681919Swnj tm_ubinfo = ubasetup(bp,1); 2692054Swnj splx(s); 2701919Swnj if ((bp->b_flags&B_READ) == 0) { 2711919Swnj if (tmtab.b_errcnt) 2721919Swnj cmd |= WIRG; 2731919Swnj else 2741919Swnj cmd |= WCOM; 2751919Swnj } else 2761919Swnj cmd |= RCOM; 2771919Swnj cmd |= (tm_ubinfo >> 12) & 0x30; 2781919Swnj tmtab.b_active = SIO; 2791919Swnj TMADDR->tmba = tm_ubinfo; 2801919Swnj TMADDR->tmcs = cmd; 2811919Swnj return; 2821919Swnj } 2831919Swnj tmtab.b_active = SSEEK; 2841919Swnj if (blkno < dbtofsb(bp->b_blkno)) { 2851919Swnj cmd |= SFORW; 2861919Swnj TMADDR->tmbc = blkno - dbtofsb(bp->b_blkno); 2871919Swnj } else { 2881919Swnj cmd |= SREV; 2891919Swnj TMADDR->tmbc = dbtofsb(bp->b_blkno) - blkno; 2901919Swnj } 2911919Swnj TMADDR->tmcs = cmd; 2921919Swnj return; 2931919Swnj 2941919Swnj next: 2952054Swnj ubarelse(&tm_ubinfo); 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) { 3311928Swnj if (++tmtab.b_errcnt < 7) { 3321919Swnj if((TMADDR->tmer&SOFT) == NXM) 3331919Swnj printf("TM UBA late error\n"); 3341919Swnj else 3351928Swnj t_blkno += 2; /* ???????? */ 3362054Swnj ubarelse(&tm_ubinfo); 3371919Swnj tmstart(); 3381919Swnj return; 3391919Swnj } 3401919Swnj } else if (t_openf>0 && bp != &rtmbuf) 3411919Swnj t_openf = -1; 3421928Swnj deverror(bp, t_erreg, t_dsreg); 3431919Swnj bp->b_flags |= B_ERROR; 3441919Swnj state = SIO; 3451919Swnj } 3461919Swnj out: 3471919Swnj switch (state) { 3481919Swnj 3491919Swnj case SIO: 3501919Swnj t_blkno++; 3511919Swnj /* fall into ... */ 3521919Swnj 3531919Swnj case SCOM: 3541919Swnj if (bp == &ctmbuf) { 3551919Swnj switch (bp->b_command) { 3561919Swnj case SFORW: 3571919Swnj t_blkno -= bp->b_repcnt; 3581919Swnj break; 3591919Swnj 3601919Swnj case SREV: 3611919Swnj t_blkno += bp->b_repcnt; 3621919Swnj break; 3631919Swnj 3641919Swnj default: 3651919Swnj if (++bp->b_repcnt < 0) { 3661919Swnj tmstart(); /* continue */ 3671919Swnj return; 3681919Swnj } 3691919Swnj } 3701919Swnj } 3711919Swnj errout: 3721919Swnj tmtab.b_errcnt = 0; 3731919Swnj tmtab.b_actf = bp->av_forw; 3741919Swnj bp->b_resid = -TMADDR->tmbc; 3752054Swnj ubarelse(&tm_ubinfo); 3761919Swnj iodone(bp); 3771919Swnj break; 3781919Swnj 3791919Swnj case SSEEK: 3801919Swnj t_blkno = dbtofsb(bp->b_blkno); 3811919Swnj break; 3821919Swnj 3831919Swnj default: 3841919Swnj return; 3851919Swnj } 3861919Swnj tmstart(); 3871919Swnj } 3881919Swnj 3891919Swnj tmseteof(bp) 3901919Swnj register struct buf *bp; 3911919Swnj { 3921919Swnj 3931919Swnj if (bp == &ctmbuf) { 3941919Swnj if (t_blkno > dbtofsb(bp->b_blkno)) { 3951919Swnj /* reversing */ 3961919Swnj t_nxrec = dbtofsb(bp->b_blkno) - TMADDR->tmbc; 3971919Swnj t_blkno = t_nxrec; 3981919Swnj } else { 3991919Swnj /* spacing forward */ 4001919Swnj t_blkno = dbtofsb(bp->b_blkno) + TMADDR->tmbc; 4011919Swnj t_nxrec = t_blkno - 1; 4021919Swnj } 4031919Swnj return; 4041919Swnj } 4051919Swnj /* eof on read */ 4061919Swnj t_nxrec = dbtofsb(bp->b_blkno); 4071919Swnj } 4081919Swnj 4091919Swnj tmread(dev) 4101919Swnj { 4111919Swnj 4121919Swnj tmphys(dev); 4131919Swnj physio(tmstrategy, &rtmbuf, dev, B_READ, minphys); 4141919Swnj } 4151919Swnj 4161919Swnj tmwrite(dev) 4171919Swnj { 4181919Swnj 4191919Swnj tmphys(dev); 4201919Swnj physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys); 4211919Swnj } 4221919Swnj 4231919Swnj tmphys(dev) 4241919Swnj { 4251919Swnj register daddr_t a; 4261919Swnj 4271919Swnj a = dbtofsb(u.u_offset >> 9); 4281919Swnj t_blkno = a; 4291919Swnj t_nxrec = a + 1; 4301919Swnj } 4311919Swnj 4321919Swnj /*ARGSUSED*/ 4331919Swnj tmioctl(dev, cmd, addr, flag) 4341919Swnj caddr_t addr; 4351919Swnj dev_t dev; 4361919Swnj { 4371919Swnj register callcount; 4381919Swnj int fcount; 4391919Swnj struct mtop mtop; 4401919Swnj struct mtget mtget; 4411919Swnj /* we depend of the values and order of the MT codes here */ 442*2324Skre static tmops[] = {WEOF, SFORW, SREV, SFORW, SREV, REW, OFFL, NOP}; 4431919Swnj 4441919Swnj switch(cmd) { 4451919Swnj case MTIOCTOP: /* tape operation */ 4461919Swnj if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) { 4471919Swnj u.u_error = EFAULT; 4481919Swnj return; 4491919Swnj } 4501919Swnj switch(mtop.mt_op) { 4511919Swnj case MTWEOF: case MTFSF: case MTBSF: 4521919Swnj callcount = mtop.mt_count; 4531919Swnj fcount = INF; 4541919Swnj break; 4551919Swnj case MTFSR: case MTBSR: 4561919Swnj callcount = 1; 4571919Swnj fcount = mtop.mt_count; 4581919Swnj break; 459*2324Skre case MTREW: case MTOFFL: case MTNOP: 4601919Swnj callcount = 1; 4611919Swnj fcount = 1; 4621919Swnj break; 4631919Swnj default: 4641919Swnj u.u_error = ENXIO; 4651919Swnj return; 4661919Swnj } 4671919Swnj if (callcount <= 0 || fcount <= 0) 4681919Swnj u.u_error = ENXIO; 4691919Swnj else while (--callcount >= 0) { 4701919Swnj tcommand(dev, tmops[mtop.mt_op], fcount); 4711919Swnj if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) && 4721919Swnj ctmbuf.b_resid) { 4731919Swnj u.u_error = EIO; 4741919Swnj break; 4751919Swnj } 4761919Swnj if ((ctmbuf.b_flags&B_ERROR) || t_erreg&BOT) 4771919Swnj break; 4781919Swnj } 4791919Swnj geterror(&ctmbuf); 4801919Swnj return; 4811919Swnj case MTIOCGET: 4821919Swnj mtget.mt_dsreg = t_dsreg; 4831919Swnj mtget.mt_erreg = t_erreg; 4841919Swnj mtget.mt_resid = t_resid; 4851919Swnj if (copyout((caddr_t)&mtget, addr, sizeof(mtget))) 4861919Swnj u.u_error = EFAULT; 4871919Swnj return; 4881919Swnj default: 4891919Swnj u.u_error = ENXIO; 4901919Swnj } 4911919Swnj } 4921919Swnj 4931919Swnj #define DBSIZE 20 4941919Swnj 4951919Swnj twall(start, num) 4961919Swnj int start, num; 4971919Swnj { 4981919Swnj #if VAX==780 4991919Swnj register struct uba_regs *up = (struct uba_regs *)PHYSUBA0; 5001919Swnj #endif 5012297Swnj int blk, bdp; 5021919Swnj 5031919Swnj #if VAX==780 5041919Swnj up->uba_cr = ADINIT; 5051919Swnj up->uba_cr = IFS|BRIE|USEFIE|SUEFIE; 5061919Swnj while ((up->uba_cnfgr & UBIC) == 0) 5071919Swnj ; 5081919Swnj #endif 509*2324Skre DELAY(1000000); 510*2324Skre twait(); 511*2324Skre TMPHYS->tmcs = DCLR | GO; 5121919Swnj while (num > 0) { 5131919Swnj blk = num > DBSIZE ? DBSIZE : num; 5141919Swnj tmdwrite(start, blk); 5151919Swnj start += blk; 5161919Swnj num -= blk; 5171919Swnj } 5182297Swnj bdp = 1; /* crud to fool c compiler */ 5192297Swnj ((struct uba_regs *)PHYSUBA0)->uba_dpr[bdp] |= BNE; 5201919Swnj } 5211919Swnj 5221919Swnj tmdwrite(buf, num) 5231919Swnj register buf, num; 5241919Swnj { 5251919Swnj register int *io, npf; 5262297Swnj int bdp; 5271928Swnj 5282043Swnj twait(); 5292297Swnj bdp = 1; /* more dastardly tricks on pcc */ 5302297Swnj ((struct uba_regs *)PHYSUBA0)->uba_dpr[bdp] |= BNE; 5311919Swnj io = (int *)((struct uba_regs *)PHYSUBA0)->uba_map; 5321919Swnj npf = num+1; 5331928Swnj while (--npf != 0) 5341919Swnj *io++ = (int)(buf++ | (1<<21) | MRV); 5351919Swnj *io = 0; 5361919Swnj TMPHYS->tmbc = -(num*NBPG); 5371919Swnj TMPHYS->tmba = 0; 538*2324Skre TMPHYS->tmcs = WCOM | GO; 5391919Swnj } 5401919Swnj 5412043Swnj twait() 5421919Swnj { 5431928Swnj register s; 5441919Swnj 5451919Swnj do 5461919Swnj s = TMPHYS->tmcs; 5471919Swnj while ((s & CUR) == 0); 5481919Swnj } 5491919Swnj 5502043Swnj rewind() 5511919Swnj { 5521919Swnj 5532043Swnj twait(); 5541919Swnj TMPHYS->tmcs = REW | GO; 5551919Swnj } 5561919Swnj 5572043Swnj teof() 5581919Swnj { 5591919Swnj 5602043Swnj twait(); 561*2324Skre TMPHYS->tmcs = WEOF | GO; 5621919Swnj } 5631919Swnj #endif 564