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