xref: /csrg-svn/sys/vax/uba/tm.c (revision 1919)
1 /*	tm.c	4.1	12/17/80	*/
2 
3 #include "../conf/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 		tcommand(dev, NOP, 1);
149 		if ((t_erreg&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 	tcommand(bp->b_dev, NOP, 1);
204 	if (t_erreg&RWS)
205 		tmwaitrws(bp->b_dev);
206 	if (bp != &ctmbuf) {
207 		p = &t_nxrec;
208 		if (dbtofsb(bp->b_blkno) > *p) {
209 			bp->b_flags |= B_ERROR;
210 			bp->b_error = ENXIO;		/* past EOF */
211 			iodone(bp);
212 			return;
213 		} else if (dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) {
214 			bp->b_resid = bp->b_bcount;
215 			clrbuf(bp);			/* at EOF */
216 			iodone(bp);
217 			return;
218 		} else if ((bp->b_flags&B_READ) == 0)
219 			*p = dbtofsb(bp->b_blkno) + 1;	/* write sets EOF */
220 	}
221 	bp->av_forw = NULL;
222 	(void) spl5();
223 	if (tmtab.b_actf == NULL)
224 		tmtab.b_actf = bp;
225 	else
226 		tmtab.b_actl->av_forw = bp;
227 	tmtab.b_actl = bp;
228 	if (tmtab.b_active == 0)
229 		tmstart();
230 	(void) spl0();
231 }
232 
233 tmstart()
234 {
235 	register struct buf *bp;
236 	register cmd;
237 	register daddr_t blkno;
238 
239 loop:
240 	if ((bp = tmtab.b_actf) == 0)
241 		return;
242 	t_dsreg = TMADDR->tmcs;
243 	t_erreg = TMADDR->tmer;
244 	t_resid = TMADDR->tmbc;
245 	t_flags &= ~LASTIOW;
246 	if (t_openf < 0 || (TMADDR->tmcs&CUR) == 0) {
247 		/* t_openf = -1; ??? */
248 		bp->b_flags |= B_ERROR;		/* hard error'ed or !SELR */
249 		goto next;
250 	}
251 	cmd = IENABLE | GO;
252 	if ((minor(bp->b_dev) & T_1600BPI) == 0)
253 		cmd |= D800;
254 	if (bp == &ctmbuf) {
255 		if (bp->b_command == NOP)
256 			goto next;		/* just get status */
257 		else {
258 			cmd |= bp->b_command;
259 			tmtab.b_active = SCOM;
260 			if (bp->b_command == SFORW || bp->b_command == SREV)
261 				TMADDR->tmbc = bp->b_repcnt;
262 			TMADDR->tmcs = cmd;
263 			return;
264 		}
265 	}
266 	if ((blkno = t_blkno) == dbtofsb(bp->b_blkno)) {
267 		TMADDR->tmbc = -bp->b_bcount;
268 		if (tm_ubinfo == 0)
269 			tm_ubinfo = ubasetup(bp,1);
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 	if (tm_ubinfo != 0) {
296 		ubafree(tm_ubinfo);
297 		tm_ubinfo = 0;
298 	}
299 	tmtab.b_actf = bp->av_forw;
300 	iodone(bp);
301 	goto loop;
302 }
303 
304 tmintr()
305 {
306 	register struct buf *bp;
307 	register state;
308 
309 	if (t_flags&WAITREW && (TMADDR->tmer&RWS) == 0) {
310 		t_flags &= ~WAITREW;
311 		wakeup((caddr_t)&t_flags);
312 	}
313 	if ((bp = tmtab.b_actf) == NULL)
314 		return;
315 	t_dsreg = TMADDR->tmcs;
316 	TMADDR->tmcs = IENABLE;
317 	t_erreg = TMADDR->tmer;
318 	t_resid = TMADDR->tmbc;
319 	if ((bp->b_flags & B_READ) == 0)
320 		t_flags |= LASTIOW;
321 	state = tmtab.b_active;
322 	tmtab.b_active = 0;
323 	if (TMADDR->tmcs&ERROR) {
324 		while(TMADDR->tmer & SDWN)
325 			;			/* await settle down */
326 		if (TMADDR->tmer&EOF) {
327 			tmseteof(bp);	/* set blkno and nxrec */
328 			state = SCOM;
329 			TMADDR->tmbc = -bp->b_bcount;
330 			goto errout;
331 		}
332 		if ((bp->b_flags&B_READ) && (TMADDR->tmer&(HARD|SOFT)) == RLE)
333 			goto out;
334 		if ((TMADDR->tmer&HARD)==0 && state==SIO) {
335 			if (++tmtab.b_errcnt < 3) {
336 				if((TMADDR->tmer&SOFT) == NXM)
337 					printf("TM UBA late error\n");
338 				else
339 					t_blkno++;
340 				if (tm_ubinfo) {
341 					ubafree(tm_ubinfo);
342 					tm_ubinfo = 0;
343 				}
344 				tmstart();
345 				return;
346 			}
347 		} else if (t_openf>0 && bp != &rtmbuf)
348 			t_openf = -1;
349 		deverror(bp, t_erreg, 0);
350 		bp->b_flags |= B_ERROR;
351 		state = SIO;
352 	}
353 out:
354 	switch (state) {
355 
356 	case SIO:
357 		t_blkno++;
358 		/* fall into ... */
359 
360 	case SCOM:
361 		if (bp == &ctmbuf) {
362 			switch (bp->b_command) {
363 			case SFORW:
364 				t_blkno -= bp->b_repcnt;
365 				break;
366 
367 			case SREV:
368 				t_blkno += bp->b_repcnt;
369 				break;
370 
371 			default:
372 				if (++bp->b_repcnt < 0) {
373 					tmstart();	/* continue */
374 					return;
375 				}
376 			}
377 		}
378 errout:
379 		tmtab.b_errcnt = 0;
380 		tmtab.b_actf = bp->av_forw;
381 		bp->b_resid = -TMADDR->tmbc;
382 		if (tm_ubinfo != 0) {
383 			ubafree(tm_ubinfo);
384 			tm_ubinfo = 0;
385 		}
386 		iodone(bp);
387 		break;
388 
389 	case SSEEK:
390 		t_blkno = dbtofsb(bp->b_blkno);
391 		break;
392 
393 	default:
394 		return;
395 	}
396 	tmstart();
397 }
398 
399 tmseteof(bp)
400 	register struct buf *bp;
401 {
402 
403 	if (bp == &ctmbuf) {
404 		if (t_blkno > dbtofsb(bp->b_blkno)) {
405 			/* reversing */
406 			t_nxrec = dbtofsb(bp->b_blkno) - TMADDR->tmbc;
407 			t_blkno = t_nxrec;
408 		} else {
409 			/* spacing forward */
410 			t_blkno = dbtofsb(bp->b_blkno) + TMADDR->tmbc;
411 			t_nxrec = t_blkno - 1;
412 		}
413 		return;
414 	}
415 	/* eof on read */
416 	t_nxrec = dbtofsb(bp->b_blkno);
417 }
418 
419 tmread(dev)
420 {
421 
422 	tmphys(dev);
423 	physio(tmstrategy, &rtmbuf, dev, B_READ, minphys);
424 }
425 
426 tmwrite(dev)
427 {
428 
429 	tmphys(dev);
430 	physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys);
431 }
432 
433 tmphys(dev)
434 {
435 	register daddr_t a;
436 
437 	a = dbtofsb(u.u_offset >> 9);
438 	t_blkno = a;
439 	t_nxrec = a + 1;
440 }
441 
442 /*ARGSUSED*/
443 tmioctl(dev, cmd, addr, flag)
444 	caddr_t addr;
445 	dev_t dev;
446 {
447 	register callcount;
448 	int fcount;
449 	struct mtop mtop;
450 	struct mtget mtget;
451 	/* we depend of the values and order of the MT codes here */
452 	static tmops[] = {WEOF, SFORW, SREV, SFORW, SREV, REW, OFFL};
453 
454 	switch(cmd) {
455 		case MTIOCTOP:	/* tape operation */
456 		if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) {
457 			u.u_error = EFAULT;
458 			return;
459 		}
460 		switch(mtop.mt_op) {
461 		case MTWEOF: case MTFSF: case MTBSF:
462 			callcount = mtop.mt_count;
463 			fcount = INF;
464 			break;
465 		case MTFSR: case MTBSR:
466 			callcount = 1;
467 			fcount = mtop.mt_count;
468 			break;
469 		case MTREW: case MTOFFL:
470 			callcount = 1;
471 			fcount = 1;
472 			break;
473 		default:
474 			u.u_error = ENXIO;
475 			return;
476 		}
477 		if (callcount <= 0 || fcount <= 0)
478 			u.u_error = ENXIO;
479 		else while (--callcount >= 0) {
480 			tcommand(dev, tmops[mtop.mt_op], fcount);
481 			if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) &&
482 			    ctmbuf.b_resid) {
483 				u.u_error = EIO;
484 				break;
485 			}
486 			if ((ctmbuf.b_flags&B_ERROR) || t_erreg&BOT)
487 				break;
488 		}
489 		geterror(&ctmbuf);
490 		return;
491 	case MTIOCGET:
492 		mtget.mt_dsreg = t_dsreg;
493 		mtget.mt_erreg = t_erreg;
494 		mtget.mt_resid = t_resid;
495 		if (copyout((caddr_t)&mtget, addr, sizeof(mtget)))
496 			u.u_error = EFAULT;
497 		return;
498 	default:
499 		u.u_error = ENXIO;
500 	}
501 }
502 
503 #define	DBSIZE	20
504 
505 twall(start, num)
506 	int start, num;
507 {
508 #if VAX==780
509 	register struct uba_regs *up = (struct uba_regs *)PHYSUBA0;
510 #endif
511 	int blk;
512 
513 	TMPHYS->tmcs = DCLR | GO;
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 	while (num > 0) {
521 		blk = num > DBSIZE ? DBSIZE : num;
522 		tmdwrite(start, blk);
523 		start += blk;
524 		num -= blk;
525 	}
526 }
527 
528 tmdwrite(buf, num)
529 register buf, num;
530 {
531 	register int *io, npf;
532 	tmwait();
533 	/* Flush buffered data path 0 */
534 	((struct uba_regs *)PHYSUBA0)->uba_dpr[1] = 0;
535 	((struct uba_regs *)PHYSUBA0)->uba_dpr[1] = BNE;
536 	/* Map unibus address 0 to section of interest */
537 	io = (int *)((struct uba_regs *)PHYSUBA0)->uba_map;
538 	npf = num+1;
539 	while(--npf != 0)
540 		 *io++ = (int)(buf++ | (1<<21) | MRV);
541 	*io = 0;
542 	TMPHYS->tmbc = -(num*NBPG);
543 	TMPHYS->tmba = 0;
544 	TMPHYS->tmcs = WCOM | GO | D800;
545 }
546 
547 tmwait()
548 {
549 	register short s;
550 
551 	do
552 		s = TMPHYS->tmcs;
553 	while ((s & CUR) == 0);
554 }
555 
556 tmrewind()
557 {
558 
559 	tmwait();
560 	TMPHYS->tmcs = REW | GO;
561 }
562 
563 tmeof()
564 {
565 
566 	tmwait();
567 	TMPHYS->tmcs = WEOF | GO | D800;
568 }
569 #endif
570