xref: /csrg-svn/sys/vax/uba/tm.c (revision 2043)
1 /*	tm.c	4.4	12/26/80	*/
2 
3 #include "tm.h"
4 #if NTM > 0
5 /*
6  * TM tape driver
7  */
8 
9 #include "../h/param.h"
10 #include "../h/buf.h"
11 #include "../h/dir.h"
12 #include "../h/conf.h"
13 #include "../h/user.h"
14 #include "../h/file.h"
15 #include "../h/map.h"
16 #include "../h/pte.h"
17 #include "../h/uba.h"
18 #include "../h/mtio.h"
19 #include "../h/ioctl.h"
20 #include "../h/vm.h"
21 
22 struct device {
23 	u_short	tmer;
24 	u_short	tmcs;
25 	short	tmbc;
26 	u_short tmba;
27 	short	tmdb;
28 	short	tmrd;
29 };
30 
31 #define	b_repcnt  b_bcount
32 #define	b_command b_resid
33 
34 struct	buf	tmtab;
35 struct	buf	ctmbuf;
36 struct	buf	rtmbuf;
37 
38 int	tm_ubinfo;
39 
40 /* bits in minor device */
41 #define	T_NOREWIND	04
42 #define	T_1600BPI	08
43 
44 #define	INF	(daddr_t)1000000L
45 
46 /*
47  * Really only handle one tape drive... if you have more than one,
48  * you can make all these arrays and change the obvious things, but
49  * it is not clear what happens when some drives are transferring while
50  * others rewind, so we don't pretend that this driver handles multiple
51  * tape drives.
52  */
53 char	t_openf;
54 daddr_t	t_blkno;
55 char	t_flags;
56 daddr_t	t_nxrec;
57 u_short	t_erreg;
58 u_short	t_dsreg;
59 short	t_resid;
60 
61 /* bits in tmcs */
62 #define	GO	01
63 #define	OFFL	0
64 #define	RCOM	02
65 #define	WCOM	04
66 #define	WEOF	06
67 #define	SFORW	010
68 #define	SREV	012
69 #define	WIRG	014
70 #define	REW	016
71 #define	IENABLE	0100
72 #define	CUR	0200
73 #define	NOP	IENABLE
74 #define	DCLR	010000
75 #define	D800	060000
76 #define	ERROR	0100000
77 
78 /* bits in tmer */
79 #define	TUR	1
80 #define	RWS	02
81 #define	WRL	04
82 #define	SDWN	010
83 #define	BOT	040
84 #define	SELR	0100
85 #define	NXM	0200
86 #define	TMBTE	0400
87 #define	RLE	01000
88 #define	EOT	02000
89 #define	BGL	04000
90 #define	PAE	010000
91 #define	CRE	020000
92 #define	EOF	040000
93 #define	ILC	0100000
94 
95 #define	HARD    (ILC|EOT)
96 #define	SOFT	(CRE|PAE|BGL|RLE|TMBTE|NXM)
97 
98 #define	SSEEK	1		/* seeking */
99 #define	SIO	2		/* doing seq i/o */
100 #define	SCOM	3		/* sending control command */
101 
102 #define	LASTIOW 1		/* last op was a write */
103 #define	WAITREW	2		/* someone is waiting for a rewind */
104 
105 tmopen(dev, flag)
106 	dev_t dev;
107 	int flag;
108 {
109 	register ds, unit;
110 
111 	tmtab.b_flags |= B_TAPE;
112 	unit = minor(dev)&03;
113 	if (unit >= NTM || t_openf) {
114 		u.u_error = ENXIO;		/* out of range or open */
115 		return;
116 	}
117 	tcommand(dev, NOP, 1);
118 	if ((t_erreg&SELR) == 0) {
119 		u.u_error = EIO;		/* offline */
120 		return;
121 	}
122 	t_openf = 1;
123 	if (t_erreg&RWS)
124 		tmwaitrws(dev);			/* wait for rewind complete */
125 	while (t_erreg&SDWN)
126 		tcommand(dev, NOP, 1);		/* await settle down */
127 	if ((t_erreg&TUR)==0 ||
128 	    ((flag&(FREAD|FWRITE)) == FWRITE && (t_erreg&WRL))) {
129 		TMADDR->tmcs = DCLR|GO;
130 		u.u_error = EIO;		/* offline or write protect */
131 	}
132 	if (u.u_error != 0) {
133 		t_openf = 0;
134 		return;
135 	}
136 	t_blkno = (daddr_t)0;
137 	t_nxrec = INF;
138 	t_flags = 0;
139 	t_openf = 1;
140 }
141 
142 tmwaitrws(dev)
143 	register dev;
144 {
145 
146 	spl5();
147 	for (;;) {
148 		if ((TMADDR->tmer&RWS) == 0) {
149 			spl0();		/* rewind complete */
150 			return;
151 		}
152 		t_flags |= WAITREW;
153 		sleep((caddr_t)&t_flags, PRIBIO);
154 	}
155 }
156 
157 tmclose(dev, flag)
158 	register dev_t dev;
159 	register flag;
160 {
161 
162 	if (flag == FWRITE || ((flag&FWRITE) && (t_flags&LASTIOW))) {
163 		tcommand(dev, WEOF, 1);
164 		tcommand(dev, WEOF, 1);
165 		tcommand(dev, SREV, 1);
166 	}
167 	if ((minor(dev)&T_NOREWIND) == 0)
168 		tcommand(dev, REW, 1);
169 	t_openf = 0;
170 }
171 
172 tcommand(dev, com, count)
173 	dev_t dev;
174 	int com, count;
175 {
176 	register struct buf *bp;
177 
178 	bp = &ctmbuf;
179 	(void) spl5();
180 	while (bp->b_flags&B_BUSY) {
181 		bp->b_flags |= B_WANTED;
182 		sleep((caddr_t)bp, PRIBIO);
183 	}
184 	bp->b_flags = B_BUSY|B_READ;
185 	(void) spl0();
186 	bp->b_dev = dev;
187 	bp->b_repcnt = -count;
188 	bp->b_command = com;
189 	bp->b_blkno = 0;
190 	tmstrategy(bp);
191 	iowait(bp);
192 	if (bp->b_flags&B_WANTED)
193 		wakeup((caddr_t)bp);
194 	bp->b_flags &= B_ERROR;
195 }
196 
197 tmstrategy(bp)
198 	register struct buf *bp;
199 {
200 	register daddr_t *p;
201 
202 	tmwaitrws(bp->b_dev);
203 	if (bp != &ctmbuf) {
204 		p = &t_nxrec;
205 		if (dbtofsb(bp->b_blkno) > *p) {
206 			bp->b_flags |= B_ERROR;
207 			bp->b_error = ENXIO;		/* past EOF */
208 			iodone(bp);
209 			return;
210 		} else if (dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) {
211 			bp->b_resid = bp->b_bcount;
212 			clrbuf(bp);			/* at EOF */
213 			iodone(bp);
214 			return;
215 		} else if ((bp->b_flags&B_READ) == 0)
216 			*p = dbtofsb(bp->b_blkno) + 1;	/* write sets EOF */
217 	}
218 	bp->av_forw = NULL;
219 	(void) spl5();
220 	if (tmtab.b_actf == NULL)
221 		tmtab.b_actf = bp;
222 	else
223 		tmtab.b_actl->av_forw = bp;
224 	tmtab.b_actl = bp;
225 	if (tmtab.b_active == 0)
226 		tmstart();
227 	(void) spl0();
228 }
229 
230 tmstart()
231 {
232 	register struct buf *bp;
233 	register cmd;
234 	register daddr_t blkno;
235 
236 loop:
237 	if ((bp = tmtab.b_actf) == 0)
238 		return;
239 	t_dsreg = TMADDR->tmcs;
240 	t_erreg = TMADDR->tmer;
241 	t_resid = TMADDR->tmbc;
242 	t_flags &= ~LASTIOW;
243 	if (t_openf < 0 || (TMADDR->tmcs&CUR) == 0) {
244 		/* t_openf = -1; ??? */
245 		bp->b_flags |= B_ERROR;		/* hard error'ed or !SELR */
246 		goto next;
247 	}
248 	cmd = IENABLE | GO;
249 	if ((minor(bp->b_dev) & T_1600BPI) == 0)
250 		cmd |= D800;
251 	if (bp == &ctmbuf) {
252 		if (bp->b_command == NOP)
253 			goto next;		/* just get status */
254 		else {
255 			cmd |= bp->b_command;
256 			tmtab.b_active = SCOM;
257 			if (bp->b_command == SFORW || bp->b_command == SREV)
258 				TMADDR->tmbc = bp->b_repcnt;
259 			TMADDR->tmcs = cmd;
260 			return;
261 		}
262 	}
263 	if ((blkno = t_blkno) == dbtofsb(bp->b_blkno)) {
264 		TMADDR->tmbc = -bp->b_bcount;
265 		if (tm_ubinfo == 0)
266 			tm_ubinfo = ubasetup(bp,1);
267 		if ((bp->b_flags&B_READ) == 0) {
268 			if (tmtab.b_errcnt)
269 				cmd |= WIRG;
270 			else
271 				cmd |= WCOM;
272 		} else
273 			cmd |= RCOM;
274 		cmd |= (tm_ubinfo >> 12) & 0x30;
275 		tmtab.b_active = SIO;
276 		TMADDR->tmba = tm_ubinfo;
277 		TMADDR->tmcs = cmd;
278 		return;
279 	}
280 	tmtab.b_active = SSEEK;
281 	if (blkno < dbtofsb(bp->b_blkno)) {
282 		cmd |= SFORW;
283 		TMADDR->tmbc = blkno - dbtofsb(bp->b_blkno);
284 	} else {
285 		cmd |= SREV;
286 		TMADDR->tmbc = dbtofsb(bp->b_blkno) - blkno;
287 	}
288 	TMADDR->tmcs = cmd;
289 	return;
290 
291 next:
292 	if (tm_ubinfo != 0) {
293 		ubafree(tm_ubinfo);
294 		tm_ubinfo = 0;
295 	}
296 	tmtab.b_actf = bp->av_forw;
297 	iodone(bp);
298 	goto loop;
299 }
300 
301 tmintr()
302 {
303 	register struct buf *bp;
304 	register state;
305 
306 	if (t_flags&WAITREW && (TMADDR->tmer&RWS) == 0) {
307 		t_flags &= ~WAITREW;
308 		wakeup((caddr_t)&t_flags);
309 	}
310 	if ((bp = tmtab.b_actf) == NULL)
311 		return;
312 	t_dsreg = TMADDR->tmcs;
313 	t_erreg = TMADDR->tmer;
314 	t_resid = TMADDR->tmbc;
315 	if ((bp->b_flags & B_READ) == 0)
316 		t_flags |= LASTIOW;
317 	state = tmtab.b_active;
318 	tmtab.b_active = 0;
319 	if (TMADDR->tmcs&ERROR) {
320 		while(TMADDR->tmer & SDWN)
321 			;			/* await settle down */
322 		if (TMADDR->tmer&EOF) {
323 			tmseteof(bp);	/* set blkno and nxrec */
324 			state = SCOM;
325 			TMADDR->tmbc = -bp->b_bcount;
326 			goto errout;
327 		}
328 		if ((bp->b_flags&B_READ) && (TMADDR->tmer&(HARD|SOFT)) == RLE)
329 			goto out;
330 		if ((TMADDR->tmer&HARD)==0 && state==SIO) {
331 			if (++tmtab.b_errcnt < 7) {
332 				if((TMADDR->tmer&SOFT) == NXM)
333 					printf("TM UBA late error\n");
334 				else
335 					t_blkno += 2;		/* ???????? */
336 				if (tm_ubinfo) {
337 					ubafree(tm_ubinfo);
338 					tm_ubinfo = 0;
339 				}
340 				tmstart();
341 				return;
342 			}
343 		} else if (t_openf>0 && bp != &rtmbuf)
344 			t_openf = -1;
345 		deverror(bp, t_erreg, t_dsreg);
346 		bp->b_flags |= B_ERROR;
347 		state = SIO;
348 	}
349 out:
350 	switch (state) {
351 
352 	case SIO:
353 		t_blkno++;
354 		/* fall into ... */
355 
356 	case SCOM:
357 		if (bp == &ctmbuf) {
358 			switch (bp->b_command) {
359 			case SFORW:
360 				t_blkno -= bp->b_repcnt;
361 				break;
362 
363 			case SREV:
364 				t_blkno += bp->b_repcnt;
365 				break;
366 
367 			default:
368 				if (++bp->b_repcnt < 0) {
369 					tmstart();	/* continue */
370 					return;
371 				}
372 			}
373 		}
374 errout:
375 		tmtab.b_errcnt = 0;
376 		tmtab.b_actf = bp->av_forw;
377 		bp->b_resid = -TMADDR->tmbc;
378 		if (tm_ubinfo != 0) {
379 			ubafree(tm_ubinfo);
380 			tm_ubinfo = 0;
381 		}
382 		iodone(bp);
383 		break;
384 
385 	case SSEEK:
386 		t_blkno = dbtofsb(bp->b_blkno);
387 		break;
388 
389 	default:
390 		return;
391 	}
392 	tmstart();
393 }
394 
395 tmseteof(bp)
396 	register struct buf *bp;
397 {
398 
399 	if (bp == &ctmbuf) {
400 		if (t_blkno > dbtofsb(bp->b_blkno)) {
401 			/* reversing */
402 			t_nxrec = dbtofsb(bp->b_blkno) - TMADDR->tmbc;
403 			t_blkno = t_nxrec;
404 		} else {
405 			/* spacing forward */
406 			t_blkno = dbtofsb(bp->b_blkno) + TMADDR->tmbc;
407 			t_nxrec = t_blkno - 1;
408 		}
409 		return;
410 	}
411 	/* eof on read */
412 	t_nxrec = dbtofsb(bp->b_blkno);
413 }
414 
415 tmread(dev)
416 {
417 
418 	tmphys(dev);
419 	physio(tmstrategy, &rtmbuf, dev, B_READ, minphys);
420 }
421 
422 tmwrite(dev)
423 {
424 
425 	tmphys(dev);
426 	physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys);
427 }
428 
429 tmphys(dev)
430 {
431 	register daddr_t a;
432 
433 	a = dbtofsb(u.u_offset >> 9);
434 	t_blkno = a;
435 	t_nxrec = a + 1;
436 }
437 
438 /*ARGSUSED*/
439 tmioctl(dev, cmd, addr, flag)
440 	caddr_t addr;
441 	dev_t dev;
442 {
443 	register callcount;
444 	int fcount;
445 	struct mtop mtop;
446 	struct mtget mtget;
447 	/* we depend of the values and order of the MT codes here */
448 	static tmops[] = {WEOF, SFORW, SREV, SFORW, SREV, REW, OFFL};
449 
450 	switch(cmd) {
451 		case MTIOCTOP:	/* tape operation */
452 		if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) {
453 			u.u_error = EFAULT;
454 			return;
455 		}
456 		switch(mtop.mt_op) {
457 		case MTWEOF: case MTFSF: case MTBSF:
458 			callcount = mtop.mt_count;
459 			fcount = INF;
460 			break;
461 		case MTFSR: case MTBSR:
462 			callcount = 1;
463 			fcount = mtop.mt_count;
464 			break;
465 		case MTREW: case MTOFFL:
466 			callcount = 1;
467 			fcount = 1;
468 			break;
469 		default:
470 			u.u_error = ENXIO;
471 			return;
472 		}
473 		if (callcount <= 0 || fcount <= 0)
474 			u.u_error = ENXIO;
475 		else while (--callcount >= 0) {
476 			tcommand(dev, tmops[mtop.mt_op], fcount);
477 			if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) &&
478 			    ctmbuf.b_resid) {
479 				u.u_error = EIO;
480 				break;
481 			}
482 			if ((ctmbuf.b_flags&B_ERROR) || t_erreg&BOT)
483 				break;
484 		}
485 		geterror(&ctmbuf);
486 		return;
487 	case MTIOCGET:
488 		mtget.mt_dsreg = t_dsreg;
489 		mtget.mt_erreg = t_erreg;
490 		mtget.mt_resid = t_resid;
491 		if (copyout((caddr_t)&mtget, addr, sizeof(mtget)))
492 			u.u_error = EFAULT;
493 		return;
494 	default:
495 		u.u_error = ENXIO;
496 	}
497 }
498 
499 #define	DBSIZE	20
500 
501 twall(start, num)
502 	int start, num;
503 {
504 #if VAX==780
505 	register struct uba_regs *up = (struct uba_regs *)PHYSUBA0;
506 #endif
507 	int blk;
508 
509 	TMPHYS->tmcs = DCLR | GO;
510 #if VAX==780
511 	up->uba_cr = ADINIT;
512 	up->uba_cr = IFS|BRIE|USEFIE|SUEFIE;
513 	while ((up->uba_cnfgr & UBIC) == 0)
514 		;
515 #endif
516 	while (num > 0) {
517 		blk = num > DBSIZE ? DBSIZE : num;
518 		tmdwrite(start, blk);
519 		start += blk;
520 		num -= blk;
521 	}
522 	((struct uba_regs *)PHYSUBA0)->uba_dpr[1] |= BNE;
523 }
524 
525 tmdwrite(buf, num)
526 register buf, num;
527 {
528 	register int *io, npf;
529 
530 	twait();
531 	((struct uba_regs *)PHYSUBA0)->uba_dpr[1] |= BNE;
532 	io = (int *)((struct uba_regs *)PHYSUBA0)->uba_map;
533 	npf = num+1;
534 	while (--npf != 0)
535 		 *io++ = (int)(buf++ | (1<<21) | MRV);
536 	*io = 0;
537 	TMPHYS->tmbc = -(num*NBPG);
538 	TMPHYS->tmba = 0;
539 	TMPHYS->tmcs = WCOM | GO | D800;
540 }
541 
542 twait()
543 {
544 	register s;
545 
546 	do
547 		s = TMPHYS->tmcs;
548 	while ((s & CUR) == 0);
549 }
550 
551 rewind()
552 {
553 
554 	twait();
555 	TMPHYS->tmcs = REW | GO;
556 }
557 
558 teof()
559 {
560 
561 	twait();
562 	TMPHYS->tmcs = WEOF | GO | D800;
563 }
564 #endif
565