1 /* tm.c 4.5 12/30/80 */ 2 3 #include "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 if ((TMADDR->tmer&RWS) == 0) { 149 spl0(); /* rewind complete */ 150 return; 151 } 152 t_flags |= WAITREW; 153 sleep((caddr_t)&t_flags, PRIBIO); 154 } 155 } 156 157 tmclose(dev, flag) 158 register dev_t dev; 159 register flag; 160 { 161 162 if (flag == FWRITE || ((flag&FWRITE) && (t_flags&LASTIOW))) { 163 tcommand(dev, WEOF, 1); 164 tcommand(dev, WEOF, 1); 165 tcommand(dev, SREV, 1); 166 } 167 if ((minor(dev)&T_NOREWIND) == 0) 168 tcommand(dev, REW, 1); 169 t_openf = 0; 170 } 171 172 tcommand(dev, com, count) 173 dev_t dev; 174 int com, count; 175 { 176 register struct buf *bp; 177 178 bp = &ctmbuf; 179 (void) spl5(); 180 while (bp->b_flags&B_BUSY) { 181 bp->b_flags |= B_WANTED; 182 sleep((caddr_t)bp, PRIBIO); 183 } 184 bp->b_flags = B_BUSY|B_READ; 185 (void) spl0(); 186 bp->b_dev = dev; 187 bp->b_repcnt = -count; 188 bp->b_command = com; 189 bp->b_blkno = 0; 190 tmstrategy(bp); 191 iowait(bp); 192 if (bp->b_flags&B_WANTED) 193 wakeup((caddr_t)bp); 194 bp->b_flags &= B_ERROR; 195 } 196 197 tmstrategy(bp) 198 register struct buf *bp; 199 { 200 register daddr_t *p; 201 202 tmwaitrws(bp->b_dev); 203 if (bp != &ctmbuf) { 204 p = &t_nxrec; 205 if (dbtofsb(bp->b_blkno) > *p) { 206 bp->b_flags |= B_ERROR; 207 bp->b_error = ENXIO; /* past EOF */ 208 iodone(bp); 209 return; 210 } else if (dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) { 211 bp->b_resid = bp->b_bcount; 212 clrbuf(bp); /* at EOF */ 213 iodone(bp); 214 return; 215 } else if ((bp->b_flags&B_READ) == 0) 216 *p = dbtofsb(bp->b_blkno) + 1; /* write sets EOF */ 217 } 218 bp->av_forw = NULL; 219 (void) spl5(); 220 if (tmtab.b_actf == NULL) 221 tmtab.b_actf = bp; 222 else 223 tmtab.b_actl->av_forw = bp; 224 tmtab.b_actl = bp; 225 if (tmtab.b_active == 0) 226 tmstart(); 227 (void) spl0(); 228 } 229 230 tmstart() 231 { 232 register struct buf *bp; 233 register cmd; 234 register daddr_t blkno; 235 int s; 236 237 loop: 238 if ((bp = tmtab.b_actf) == 0) 239 return; 240 t_dsreg = TMADDR->tmcs; 241 t_erreg = TMADDR->tmer; 242 t_resid = TMADDR->tmbc; 243 t_flags &= ~LASTIOW; 244 if (t_openf < 0 || (TMADDR->tmcs&CUR) == 0) { 245 /* t_openf = -1; ??? */ 246 bp->b_flags |= B_ERROR; /* hard error'ed or !SELR */ 247 goto next; 248 } 249 cmd = IENABLE | GO; 250 if ((minor(bp->b_dev) & T_1600BPI) == 0) 251 cmd |= D800; 252 if (bp == &ctmbuf) { 253 if (bp->b_command == NOP) 254 goto next; /* just get status */ 255 else { 256 cmd |= bp->b_command; 257 tmtab.b_active = SCOM; 258 if (bp->b_command == SFORW || bp->b_command == SREV) 259 TMADDR->tmbc = bp->b_repcnt; 260 TMADDR->tmcs = cmd; 261 return; 262 } 263 } 264 if ((blkno = t_blkno) == dbtofsb(bp->b_blkno)) { 265 TMADDR->tmbc = -bp->b_bcount; 266 s = spl6(); 267 if (tm_ubinfo == 0) 268 tm_ubinfo = ubasetup(bp,1); 269 splx(s); 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 ubarelse(&tm_ubinfo); 296 tmtab.b_actf = bp->av_forw; 297 iodone(bp); 298 goto loop; 299 } 300 301 tmintr() 302 { 303 register struct buf *bp; 304 register state; 305 306 if (t_flags&WAITREW && (TMADDR->tmer&RWS) == 0) { 307 t_flags &= ~WAITREW; 308 wakeup((caddr_t)&t_flags); 309 } 310 if ((bp = tmtab.b_actf) == NULL) 311 return; 312 t_dsreg = TMADDR->tmcs; 313 t_erreg = TMADDR->tmer; 314 t_resid = TMADDR->tmbc; 315 if ((bp->b_flags & B_READ) == 0) 316 t_flags |= LASTIOW; 317 state = tmtab.b_active; 318 tmtab.b_active = 0; 319 if (TMADDR->tmcs&ERROR) { 320 while(TMADDR->tmer & SDWN) 321 ; /* await settle down */ 322 if (TMADDR->tmer&EOF) { 323 tmseteof(bp); /* set blkno and nxrec */ 324 state = SCOM; 325 TMADDR->tmbc = -bp->b_bcount; 326 goto errout; 327 } 328 if ((bp->b_flags&B_READ) && (TMADDR->tmer&(HARD|SOFT)) == RLE) 329 goto out; 330 if ((TMADDR->tmer&HARD)==0 && state==SIO) { 331 if (++tmtab.b_errcnt < 7) { 332 if((TMADDR->tmer&SOFT) == NXM) 333 printf("TM UBA late error\n"); 334 else 335 t_blkno += 2; /* ???????? */ 336 ubarelse(&tm_ubinfo); 337 tmstart(); 338 return; 339 } 340 } else if (t_openf>0 && bp != &rtmbuf) 341 t_openf = -1; 342 deverror(bp, t_erreg, t_dsreg); 343 bp->b_flags |= B_ERROR; 344 state = SIO; 345 } 346 out: 347 switch (state) { 348 349 case SIO: 350 t_blkno++; 351 /* fall into ... */ 352 353 case SCOM: 354 if (bp == &ctmbuf) { 355 switch (bp->b_command) { 356 case SFORW: 357 t_blkno -= bp->b_repcnt; 358 break; 359 360 case SREV: 361 t_blkno += bp->b_repcnt; 362 break; 363 364 default: 365 if (++bp->b_repcnt < 0) { 366 tmstart(); /* continue */ 367 return; 368 } 369 } 370 } 371 errout: 372 tmtab.b_errcnt = 0; 373 tmtab.b_actf = bp->av_forw; 374 bp->b_resid = -TMADDR->tmbc; 375 ubarelse(&tm_ubinfo); 376 iodone(bp); 377 break; 378 379 case SSEEK: 380 t_blkno = dbtofsb(bp->b_blkno); 381 break; 382 383 default: 384 return; 385 } 386 tmstart(); 387 } 388 389 tmseteof(bp) 390 register struct buf *bp; 391 { 392 393 if (bp == &ctmbuf) { 394 if (t_blkno > dbtofsb(bp->b_blkno)) { 395 /* reversing */ 396 t_nxrec = dbtofsb(bp->b_blkno) - TMADDR->tmbc; 397 t_blkno = t_nxrec; 398 } else { 399 /* spacing forward */ 400 t_blkno = dbtofsb(bp->b_blkno) + TMADDR->tmbc; 401 t_nxrec = t_blkno - 1; 402 } 403 return; 404 } 405 /* eof on read */ 406 t_nxrec = dbtofsb(bp->b_blkno); 407 } 408 409 tmread(dev) 410 { 411 412 tmphys(dev); 413 physio(tmstrategy, &rtmbuf, dev, B_READ, minphys); 414 } 415 416 tmwrite(dev) 417 { 418 419 tmphys(dev); 420 physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys); 421 } 422 423 tmphys(dev) 424 { 425 register daddr_t a; 426 427 a = dbtofsb(u.u_offset >> 9); 428 t_blkno = a; 429 t_nxrec = a + 1; 430 } 431 432 /*ARGSUSED*/ 433 tmioctl(dev, cmd, addr, flag) 434 caddr_t addr; 435 dev_t dev; 436 { 437 register callcount; 438 int fcount; 439 struct mtop mtop; 440 struct mtget mtget; 441 /* we depend of the values and order of the MT codes here */ 442 static tmops[] = {WEOF, SFORW, SREV, SFORW, SREV, REW, OFFL}; 443 444 switch(cmd) { 445 case MTIOCTOP: /* tape operation */ 446 if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) { 447 u.u_error = EFAULT; 448 return; 449 } 450 switch(mtop.mt_op) { 451 case MTWEOF: case MTFSF: case MTBSF: 452 callcount = mtop.mt_count; 453 fcount = INF; 454 break; 455 case MTFSR: case MTBSR: 456 callcount = 1; 457 fcount = mtop.mt_count; 458 break; 459 case MTREW: case MTOFFL: 460 callcount = 1; 461 fcount = 1; 462 break; 463 default: 464 u.u_error = ENXIO; 465 return; 466 } 467 if (callcount <= 0 || fcount <= 0) 468 u.u_error = ENXIO; 469 else while (--callcount >= 0) { 470 tcommand(dev, tmops[mtop.mt_op], fcount); 471 if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) && 472 ctmbuf.b_resid) { 473 u.u_error = EIO; 474 break; 475 } 476 if ((ctmbuf.b_flags&B_ERROR) || t_erreg&BOT) 477 break; 478 } 479 geterror(&ctmbuf); 480 return; 481 case MTIOCGET: 482 mtget.mt_dsreg = t_dsreg; 483 mtget.mt_erreg = t_erreg; 484 mtget.mt_resid = t_resid; 485 if (copyout((caddr_t)&mtget, addr, sizeof(mtget))) 486 u.u_error = EFAULT; 487 return; 488 default: 489 u.u_error = ENXIO; 490 } 491 } 492 493 #define DBSIZE 20 494 495 twall(start, num) 496 int start, num; 497 { 498 #if VAX==780 499 register struct uba_regs *up = (struct uba_regs *)PHYSUBA0; 500 #endif 501 int blk; 502 503 TMPHYS->tmcs = DCLR | GO; 504 #if VAX==780 505 up->uba_cr = ADINIT; 506 up->uba_cr = IFS|BRIE|USEFIE|SUEFIE; 507 while ((up->uba_cnfgr & UBIC) == 0) 508 ; 509 #endif 510 while (num > 0) { 511 blk = num > DBSIZE ? DBSIZE : num; 512 tmdwrite(start, blk); 513 start += blk; 514 num -= blk; 515 } 516 ((struct uba_regs *)PHYSUBA0)->uba_dpr[1] |= BNE; 517 } 518 519 tmdwrite(buf, num) 520 register buf, num; 521 { 522 register int *io, npf; 523 524 twait(); 525 ((struct uba_regs *)PHYSUBA0)->uba_dpr[1] |= BNE; 526 io = (int *)((struct uba_regs *)PHYSUBA0)->uba_map; 527 npf = num+1; 528 while (--npf != 0) 529 *io++ = (int)(buf++ | (1<<21) | MRV); 530 *io = 0; 531 TMPHYS->tmbc = -(num*NBPG); 532 TMPHYS->tmba = 0; 533 TMPHYS->tmcs = WCOM | GO | D800; 534 } 535 536 twait() 537 { 538 register s; 539 540 do 541 s = TMPHYS->tmcs; 542 while ((s & CUR) == 0); 543 } 544 545 rewind() 546 { 547 548 twait(); 549 TMPHYS->tmcs = REW | GO; 550 } 551 552 teof() 553 { 554 555 twait(); 556 TMPHYS->tmcs = WEOF | GO | D800; 557 } 558 #endif 559