1 /* tm.c 4.1 12/17/80 */ 2 3 #include "../conf/tm.h" 4 #if NTM > 0 5 /* 6 * TM tape driver 7 */ 8 9 #include "../h/param.h" 10 #include "../h/buf.h" 11 #include "../h/dir.h" 12 #include "../h/conf.h" 13 #include "../h/user.h" 14 #include "../h/file.h" 15 #include "../h/map.h" 16 #include "../h/pte.h" 17 #include "../h/uba.h" 18 #include "../h/mtio.h" 19 #include "../h/ioctl.h" 20 #include "../h/vm.h" 21 22 struct device { 23 u_short tmer; 24 u_short tmcs; 25 short tmbc; 26 u_short tmba; 27 short tmdb; 28 short tmrd; 29 }; 30 31 #define b_repcnt b_bcount 32 #define b_command b_resid 33 34 struct buf tmtab; 35 struct buf ctmbuf; 36 struct buf rtmbuf; 37 38 int tm_ubinfo; 39 40 /* bits in minor device */ 41 #define T_NOREWIND 04 42 #define T_1600BPI 08 43 44 #define INF (daddr_t)1000000L 45 46 /* 47 * Really only handle one tape drive... if you have more than one, 48 * you can make all these arrays and change the obvious things, but 49 * it is not clear what happens when some drives are transferring while 50 * others rewind, so we don't pretend that this driver handles multiple 51 * tape drives. 52 */ 53 char t_openf; 54 daddr_t t_blkno; 55 char t_flags; 56 daddr_t t_nxrec; 57 u_short t_erreg; 58 u_short t_dsreg; 59 short t_resid; 60 61 /* bits in tmcs */ 62 #define GO 01 63 #define OFFL 0 64 #define RCOM 02 65 #define WCOM 04 66 #define WEOF 06 67 #define SFORW 010 68 #define SREV 012 69 #define WIRG 014 70 #define REW 016 71 #define IENABLE 0100 72 #define CUR 0200 73 #define NOP IENABLE 74 #define DCLR 010000 75 #define D800 060000 76 #define ERROR 0100000 77 78 /* bits in tmer */ 79 #define TUR 1 80 #define RWS 02 81 #define WRL 04 82 #define SDWN 010 83 #define BOT 040 84 #define SELR 0100 85 #define NXM 0200 86 #define TMBTE 0400 87 #define RLE 01000 88 #define EOT 02000 89 #define BGL 04000 90 #define PAE 010000 91 #define CRE 020000 92 #define EOF 040000 93 #define ILC 0100000 94 95 #define HARD (ILC|EOT) 96 #define SOFT (CRE|PAE|BGL|RLE|TMBTE|NXM) 97 98 #define SSEEK 1 /* seeking */ 99 #define SIO 2 /* doing seq i/o */ 100 #define SCOM 3 /* sending control command */ 101 102 #define LASTIOW 1 /* last op was a write */ 103 #define WAITREW 2 /* someone is waiting for a rewind */ 104 105 tmopen(dev, flag) 106 dev_t dev; 107 int flag; 108 { 109 register ds, unit; 110 111 tmtab.b_flags |= B_TAPE; 112 unit = minor(dev)&03; 113 if (unit >= NTM || t_openf) { 114 u.u_error = ENXIO; /* out of range or open */ 115 return; 116 } 117 tcommand(dev, NOP, 1); 118 if ((t_erreg&SELR) == 0) { 119 u.u_error = EIO; /* offline */ 120 return; 121 } 122 t_openf = 1; 123 if (t_erreg&RWS) 124 tmwaitrws(dev); /* wait for rewind complete */ 125 while (t_erreg&SDWN) 126 tcommand(dev, NOP, 1); /* await settle down */ 127 if ((t_erreg&TUR)==0 || 128 ((flag&(FREAD|FWRITE)) == FWRITE && (t_erreg&WRL))) { 129 TMADDR->tmcs = DCLR|GO; 130 u.u_error = EIO; /* offline or write protect */ 131 } 132 if (u.u_error != 0) { 133 t_openf = 0; 134 return; 135 } 136 t_blkno = (daddr_t)0; 137 t_nxrec = INF; 138 t_flags = 0; 139 t_openf = 1; 140 } 141 142 tmwaitrws(dev) 143 register dev; 144 { 145 146 spl5(); 147 for (;;) { 148 tcommand(dev, NOP, 1); 149 if ((t_erreg&RWS) == 0) { 150 spl0(); /* rewind complete */ 151 return; 152 } 153 t_flags |= WAITREW; 154 sleep((caddr_t)&t_flags, PRIBIO); 155 } 156 } 157 158 tmclose(dev, flag) 159 register dev_t dev; 160 register flag; 161 { 162 163 if (flag == FWRITE || ((flag&FWRITE) && (t_flags&LASTIOW))) { 164 tcommand(dev, WEOF, 1); 165 tcommand(dev, WEOF, 1); 166 tcommand(dev, SREV, 1); 167 } 168 if ((minor(dev)&T_NOREWIND) == 0) 169 tcommand(dev, REW, 1); 170 t_openf = 0; 171 } 172 173 tcommand(dev, com, count) 174 dev_t dev; 175 int com, count; 176 { 177 register struct buf *bp; 178 179 bp = &ctmbuf; 180 (void) spl5(); 181 while (bp->b_flags&B_BUSY) { 182 bp->b_flags |= B_WANTED; 183 sleep((caddr_t)bp, PRIBIO); 184 } 185 bp->b_flags = B_BUSY|B_READ; 186 (void) spl0(); 187 bp->b_dev = dev; 188 bp->b_repcnt = -count; 189 bp->b_command = com; 190 bp->b_blkno = 0; 191 tmstrategy(bp); 192 iowait(bp); 193 if (bp->b_flags&B_WANTED) 194 wakeup((caddr_t)bp); 195 bp->b_flags &= B_ERROR; 196 } 197 198 tmstrategy(bp) 199 register struct buf *bp; 200 { 201 register daddr_t *p; 202 203 tcommand(bp->b_dev, NOP, 1); 204 if (t_erreg&RWS) 205 tmwaitrws(bp->b_dev); 206 if (bp != &ctmbuf) { 207 p = &t_nxrec; 208 if (dbtofsb(bp->b_blkno) > *p) { 209 bp->b_flags |= B_ERROR; 210 bp->b_error = ENXIO; /* past EOF */ 211 iodone(bp); 212 return; 213 } else if (dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) { 214 bp->b_resid = bp->b_bcount; 215 clrbuf(bp); /* at EOF */ 216 iodone(bp); 217 return; 218 } else if ((bp->b_flags&B_READ) == 0) 219 *p = dbtofsb(bp->b_blkno) + 1; /* write sets EOF */ 220 } 221 bp->av_forw = NULL; 222 (void) spl5(); 223 if (tmtab.b_actf == NULL) 224 tmtab.b_actf = bp; 225 else 226 tmtab.b_actl->av_forw = bp; 227 tmtab.b_actl = bp; 228 if (tmtab.b_active == 0) 229 tmstart(); 230 (void) spl0(); 231 } 232 233 tmstart() 234 { 235 register struct buf *bp; 236 register cmd; 237 register daddr_t blkno; 238 239 loop: 240 if ((bp = tmtab.b_actf) == 0) 241 return; 242 t_dsreg = TMADDR->tmcs; 243 t_erreg = TMADDR->tmer; 244 t_resid = TMADDR->tmbc; 245 t_flags &= ~LASTIOW; 246 if (t_openf < 0 || (TMADDR->tmcs&CUR) == 0) { 247 /* t_openf = -1; ??? */ 248 bp->b_flags |= B_ERROR; /* hard error'ed or !SELR */ 249 goto next; 250 } 251 cmd = IENABLE | GO; 252 if ((minor(bp->b_dev) & T_1600BPI) == 0) 253 cmd |= D800; 254 if (bp == &ctmbuf) { 255 if (bp->b_command == NOP) 256 goto next; /* just get status */ 257 else { 258 cmd |= bp->b_command; 259 tmtab.b_active = SCOM; 260 if (bp->b_command == SFORW || bp->b_command == SREV) 261 TMADDR->tmbc = bp->b_repcnt; 262 TMADDR->tmcs = cmd; 263 return; 264 } 265 } 266 if ((blkno = t_blkno) == dbtofsb(bp->b_blkno)) { 267 TMADDR->tmbc = -bp->b_bcount; 268 if (tm_ubinfo == 0) 269 tm_ubinfo = ubasetup(bp,1); 270 if ((bp->b_flags&B_READ) == 0) { 271 if (tmtab.b_errcnt) 272 cmd |= WIRG; 273 else 274 cmd |= WCOM; 275 } else 276 cmd |= RCOM; 277 cmd |= (tm_ubinfo >> 12) & 0x30; 278 tmtab.b_active = SIO; 279 TMADDR->tmba = tm_ubinfo; 280 TMADDR->tmcs = cmd; 281 return; 282 } 283 tmtab.b_active = SSEEK; 284 if (blkno < dbtofsb(bp->b_blkno)) { 285 cmd |= SFORW; 286 TMADDR->tmbc = blkno - dbtofsb(bp->b_blkno); 287 } else { 288 cmd |= SREV; 289 TMADDR->tmbc = dbtofsb(bp->b_blkno) - blkno; 290 } 291 TMADDR->tmcs = cmd; 292 return; 293 294 next: 295 if (tm_ubinfo != 0) { 296 ubafree(tm_ubinfo); 297 tm_ubinfo = 0; 298 } 299 tmtab.b_actf = bp->av_forw; 300 iodone(bp); 301 goto loop; 302 } 303 304 tmintr() 305 { 306 register struct buf *bp; 307 register state; 308 309 if (t_flags&WAITREW && (TMADDR->tmer&RWS) == 0) { 310 t_flags &= ~WAITREW; 311 wakeup((caddr_t)&t_flags); 312 } 313 if ((bp = tmtab.b_actf) == NULL) 314 return; 315 t_dsreg = TMADDR->tmcs; 316 TMADDR->tmcs = IENABLE; 317 t_erreg = TMADDR->tmer; 318 t_resid = TMADDR->tmbc; 319 if ((bp->b_flags & B_READ) == 0) 320 t_flags |= LASTIOW; 321 state = tmtab.b_active; 322 tmtab.b_active = 0; 323 if (TMADDR->tmcs&ERROR) { 324 while(TMADDR->tmer & SDWN) 325 ; /* await settle down */ 326 if (TMADDR->tmer&EOF) { 327 tmseteof(bp); /* set blkno and nxrec */ 328 state = SCOM; 329 TMADDR->tmbc = -bp->b_bcount; 330 goto errout; 331 } 332 if ((bp->b_flags&B_READ) && (TMADDR->tmer&(HARD|SOFT)) == RLE) 333 goto out; 334 if ((TMADDR->tmer&HARD)==0 && state==SIO) { 335 if (++tmtab.b_errcnt < 3) { 336 if((TMADDR->tmer&SOFT) == NXM) 337 printf("TM UBA late error\n"); 338 else 339 t_blkno++; 340 if (tm_ubinfo) { 341 ubafree(tm_ubinfo); 342 tm_ubinfo = 0; 343 } 344 tmstart(); 345 return; 346 } 347 } else if (t_openf>0 && bp != &rtmbuf) 348 t_openf = -1; 349 deverror(bp, t_erreg, 0); 350 bp->b_flags |= B_ERROR; 351 state = SIO; 352 } 353 out: 354 switch (state) { 355 356 case SIO: 357 t_blkno++; 358 /* fall into ... */ 359 360 case SCOM: 361 if (bp == &ctmbuf) { 362 switch (bp->b_command) { 363 case SFORW: 364 t_blkno -= bp->b_repcnt; 365 break; 366 367 case SREV: 368 t_blkno += bp->b_repcnt; 369 break; 370 371 default: 372 if (++bp->b_repcnt < 0) { 373 tmstart(); /* continue */ 374 return; 375 } 376 } 377 } 378 errout: 379 tmtab.b_errcnt = 0; 380 tmtab.b_actf = bp->av_forw; 381 bp->b_resid = -TMADDR->tmbc; 382 if (tm_ubinfo != 0) { 383 ubafree(tm_ubinfo); 384 tm_ubinfo = 0; 385 } 386 iodone(bp); 387 break; 388 389 case SSEEK: 390 t_blkno = dbtofsb(bp->b_blkno); 391 break; 392 393 default: 394 return; 395 } 396 tmstart(); 397 } 398 399 tmseteof(bp) 400 register struct buf *bp; 401 { 402 403 if (bp == &ctmbuf) { 404 if (t_blkno > dbtofsb(bp->b_blkno)) { 405 /* reversing */ 406 t_nxrec = dbtofsb(bp->b_blkno) - TMADDR->tmbc; 407 t_blkno = t_nxrec; 408 } else { 409 /* spacing forward */ 410 t_blkno = dbtofsb(bp->b_blkno) + TMADDR->tmbc; 411 t_nxrec = t_blkno - 1; 412 } 413 return; 414 } 415 /* eof on read */ 416 t_nxrec = dbtofsb(bp->b_blkno); 417 } 418 419 tmread(dev) 420 { 421 422 tmphys(dev); 423 physio(tmstrategy, &rtmbuf, dev, B_READ, minphys); 424 } 425 426 tmwrite(dev) 427 { 428 429 tmphys(dev); 430 physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys); 431 } 432 433 tmphys(dev) 434 { 435 register daddr_t a; 436 437 a = dbtofsb(u.u_offset >> 9); 438 t_blkno = a; 439 t_nxrec = a + 1; 440 } 441 442 /*ARGSUSED*/ 443 tmioctl(dev, cmd, addr, flag) 444 caddr_t addr; 445 dev_t dev; 446 { 447 register callcount; 448 int fcount; 449 struct mtop mtop; 450 struct mtget mtget; 451 /* we depend of the values and order of the MT codes here */ 452 static tmops[] = {WEOF, SFORW, SREV, SFORW, SREV, REW, OFFL}; 453 454 switch(cmd) { 455 case MTIOCTOP: /* tape operation */ 456 if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) { 457 u.u_error = EFAULT; 458 return; 459 } 460 switch(mtop.mt_op) { 461 case MTWEOF: case MTFSF: case MTBSF: 462 callcount = mtop.mt_count; 463 fcount = INF; 464 break; 465 case MTFSR: case MTBSR: 466 callcount = 1; 467 fcount = mtop.mt_count; 468 break; 469 case MTREW: case MTOFFL: 470 callcount = 1; 471 fcount = 1; 472 break; 473 default: 474 u.u_error = ENXIO; 475 return; 476 } 477 if (callcount <= 0 || fcount <= 0) 478 u.u_error = ENXIO; 479 else while (--callcount >= 0) { 480 tcommand(dev, tmops[mtop.mt_op], fcount); 481 if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) && 482 ctmbuf.b_resid) { 483 u.u_error = EIO; 484 break; 485 } 486 if ((ctmbuf.b_flags&B_ERROR) || t_erreg&BOT) 487 break; 488 } 489 geterror(&ctmbuf); 490 return; 491 case MTIOCGET: 492 mtget.mt_dsreg = t_dsreg; 493 mtget.mt_erreg = t_erreg; 494 mtget.mt_resid = t_resid; 495 if (copyout((caddr_t)&mtget, addr, sizeof(mtget))) 496 u.u_error = EFAULT; 497 return; 498 default: 499 u.u_error = ENXIO; 500 } 501 } 502 503 #define DBSIZE 20 504 505 twall(start, num) 506 int start, num; 507 { 508 #if VAX==780 509 register struct uba_regs *up = (struct uba_regs *)PHYSUBA0; 510 #endif 511 int blk; 512 513 TMPHYS->tmcs = DCLR | GO; 514 #if VAX==780 515 up->uba_cr = ADINIT; 516 up->uba_cr = IFS|BRIE|USEFIE|SUEFIE; 517 while ((up->uba_cnfgr & UBIC) == 0) 518 ; 519 #endif 520 while (num > 0) { 521 blk = num > DBSIZE ? DBSIZE : num; 522 tmdwrite(start, blk); 523 start += blk; 524 num -= blk; 525 } 526 } 527 528 tmdwrite(buf, num) 529 register buf, num; 530 { 531 register int *io, npf; 532 tmwait(); 533 /* Flush buffered data path 0 */ 534 ((struct uba_regs *)PHYSUBA0)->uba_dpr[1] = 0; 535 ((struct uba_regs *)PHYSUBA0)->uba_dpr[1] = BNE; 536 /* Map unibus address 0 to section of interest */ 537 io = (int *)((struct uba_regs *)PHYSUBA0)->uba_map; 538 npf = num+1; 539 while(--npf != 0) 540 *io++ = (int)(buf++ | (1<<21) | MRV); 541 *io = 0; 542 TMPHYS->tmbc = -(num*NBPG); 543 TMPHYS->tmba = 0; 544 TMPHYS->tmcs = WCOM | GO | D800; 545 } 546 547 tmwait() 548 { 549 register short s; 550 551 do 552 s = TMPHYS->tmcs; 553 while ((s & CUR) == 0); 554 } 555 556 tmrewind() 557 { 558 559 tmwait(); 560 TMPHYS->tmcs = REW | GO; 561 } 562 563 tmeof() 564 { 565 566 tmwait(); 567 TMPHYS->tmcs = WEOF | GO | D800; 568 } 569 #endif 570