1*1900Swnj /* ts.c 4.1 12/17/80 */ 2*1900Swnj 3*1900Swnj #include "../conf/ts.h" 4*1900Swnj #if NTS > 0 5*1900Swnj /* 6*1900Swnj * TS11 tape driver 7*1900Swnj */ 8*1900Swnj 9*1900Swnj #include "../h/param.h" 10*1900Swnj #include "../h/systm.h" 11*1900Swnj #include "../h/buf.h" 12*1900Swnj #include "../h/conf.h" 13*1900Swnj #include "../h/dir.h" 14*1900Swnj #include "../h/file.h" 15*1900Swnj #include "../h/user.h" 16*1900Swnj #include "../h/pte.h" 17*1900Swnj #include "../h/map.h" 18*1900Swnj #include "../h/uba.h" 19*1900Swnj 20*1900Swnj typedef unsigned short ushort; 21*1900Swnj 22*1900Swnj struct device { 23*1900Swnj ushort tsdb; 24*1900Swnj ushort tssr; 25*1900Swnj }; 26*1900Swnj 27*1900Swnj struct buf tstab; 28*1900Swnj struct buf rtsbuf; 29*1900Swnj struct buf ctsbuf; 30*1900Swnj 31*1900Swnj #define INF 1000000000 32*1900Swnj 33*1900Swnj ushort ts_uba; 34*1900Swnj long ts_iouba; 35*1900Swnj char ts_flags; 36*1900Swnj char ts_openf; 37*1900Swnj daddr_t ts_blkno; 38*1900Swnj daddr_t ts_nxrec; 39*1900Swnj 40*1900Swnj /* status message */ 41*1900Swnj struct sts { 42*1900Swnj ushort s_sts; 43*1900Swnj ushort len; 44*1900Swnj ushort rbpcr; 45*1900Swnj ushort xs0; 46*1900Swnj ushort xs1; 47*1900Swnj ushort xs2; 48*1900Swnj ushort xs3; 49*1900Swnj }; 50*1900Swnj 51*1900Swnj /* Error codes in stat 0 */ 52*1900Swnj #define TMK 0100000 53*1900Swnj #define RLS 040000 54*1900Swnj #define ONL 0100 55*1900Swnj #define WLE 04000 56*1900Swnj 57*1900Swnj /* command message */ 58*1900Swnj struct cmd { 59*1900Swnj ushort c_cmd; 60*1900Swnj ushort c_loba; 61*1900Swnj ushort c_hiba; 62*1900Swnj ushort c_size; 63*1900Swnj }; 64*1900Swnj 65*1900Swnj #define ACK 0100000 66*1900Swnj #define CVC 040000 67*1900Swnj #define IE 0200 68*1900Swnj #define READ 01 69*1900Swnj #define REREAD 01001 70*1900Swnj 71*1900Swnj #define SETCHR 04 72*1900Swnj 73*1900Swnj #define WRITE 05 74*1900Swnj #define REWRITE 01005 75*1900Swnj 76*1900Swnj #define SFORW 010 77*1900Swnj #define SREV 0410 78*1900Swnj #define REW 02010 79*1900Swnj 80*1900Swnj #define WTM 011 81*1900Swnj 82*1900Swnj #define GSTAT 017 83*1900Swnj 84*1900Swnj /* characteristics data */ 85*1900Swnj struct charac { 86*1900Swnj ushort char_loba; 87*1900Swnj ushort char_hiba; 88*1900Swnj ushort char_size; 89*1900Swnj ushort char_mode; 90*1900Swnj }; 91*1900Swnj 92*1900Swnj /* All the packets, collected */ 93*1900Swnj struct tsmesg { 94*1900Swnj struct cmd ts_cmd; 95*1900Swnj struct sts ts_sts; 96*1900Swnj struct charac ts_char; 97*1900Swnj int align; /* Should force alignment */ 98*1900Swnj } ts; 99*1900Swnj 100*1900Swnj /* Bits in (unibus) status register */ 101*1900Swnj #define SC 0100000 102*1900Swnj #define SSR 0200 103*1900Swnj #define OFL 0100 104*1900Swnj #define NBA 02000 105*1900Swnj 106*1900Swnj /* states */ 107*1900Swnj #define SIO 1 108*1900Swnj #define SSFOR 2 109*1900Swnj #define SSREV 3 110*1900Swnj #define SRETRY 4 111*1900Swnj #define SCOM 5 112*1900Swnj #define SOK 6 113*1900Swnj 114*1900Swnj #define H_WRITTEN 1 115*1900Swnj 116*1900Swnj tsopen(dev, flag) 117*1900Swnj { 118*1900Swnj register struct device *tsaddr = TSADDR; 119*1900Swnj static struct tsmesg *ubaddr; 120*1900Swnj 121*1900Swnj tstab.b_flags |= B_TAPE; 122*1900Swnj if (ts_openf) { 123*1900Swnj u.u_error = ENXIO; 124*1900Swnj return; 125*1900Swnj } 126*1900Swnj if (ubaddr==0 || tsaddr->tssr&(OFL|NBA) || (tsaddr->tssr&SSR)==0) { 127*1900Swnj long i = 0; 128*1900Swnj tsaddr->tssr = 0; 129*1900Swnj while ((tsaddr->tssr & SSR)==0) { 130*1900Swnj if (++i > 1000000) { 131*1900Swnj printf("Tape unready\n"); 132*1900Swnj u.u_error = ENXIO; 133*1900Swnj return; 134*1900Swnj } 135*1900Swnj } 136*1900Swnj } 137*1900Swnj if (tsaddr->tssr&OFL) { 138*1900Swnj printf("Tape offline\n"); 139*1900Swnj u.u_error = ENXIO; 140*1900Swnj return; 141*1900Swnj } 142*1900Swnj if (tsaddr->tssr&NBA) { 143*1900Swnj ctsbuf.b_un.b_addr = (caddr_t) &ts; 144*1900Swnj ctsbuf.b_bcount = sizeof(ts); 145*1900Swnj if (ubaddr == 0) 146*1900Swnj ubaddr = (struct tsmesg *)ubasetup(&ctsbuf, 0); 147*1900Swnj ts_uba = (ushort)((long)ubaddr + (((long)ubaddr >> 16) & 03)); 148*1900Swnj ts.ts_char.char_loba = (int)&ubaddr->ts_sts; 149*1900Swnj ts.ts_char.char_hiba = (ushort)((long)&ubaddr->ts_sts >> 16) & 03; 150*1900Swnj ts.ts_char.char_size = sizeof(ts.ts_sts); 151*1900Swnj ts.ts_char.char_mode = 0400; /* Stop on 2 tape marks */ 152*1900Swnj ts.ts_cmd.c_cmd = ACK + 04; /* write characteristics */ 153*1900Swnj ts.ts_cmd.c_loba = (int)&ubaddr->ts_char; 154*1900Swnj ts.ts_cmd.c_hiba = (ushort)((long)&ubaddr->ts_sts >> 16) & 03; 155*1900Swnj ts.ts_cmd.c_size = sizeof(ts.ts_sts); 156*1900Swnj tsaddr->tsdb = ts_uba; 157*1900Swnj } 158*1900Swnj ts_blkno = 0; 159*1900Swnj ts_nxrec = INF; 160*1900Swnj ts_flags = 0; 161*1900Swnj if (u.u_error==0) 162*1900Swnj ts_openf++; 163*1900Swnj } 164*1900Swnj 165*1900Swnj tsclose(dev, flag) 166*1900Swnj { 167*1900Swnj 168*1900Swnj if (flag == FWRITE || ((flag&FWRITE) && (ts_flags&H_WRITTEN))) { 169*1900Swnj tscommand(WTM); 170*1900Swnj tscommand(WTM); 171*1900Swnj tscommand(SREV); 172*1900Swnj } 173*1900Swnj if ((minor(dev)&4) == 0) 174*1900Swnj tscommand(REW); 175*1900Swnj ts_openf = 0; 176*1900Swnj } 177*1900Swnj 178*1900Swnj tscommand(com) 179*1900Swnj { 180*1900Swnj register struct buf *bp; 181*1900Swnj 182*1900Swnj bp = &ctsbuf; 183*1900Swnj spl5(); 184*1900Swnj while(bp->b_flags&B_BUSY) { 185*1900Swnj bp->b_flags |= B_WANTED; 186*1900Swnj sleep((caddr_t)bp, PRIBIO); 187*1900Swnj } 188*1900Swnj spl0(); 189*1900Swnj bp->b_resid = com; 190*1900Swnj bp->b_blkno = 0; 191*1900Swnj bp->b_flags = B_BUSY|B_READ; 192*1900Swnj tsstrategy(bp); 193*1900Swnj iowait(bp); 194*1900Swnj if(bp->b_flags&B_WANTED) 195*1900Swnj wakeup((caddr_t)bp); 196*1900Swnj bp->b_flags = 0; 197*1900Swnj return(bp->b_resid); 198*1900Swnj } 199*1900Swnj 200*1900Swnj tsstrategy(bp) 201*1900Swnj register struct buf *bp; 202*1900Swnj { 203*1900Swnj register daddr_t *p; 204*1900Swnj 205*1900Swnj if(bp != &ctsbuf) { 206*1900Swnj p = &ts_nxrec; 207*1900Swnj if(dbtofsb(bp->b_blkno) > *p) { 208*1900Swnj bp->b_flags |= B_ERROR; 209*1900Swnj bp->b_error = ENXIO; 210*1900Swnj iodone(bp); 211*1900Swnj return; 212*1900Swnj } 213*1900Swnj if(dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) { 214*1900Swnj bp->b_resid = bp->b_bcount; 215*1900Swnj iodone(bp); 216*1900Swnj return; 217*1900Swnj } 218*1900Swnj if ((bp->b_flags&B_READ)==0) { 219*1900Swnj *p = dbtofsb(bp->b_blkno) + 1; 220*1900Swnj ts_flags |= H_WRITTEN; 221*1900Swnj } 222*1900Swnj } 223*1900Swnj bp->av_forw = NULL; 224*1900Swnj spl5(); 225*1900Swnj if (tstab.b_actf == NULL) 226*1900Swnj tstab.b_actf = bp; 227*1900Swnj else 228*1900Swnj tstab.b_actl->av_forw = bp; 229*1900Swnj tstab.b_actl = bp; 230*1900Swnj if (tstab.b_active==0) 231*1900Swnj tsstart(); 232*1900Swnj spl0(); 233*1900Swnj } 234*1900Swnj 235*1900Swnj tsstart() 236*1900Swnj { 237*1900Swnj register struct buf *bp; 238*1900Swnj register struct device *tsaddr = TSADDR; 239*1900Swnj daddr_t blkno; 240*1900Swnj 241*1900Swnj loop: 242*1900Swnj if ((bp = tstab.b_actf) == NULL) 243*1900Swnj return; 244*1900Swnj blkno = ts_blkno; 245*1900Swnj if (ts_openf < 0 || dbtofsb(bp->b_blkno) > ts_nxrec) 246*1900Swnj goto abort; 247*1900Swnj if (bp == &ctsbuf) { 248*1900Swnj tstab.b_active = SCOM; 249*1900Swnj ts.ts_cmd.c_cmd = ACK+CVC+IE+bp->b_resid; 250*1900Swnj ts.ts_cmd.c_loba = 1; /* count always 1 */ 251*1900Swnj } else if (blkno == dbtofsb(bp->b_blkno)) { 252*1900Swnj tstab.b_active = SIO; 253*1900Swnj ts_iouba = ubasetup(bp, 1); 254*1900Swnj ts.ts_cmd.c_loba = (ushort)ts_iouba; 255*1900Swnj ts.ts_cmd.c_hiba = (ushort)(ts_iouba >> 16) & 03; 256*1900Swnj ts.ts_cmd.c_size = bp->b_bcount; 257*1900Swnj if(bp->b_flags & B_READ) 258*1900Swnj ts.ts_cmd.c_cmd = ACK+CVC+IE+READ; 259*1900Swnj else 260*1900Swnj ts.ts_cmd.c_cmd = ACK+CVC+IE+WRITE; 261*1900Swnj } else { 262*1900Swnj if (blkno < dbtofsb(bp->b_blkno)) { 263*1900Swnj tstab.b_active = SSFOR; 264*1900Swnj ts.ts_cmd.c_cmd = ACK+CVC+IE+SFORW; 265*1900Swnj ts.ts_cmd.c_loba = dbtofsb(bp->b_blkno) - blkno; 266*1900Swnj } else { 267*1900Swnj tstab.b_active = SSREV; 268*1900Swnj ts.ts_cmd.c_cmd = ACK+CVC+IE+SREV; 269*1900Swnj ts.ts_cmd.c_loba = blkno - dbtofsb(bp->b_blkno); 270*1900Swnj } 271*1900Swnj } 272*1900Swnj tsaddr->tsdb = ts_uba; 273*1900Swnj return; 274*1900Swnj 275*1900Swnj abort: 276*1900Swnj bp->b_flags |= B_ERROR; 277*1900Swnj 278*1900Swnj next: 279*1900Swnj tstab.b_active = 0; 280*1900Swnj tstab.b_actf = bp->av_forw; 281*1900Swnj iodone(bp); 282*1900Swnj goto loop; 283*1900Swnj } 284*1900Swnj 285*1900Swnj tsintr() 286*1900Swnj { 287*1900Swnj register struct buf *bp; 288*1900Swnj register struct device *tsaddr = TSADDR; 289*1900Swnj register err, errclass, state; 290*1900Swnj 291*1900Swnj if ((bp = tstab.b_actf)==NULL) 292*1900Swnj return; 293*1900Swnj state = tstab.b_active; 294*1900Swnj tstab.b_active = 0; 295*1900Swnj err = tsaddr->tssr & 016; 296*1900Swnj if ((tsaddr->tssr & SC) == 0) 297*1900Swnj err = 0; 298*1900Swnj errclass = 0; 299*1900Swnj switch (err) { 300*1900Swnj case 014: /* unrecoverable */ 301*1900Swnj case 016: /* fatal */ 302*1900Swnj case 002: /* attention (shouldn't happen) */ 303*1900Swnj case 012: /* "recoverable", but shouldn't happen */ 304*1900Swnj errclass = 2; 305*1900Swnj break; 306*1900Swnj 307*1900Swnj case 0: /* all OK */ 308*1900Swnj break; 309*1900Swnj 310*1900Swnj case 004: /* status alert */ 311*1900Swnj if (ts.ts_sts.xs0&RLS && bp==&rtsbuf) /* short record */ 312*1900Swnj break; 313*1900Swnj if (ts.ts_sts.xs0 & TMK) { /* tape mark */ 314*1900Swnj ts.ts_sts.rbpcr = bp->b_bcount; 315*1900Swnj break; 316*1900Swnj } 317*1900Swnj errclass = 1; 318*1900Swnj break; 319*1900Swnj 320*1900Swnj case 010: /* recoverable, tape moved */ 321*1900Swnj if (state==SIO && ++bp->b_errcnt < 10) { 322*1900Swnj ts.ts_cmd.c_cmd |= 01000; /* redo bit */ 323*1900Swnj tstab.b_active = SIO; 324*1900Swnj tsaddr->tsdb = ts_uba; 325*1900Swnj return; 326*1900Swnj } 327*1900Swnj errclass = 1; 328*1900Swnj break; 329*1900Swnj 330*1900Swnj case 006: /* Function reject */ 331*1900Swnj if (state==SIO && ts.ts_sts.xs0 & WLE) 332*1900Swnj printf("Tape needs a ring\n"); 333*1900Swnj if ((ts.ts_sts.xs0&ONL) == 0) /* tape offline */ 334*1900Swnj printf("Tape offline\n"); 335*1900Swnj errclass = 2; 336*1900Swnj } 337*1900Swnj if (errclass) 338*1900Swnj printf("tp: %o %o %o %o %o %o %o %o\n", tsaddr->tssr, 339*1900Swnj ts.ts_sts.s_sts, ts.ts_sts.len, ts.ts_sts.rbpcr, 340*1900Swnj ts.ts_sts.xs0, ts.ts_sts.xs1, ts.ts_sts.xs2, ts.ts_sts.xs3); 341*1900Swnj switch(state) { 342*1900Swnj case SIO: 343*1900Swnj ts_blkno++; 344*1900Swnj if (ts_iouba) 345*1900Swnj ubafree(ts_iouba); 346*1900Swnj else 347*1900Swnj printf("uba alloc botch\n"); 348*1900Swnj ts_iouba = 0; 349*1900Swnj case SCOM: 350*1900Swnj tstab.b_errcnt = 0; 351*1900Swnj tstab.b_actf = bp->av_forw; 352*1900Swnj bp->b_resid = ts.ts_sts.rbpcr; 353*1900Swnj iodone(bp); 354*1900Swnj break; 355*1900Swnj 356*1900Swnj case SSFOR: 357*1900Swnj case SSREV: 358*1900Swnj ts_blkno = dbtofsb(bp->b_blkno); 359*1900Swnj break; 360*1900Swnj 361*1900Swnj default: 362*1900Swnj printf("Unknown tape interrupt\n"); 363*1900Swnj errclass = 2; 364*1900Swnj break; 365*1900Swnj } 366*1900Swnj if (errclass > 1) { 367*1900Swnj while (bp = tstab.b_actf) { 368*1900Swnj bp->b_flags |= B_ERROR; 369*1900Swnj iodone(bp); 370*1900Swnj tstab.b_actf = bp->av_forw; 371*1900Swnj } 372*1900Swnj } 373*1900Swnj tsstart(); 374*1900Swnj } 375*1900Swnj 376*1900Swnj tsread(dev) 377*1900Swnj { 378*1900Swnj tsphys(dev); 379*1900Swnj physio(tsstrategy, &rtsbuf, dev, B_READ, minphys); 380*1900Swnj } 381*1900Swnj 382*1900Swnj tswrite(dev) 383*1900Swnj { 384*1900Swnj tsphys(dev); 385*1900Swnj physio(tsstrategy, &rtsbuf, dev, B_WRITE, minphys); 386*1900Swnj } 387*1900Swnj 388*1900Swnj tsphys(dev) 389*1900Swnj { 390*1900Swnj register unit; 391*1900Swnj daddr_t a; 392*1900Swnj 393*1900Swnj a = u.u_offset >> 9; 394*1900Swnj ts_blkno = dbtofsb(a); 395*1900Swnj ts_nxrec = dbtofsb(a)+1; 396*1900Swnj } 397*1900Swnj #endif 398