1 /* ts.c 4.6 81/03/09 */ 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 int ts_ubinfo; 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_ubinfo = ubasetup(bp, 1); 253 ts.ts_cmd.c_loba = (u_short)ts_ubinfo; 254 ts.ts_cmd.c_hiba = (u_short)(ts_ubinfo >> 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 ubarelse(&ts_ubinfo); 344 case SCOM: 345 tstab.b_errcnt = 0; 346 tstab.b_actf = bp->av_forw; 347 bp->b_resid = ts.ts_sts.rbpcr; 348 iodone(bp); 349 break; 350 351 case SSFOR: 352 case SSREV: 353 ts_blkno = dbtofsb(bp->b_blkno); 354 break; 355 356 default: 357 printf("Unknown tape interrupt\n"); 358 errclass = 2; 359 break; 360 } 361 if (errclass > 1) { 362 while (bp = tstab.b_actf) { 363 bp->b_flags |= B_ERROR; 364 iodone(bp); 365 tstab.b_actf = bp->av_forw; 366 } 367 } 368 tsstart(); 369 } 370 371 tsread(dev) 372 { 373 tsphys(dev); 374 physio(tsstrategy, &rtsbuf, dev, B_READ, minphys); 375 } 376 377 tswrite(dev) 378 { 379 tsphys(dev); 380 physio(tsstrategy, &rtsbuf, dev, B_WRITE, minphys); 381 } 382 383 tsphys(dev) 384 { 385 register unit; 386 daddr_t a; 387 388 a = u.u_offset >> 9; 389 ts_blkno = dbtofsb(a); 390 ts_nxrec = dbtofsb(a)+1; 391 } 392 393 #define UBMAP (int *)0xf30800 394 395 int dtsinfo; 396 struct tsmesg dts; 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 = (int)&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 = (int)&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