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