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