xref: /csrg-svn/sys/vax/uba/tm.c (revision 2054)
1 /*	tm.c	4.5	12/30/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 	int s;
236 
237 loop:
238 	if ((bp = tmtab.b_actf) == 0)
239 		return;
240 	t_dsreg = TMADDR->tmcs;
241 	t_erreg = TMADDR->tmer;
242 	t_resid = TMADDR->tmbc;
243 	t_flags &= ~LASTIOW;
244 	if (t_openf < 0 || (TMADDR->tmcs&CUR) == 0) {
245 		/* t_openf = -1; ??? */
246 		bp->b_flags |= B_ERROR;		/* hard error'ed or !SELR */
247 		goto next;
248 	}
249 	cmd = IENABLE | GO;
250 	if ((minor(bp->b_dev) & T_1600BPI) == 0)
251 		cmd |= D800;
252 	if (bp == &ctmbuf) {
253 		if (bp->b_command == NOP)
254 			goto next;		/* just get status */
255 		else {
256 			cmd |= bp->b_command;
257 			tmtab.b_active = SCOM;
258 			if (bp->b_command == SFORW || bp->b_command == SREV)
259 				TMADDR->tmbc = bp->b_repcnt;
260 			TMADDR->tmcs = cmd;
261 			return;
262 		}
263 	}
264 	if ((blkno = t_blkno) == dbtofsb(bp->b_blkno)) {
265 		TMADDR->tmbc = -bp->b_bcount;
266 		s = spl6();
267 		if (tm_ubinfo == 0)
268 			tm_ubinfo = ubasetup(bp,1);
269 		splx(s);
270 		if ((bp->b_flags&B_READ) == 0) {
271 			if (tmtab.b_errcnt)
272 				cmd |= WIRG;
273 			else
274 				cmd |= WCOM;
275 		} else
276 			cmd |= RCOM;
277 		cmd |= (tm_ubinfo >> 12) & 0x30;
278 		tmtab.b_active = SIO;
279 		TMADDR->tmba = tm_ubinfo;
280 		TMADDR->tmcs = cmd;
281 		return;
282 	}
283 	tmtab.b_active = SSEEK;
284 	if (blkno < dbtofsb(bp->b_blkno)) {
285 		cmd |= SFORW;
286 		TMADDR->tmbc = blkno - dbtofsb(bp->b_blkno);
287 	} else {
288 		cmd |= SREV;
289 		TMADDR->tmbc = dbtofsb(bp->b_blkno) - blkno;
290 	}
291 	TMADDR->tmcs = cmd;
292 	return;
293 
294 next:
295 	ubarelse(&tm_ubinfo);
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 				ubarelse(&tm_ubinfo);
337 				tmstart();
338 				return;
339 			}
340 		} else if (t_openf>0 && bp != &rtmbuf)
341 			t_openf = -1;
342 		deverror(bp, t_erreg, t_dsreg);
343 		bp->b_flags |= B_ERROR;
344 		state = SIO;
345 	}
346 out:
347 	switch (state) {
348 
349 	case SIO:
350 		t_blkno++;
351 		/* fall into ... */
352 
353 	case SCOM:
354 		if (bp == &ctmbuf) {
355 			switch (bp->b_command) {
356 			case SFORW:
357 				t_blkno -= bp->b_repcnt;
358 				break;
359 
360 			case SREV:
361 				t_blkno += bp->b_repcnt;
362 				break;
363 
364 			default:
365 				if (++bp->b_repcnt < 0) {
366 					tmstart();	/* continue */
367 					return;
368 				}
369 			}
370 		}
371 errout:
372 		tmtab.b_errcnt = 0;
373 		tmtab.b_actf = bp->av_forw;
374 		bp->b_resid = -TMADDR->tmbc;
375 		ubarelse(&tm_ubinfo);
376 		iodone(bp);
377 		break;
378 
379 	case SSEEK:
380 		t_blkno = dbtofsb(bp->b_blkno);
381 		break;
382 
383 	default:
384 		return;
385 	}
386 	tmstart();
387 }
388 
389 tmseteof(bp)
390 	register struct buf *bp;
391 {
392 
393 	if (bp == &ctmbuf) {
394 		if (t_blkno > dbtofsb(bp->b_blkno)) {
395 			/* reversing */
396 			t_nxrec = dbtofsb(bp->b_blkno) - TMADDR->tmbc;
397 			t_blkno = t_nxrec;
398 		} else {
399 			/* spacing forward */
400 			t_blkno = dbtofsb(bp->b_blkno) + TMADDR->tmbc;
401 			t_nxrec = t_blkno - 1;
402 		}
403 		return;
404 	}
405 	/* eof on read */
406 	t_nxrec = dbtofsb(bp->b_blkno);
407 }
408 
409 tmread(dev)
410 {
411 
412 	tmphys(dev);
413 	physio(tmstrategy, &rtmbuf, dev, B_READ, minphys);
414 }
415 
416 tmwrite(dev)
417 {
418 
419 	tmphys(dev);
420 	physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys);
421 }
422 
423 tmphys(dev)
424 {
425 	register daddr_t a;
426 
427 	a = dbtofsb(u.u_offset >> 9);
428 	t_blkno = a;
429 	t_nxrec = a + 1;
430 }
431 
432 /*ARGSUSED*/
433 tmioctl(dev, cmd, addr, flag)
434 	caddr_t addr;
435 	dev_t dev;
436 {
437 	register callcount;
438 	int fcount;
439 	struct mtop mtop;
440 	struct mtget mtget;
441 	/* we depend of the values and order of the MT codes here */
442 	static tmops[] = {WEOF, SFORW, SREV, SFORW, SREV, REW, OFFL};
443 
444 	switch(cmd) {
445 		case MTIOCTOP:	/* tape operation */
446 		if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) {
447 			u.u_error = EFAULT;
448 			return;
449 		}
450 		switch(mtop.mt_op) {
451 		case MTWEOF: case MTFSF: case MTBSF:
452 			callcount = mtop.mt_count;
453 			fcount = INF;
454 			break;
455 		case MTFSR: case MTBSR:
456 			callcount = 1;
457 			fcount = mtop.mt_count;
458 			break;
459 		case MTREW: case MTOFFL:
460 			callcount = 1;
461 			fcount = 1;
462 			break;
463 		default:
464 			u.u_error = ENXIO;
465 			return;
466 		}
467 		if (callcount <= 0 || fcount <= 0)
468 			u.u_error = ENXIO;
469 		else while (--callcount >= 0) {
470 			tcommand(dev, tmops[mtop.mt_op], fcount);
471 			if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) &&
472 			    ctmbuf.b_resid) {
473 				u.u_error = EIO;
474 				break;
475 			}
476 			if ((ctmbuf.b_flags&B_ERROR) || t_erreg&BOT)
477 				break;
478 		}
479 		geterror(&ctmbuf);
480 		return;
481 	case MTIOCGET:
482 		mtget.mt_dsreg = t_dsreg;
483 		mtget.mt_erreg = t_erreg;
484 		mtget.mt_resid = t_resid;
485 		if (copyout((caddr_t)&mtget, addr, sizeof(mtget)))
486 			u.u_error = EFAULT;
487 		return;
488 	default:
489 		u.u_error = ENXIO;
490 	}
491 }
492 
493 #define	DBSIZE	20
494 
495 twall(start, num)
496 	int start, num;
497 {
498 #if VAX==780
499 	register struct uba_regs *up = (struct uba_regs *)PHYSUBA0;
500 #endif
501 	int blk;
502 
503 	TMPHYS->tmcs = DCLR | GO;
504 #if VAX==780
505 	up->uba_cr = ADINIT;
506 	up->uba_cr = IFS|BRIE|USEFIE|SUEFIE;
507 	while ((up->uba_cnfgr & UBIC) == 0)
508 		;
509 #endif
510 	while (num > 0) {
511 		blk = num > DBSIZE ? DBSIZE : num;
512 		tmdwrite(start, blk);
513 		start += blk;
514 		num -= blk;
515 	}
516 	((struct uba_regs *)PHYSUBA0)->uba_dpr[1] |= BNE;
517 }
518 
519 tmdwrite(buf, num)
520 register buf, num;
521 {
522 	register int *io, npf;
523 
524 	twait();
525 	((struct uba_regs *)PHYSUBA0)->uba_dpr[1] |= BNE;
526 	io = (int *)((struct uba_regs *)PHYSUBA0)->uba_map;
527 	npf = num+1;
528 	while (--npf != 0)
529 		 *io++ = (int)(buf++ | (1<<21) | MRV);
530 	*io = 0;
531 	TMPHYS->tmbc = -(num*NBPG);
532 	TMPHYS->tmba = 0;
533 	TMPHYS->tmcs = WCOM | GO | D800;
534 }
535 
536 twait()
537 {
538 	register s;
539 
540 	do
541 		s = TMPHYS->tmcs;
542 	while ((s & CUR) == 0);
543 }
544 
545 rewind()
546 {
547 
548 	twait();
549 	TMPHYS->tmcs = REW | GO;
550 }
551 
552 teof()
553 {
554 
555 	twait();
556 	TMPHYS->tmcs = WEOF | GO | D800;
557 }
558 #endif
559