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