spelling errors and add NEXFLT_BITS and UBASR_BITS
[unix-history] / usr / src / sys / vax / uba / ts.c
CommitLineData
b28deaf8 1/* ts.c 4.5 %G% */
9bad5ea5 2
66b4fb09 3#include "ts.h"
9bad5ea5
BJ
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"
e1b765e1 19#include "../h/vm.h"
9bad5ea5 20
9bad5ea5 21struct device {
f0a3ddbd
BJ
22 u_short tsdb;
23 u_short tssr;
9bad5ea5
BJ
24};
25
26struct buf tstab;
27struct buf rtsbuf;
28struct buf ctsbuf;
29
30#define INF 1000000000
31
f0a3ddbd 32u_short ts_uba;
b28deaf8 33int ts_ubinfo;
9bad5ea5
BJ
34char ts_flags;
35char ts_openf;
36daddr_t ts_blkno;
37daddr_t ts_nxrec;
38
39/* status message */
40struct sts {
f0a3ddbd 41 u_short s_sts;
e1b765e1
BJ
42 u_short len;
43 u_short rbpcr;
f0a3ddbd
BJ
44 u_short xs0;
45 u_short xs1;
46 u_short xs2;
47 u_short xs3;
9bad5ea5
BJ
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 */
57struct cmd {
f0a3ddbd
BJ
58 u_short c_cmd;
59 u_short c_loba;
60 u_short c_hiba;
61 u_short c_size;
9bad5ea5
BJ
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 */
84struct charac {
f0a3ddbd
BJ
85 u_short char_loba;
86 u_short char_hiba;
87 u_short char_size;
88 u_short char_mode;
9bad5ea5
BJ
89};
90
91/* All the packets, collected */
92struct 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
115tsopen(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);
f0a3ddbd 146 ts_uba = (u_short)((long)ubaddr + (((long)ubaddr >> 16) & 03));
9bad5ea5 147 ts.ts_char.char_loba = (int)&ubaddr->ts_sts;
f0a3ddbd 148 ts.ts_char.char_hiba = (u_short)((long)&ubaddr->ts_sts >> 16) & 03;
9bad5ea5
BJ
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;
f0a3ddbd 153 ts.ts_cmd.c_hiba = (u_short)((long)&ubaddr->ts_sts >> 16) & 03;
9bad5ea5
BJ
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
164tsclose(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
177tscommand(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
199tsstrategy(bp)
200register 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
234tsstart()
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;
b28deaf8
BJ
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;
9bad5ea5
BJ
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
284tsintr()
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++;
b28deaf8 343 ubarelse(&ts_ubinfo);
9bad5ea5
BJ
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
371tsread(dev)
372{
373 tsphys(dev);
374 physio(tsstrategy, &rtsbuf, dev, B_READ, minphys);
375}
376
377tswrite(dev)
378{
379 tsphys(dev);
380 physio(tsstrategy, &rtsbuf, dev, B_WRITE, minphys);
381}
382
383tsphys(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}
f0a3ddbd
BJ
392
393#define UBMAP (int *)0xf30800
394
395int dtsinfo;
e1b765e1 396struct tsmesg dts;
f0a3ddbd
BJ
397
398twall(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
421tsinit()
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;
e1b765e1 440 dts.ts_cmd.c_loba = (int)&tsm->ts_char;
f0a3ddbd
BJ
441 dts.ts_cmd.c_hiba = 0;
442 dts.ts_cmd.c_size = sizeof(dts.ts_char);
e1b765e1 443 dts.ts_char.char_loba = (int)&tsm->ts_sts;
f0a3ddbd
BJ
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
451teof()
452{
453
454 dtscommand(WTM);
455}
456
457rewind()
458{
459
460 dtscommand(REW);
461}
462
463dtscommand(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
473twait()
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}
9bad5ea5 484#endif