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