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