xref: /csrg-svn/sys/vax/mba/mt.c (revision 5437)
1 /*	mt.c	4.2	82/01/17	*/
2 
3 #include "mu.h"
4 #if NMT > 0
5 /*
6  * TM78/TU78 tape driver
7  *
8  *	Behavior in complex error situations is uncertain...
9  *
10  * TODO:
11  *	test error recovery
12  *	add odd byte count kludge from VMS driver
13  *	write dump routine
14  */
15 #include "../h/param.h"
16 #include "../h/systm.h"
17 #include "../h/buf.h"
18 #include "../h/conf.h"
19 #include "../h/dir.h"
20 #include "../h/file.h"
21 #include "../h/user.h"
22 #include "../h/map.h"
23 #include "../h/pte.h"
24 #include "../h/mbareg.h"
25 #include "../h/mbavar.h"
26 #include "../h/mtio.h"
27 #include "../h/ioctl.h"
28 #include "../h/cmap.h"
29 #include "../h/cpu.h"
30 
31 #include "../h/mtreg.h"
32 
33 struct	buf	rmtbuf[NMT];
34 struct	buf	cmtbuf[NMT];
35 
36 short	mttypes[] =
37 	{ MBDT_TU78, 0 };
38 struct	mba_device *mtinfo[NMT];
39 int	mtattach(), mtslave(), mtustart(), mtstart(), mtndtint(), mtdtint();
40 struct	mba_driver mtdriver =
41     { mtattach, mtslave, mtustart, mtstart, mtdtint, mtndtint,
42       mttypes, "mt", "mu", mtinfo };
43 
44 #define MASKREG(r)	((r) & 0xffff)
45 
46 /* bits in minor device */
47 #define	MUUNIT(dev)	(minor(dev)&03)
48 #define	H_NOREWIND	04
49 #define	H_6250BPI	08
50 
51 #define MTUNIT(dev)	(mutomt[MUUNIT(dev)])
52 
53 #define	INF	(daddr_t)1000000L	/* a block number that wont exist */
54 
55 struct	mu_softc {
56 	char	sc_openf;
57 	char	sc_flags;
58 	daddr_t	sc_blkno;
59 	daddr_t	sc_nxrec;
60 	u_short	sc_erreg;
61 	u_short	sc_dsreg;
62 	short	sc_resid;
63 	short	sc_dens;
64 	struct	mba_device *sc_mi;
65 	int	sc_slave;
66 } mu_softc[NMU];
67 short	mutomt[NMU];
68 
69 /*
70  * Bits for sc_flags.
71  */
72 #define	H_WRITTEN 1	/* last operation was a write */
73 
74 char	mtds_bits[] = MTDS_BITS;
75 
76 /*ARGSUSED*/
77 mtattach(mi)
78 	struct mba_device *mi;
79 {
80 
81 }
82 
83 mtslave(mi, ms)
84 	struct mba_device *mi;
85 	struct mba_slave *ms;
86 {
87 	register struct mu_softc *sc = &mu_softc[ms->ms_unit];
88 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
89 	int s = spl7(), rtn = 0;
90 
91 	mtaddr->mtas = -1;
92 	mtaddr->mtncs[ms->ms_slave] = MT_SENSE|MT_GO;
93 	while (mtaddr->mtas == 0)
94 		;
95 	if ((mtaddr->mtner & MTER_INTCODE) == MTER_DONE &&
96 	    (mtaddr->mtds & MTDS_PRES)) {
97 		sc->sc_mi = mi;
98 		sc->sc_slave = ms->ms_slave;
99 		mutomt[ms->ms_unit] = mi->mi_unit;
100 		rtn = 1;
101 	}
102 	mtaddr->mtas = mtaddr->mtas;
103 	splx(s);
104 	return (rtn);
105 }
106 
107 mtopen(dev, flag)
108 	dev_t dev;
109 	int flag;
110 {
111 	register int muunit;
112 	register struct mba_device *mi;
113 	register struct mu_softc *sc;
114 	int olddens, dens;
115 
116 	muunit = MUUNIT(dev);
117 	if (muunit >= NMU || (sc = &mu_softc[muunit])->sc_openf ||
118 	    (mi = mtinfo[MTUNIT(dev)]) == 0 || mi->mi_alive == 0) {
119 		u.u_error = ENXIO;
120 		return;
121 	}
122 	olddens = sc->sc_dens;
123 	dens = sc->sc_dens = (minor(dev)&H_6250BPI) ? MT_GCR : 0;
124 	mtcommand(dev, MT_SENSE, 1);
125 	sc->sc_dens = olddens;
126 	if ((sc->sc_dsreg & MTDS_ONL) == 0) {
127 		uprintf("mu%d: not online\n", muunit);
128 		u.u_error = EIO;
129 		return;
130 	}
131 	if ((flag&FWRITE) && (sc->sc_dsreg&MTDS_FPT)) {
132 		uprintf("mu%d: no write ring\n", muunit);
133 		u.u_error = EIO;
134 		return;
135 	}
136 	if ((sc->sc_dsreg & MTDS_BOT) == 0 && (flag&FWRITE) &&
137 	    dens != sc->sc_dens) {
138 		uprintf("mu%d: can't change density in mid-tape\n", muunit);
139 		u.u_error = EIO;
140 		return;
141 	}
142 	sc->sc_openf = 1;
143 	sc->sc_blkno = (daddr_t)0;
144 	sc->sc_nxrec = INF;
145 	sc->sc_flags = 0;
146 	sc->sc_dens = dens;
147 }
148 
149 mtclose(dev, flag)
150 	register dev_t dev;
151 	register flag;
152 {
153 	register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
154 
155 	if (flag == FWRITE || ((flag&FWRITE) && (sc->sc_flags&H_WRITTEN)))
156 		mtcommand(dev, MT_CLS|sc->sc_dens, 1);
157 	if ((minor(dev)&H_NOREWIND) == 0)
158 		mtcommand(dev, MT_REW, 0);
159 	sc->sc_openf = 0;
160 }
161 
162 mtcommand(dev, com, count)
163 	dev_t dev;
164 	int com, count;
165 {
166 	register struct buf *bp;
167 	register int s;
168 
169 	bp = &cmtbuf[MTUNIT(dev)];
170 	s = spl5();
171 	while (bp->b_flags&B_BUSY) {
172 		if(bp->b_repcnt == 0 && (bp->b_flags&B_DONE))
173 			break;
174 		bp->b_flags |= B_WANTED;
175 		sleep((caddr_t)bp, PRIBIO);
176 	}
177 	bp->b_flags = B_BUSY|B_READ;
178 	splx(s);
179 	bp->b_dev = dev;
180 	bp->b_command = com;
181 	bp->b_repcnt = count;
182 	bp->b_blkno = 0;
183 	mtstrategy(bp);
184 	if (count == 0)
185 		return;
186 	iowait(bp);
187 	if (bp->b_flags&B_WANTED)
188 		wakeup((caddr_t)bp);
189 	bp->b_flags &= B_ERROR;
190 }
191 
192 mtstrategy(bp)
193 	register struct buf *bp;
194 {
195 	register struct mba_device *mi = mtinfo[MTUNIT(bp->b_dev)];
196 	register struct buf *dp;
197 	register int s;
198 
199 	bp->av_forw = NULL;
200 	dp = &mi->mi_tab;
201 	s = spl5();
202 	if (dp->b_actf == NULL)
203 		dp->b_actf = bp;
204 	else
205 		dp->b_actl->av_forw = bp;
206 	dp->b_actl = bp;
207 	if (dp->b_active == 0)
208 		mbustart(mi);
209 	splx(s);
210 }
211 
212 mtustart(mi)
213 	register struct mba_device *mi;
214 {
215 	register struct mtdevice *mtaddr =
216 	    (struct mtdevice *)mi->mi_drv;
217 	register struct buf *bp = mi->mi_tab.b_actf;
218 	register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
219 	daddr_t blkno;
220 
221 	sc->sc_flags &= ~H_WRITTEN;
222 	if (sc->sc_openf < 0) {
223 		bp->b_flags |= B_ERROR;
224 		return (MBU_NEXT);
225 	}
226 	if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) {
227 		if (dbtofsb(bp->b_blkno) > sc->sc_nxrec) {
228 			bp->b_flags |= B_ERROR;
229 			bp->b_error = ENXIO;
230 			return (MBU_NEXT);
231 		}
232 		if (dbtofsb(bp->b_blkno) == sc->sc_nxrec &&
233 		    bp->b_flags&B_READ) {
234 			bp->b_resid = bp->b_bcount;
235 			clrbuf(bp);
236 			return (MBU_NEXT);
237 		}
238 		if ((bp->b_flags&B_READ)==0)
239 			sc->sc_nxrec = dbtofsb(bp->b_blkno) + 1;
240 	} else {
241 		mtaddr->mtncs[MUUNIT(bp->b_dev)] =
242 			(bp->b_repcnt<<8)|bp->b_command|MT_GO;
243 		return (MBU_STARTED);
244 	}
245 	if ((blkno = sc->sc_blkno) == dbtofsb(bp->b_blkno)) {
246 		if (mi->mi_tab.b_errcnt == 2) {
247 			mtaddr->mtca = MUUNIT(bp->b_dev);
248 		} else {
249 			mtaddr->mtbc = bp->b_bcount;
250 			mtaddr->mtca = (1<<2)|MUUNIT(bp->b_dev);
251 		}
252 		return (MBU_DODATA);
253 	}
254 	if (blkno < dbtofsb(bp->b_blkno))
255 		mtaddr->mtncs[MUUNIT(bp->b_dev)] =
256 		  (min(dbtofsb(bp->b_blkno) - blkno, 0377)<<8)| MT_SFORW|MT_GO;
257 	else
258 		mtaddr->mtncs[MUUNIT(bp->b_dev)] =
259 		  (min(blkno - dbtofsb(bp->b_blkno), 0377)<<8)| MT_SREV|MT_GO;
260 	return (MBU_STARTED);
261 }
262 
263 mtstart(mi)
264 	register struct mba_device *mi;
265 {
266 	register struct buf *bp = mi->mi_tab.b_actf;
267 	register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
268 
269 	if (bp->b_flags & B_READ)
270 		if (mi->mi_tab.b_errcnt == 2)
271 			return(MT_READREV|MT_GO);
272 		else
273 			return(MT_READ|MT_GO);
274 	else
275 		return(MT_WRITE|sc->sc_dens|MT_GO);
276 }
277 
278 mtdtint(mi, mbsr)
279 	register struct mba_device *mi;
280 	int mbsr;
281 {
282 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
283 	register struct buf *bp = mi->mi_tab.b_actf;
284 	register struct mu_softc *sc;
285 
286 	/* I'M NOT SURE IF THIS SHOULD ALWAYS BE THE CASE SO FOR NOW... */
287 	if ((mtaddr->mtca&3) != MUUNIT(bp->b_dev)) {
288 		printf("mt: wrong unit!\n");
289 		mtaddr->mtca = MUUNIT(bp->b_dev);
290 	}
291 	sc = &mu_softc[MUUNIT(bp->b_dev)];
292 	sc->sc_erreg = mtaddr->mter;
293 	if((bp->b_flags & B_READ) == 0)
294 		sc->sc_flags |= H_WRITTEN;
295 	switch (sc->sc_erreg & MTER_INTCODE) {
296 	case MTER_DONE:
297 	case MTER_LONGREC:
298 		if (mi->mi_tab.b_errcnt != 2)
299 			sc->sc_blkno++;
300 		bp->b_resid = 0;
301 		break;
302 
303 	case MTER_NOTCAP:
304 		printf("mu%d: blank tape\n", MUUNIT(bp->b_dev));
305 		goto err;
306 
307 	case MTER_TM:
308 	case MTER_EOT:
309 		sc->sc_blkno++;
310 	err:
311 		bp->b_resid = bp->b_bcount;
312 		sc->sc_nxrec = dbtofsb(bp->b_blkno);
313 		break;
314 
315 	case MTER_SHRTREC:
316 		sc->sc_blkno++;
317 		if (bp != &rmtbuf[MTUNIT(bp->b_dev)])
318 			bp->b_flags |= B_ERROR;
319 		if (mi->mi_tab.b_errcnt == 2)
320 			bp->b_bcount = bp->b_resid;	/* restore saved value */
321 		bp->b_resid = bp->b_bcount - mtaddr->mtbc;
322 		break;
323 
324 	case MTER_RDOPP:
325 		mi->mi_tab.b_errcnt = 2;	/* indicate "read opposite" */
326 		bp->b_resid = bp->b_bcount;	/* save it */
327 		bp->b_bcount = mtaddr->mtbc;	/* use this instead */
328 		return(MBD_RETRY);
329 
330 	case MTER_RETRY:
331 		mi->mi_tab.b_errcnt = 1;	/* indicate simple retry */
332 		return(MBD_RETRY);
333 
334 	case MTER_OFFLINE:
335 		if (sc->sc_openf > 0) {
336 			sc->sc_openf = -1;
337 			printf("mu%d: offline\n", MUUNIT(bp->b_dev));
338 		}
339 		bp->b_flags |= B_ERROR;
340 		break;
341 
342 	case MTER_FPT:
343 		printf("mu%d: no write ring\n", MUUNIT(bp->b_dev));
344 		bp->b_flags |= B_ERROR;
345 		break;
346 
347 	default:
348 		printf("mu%d: hard error bn%d mbsr=%b er=%x ds=%b\n",
349 		    MUUNIT(bp->b_dev), bp->b_blkno,
350 		    mbsr, mbsr_bits, sc->sc_erreg,
351 		    sc->sc_dsreg, mtds_bits);
352 		bp->b_flags |= B_ERROR;
353 		mtaddr->mtid = MTID_CLR;		/* reset the TM78 */
354 		DELAY(250);
355 		while ((mtaddr->mtid & MTID_RDY) == 0)	/* wait for it */
356 			;
357 		return (MBD_DONE);
358 	}
359 	/* CHECK FOR MBA ERROR WHEN NO OTHER ERROR INDICATED? */
360 	return (MBD_DONE);
361 }
362 
363 mtndtint(mi)
364 	register struct mba_device *mi;
365 {
366 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
367 	register struct buf *bp = mi->mi_tab.b_actf;
368 	register struct mu_softc *sc;
369 	int er, fc, unit;
370 
371 	unit = (mtaddr->mtner >> 8) & 3;
372 	er = MASKREG(mtaddr->mtner);
373 	/* WILL THIS OCCUR IF ANOTHER DRIVE COMES ONLINE? */
374 	if (bp == 0 || unit != MUUNIT(bp->b_dev)) {	/* consistency check */
375 		if ((er & MTER_INTCODE) != MTER_ONLINE)
376 			printf("mt: unit %d random interrupt\n", unit);
377 		return (MBN_SKIP);
378 	}
379 	if (bp == 0)
380 		return (MBN_SKIP);
381 	fc = (mtaddr->mtncs[unit] >> 8) & 0xff;
382 	sc = &mu_softc[unit];
383 	sc->sc_erreg = er;
384 	sc->sc_resid = fc;
385 	switch (er & MTER_INTCODE) {
386 	case MTER_DONE:
387 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) {
388 	done:
389 			if (bp->b_command == MT_SENSE)
390 				sc->sc_dsreg = MASKREG(mtaddr->mtds);
391 			bp->b_resid = fc;
392 			return (MBN_DONE);
393 		}
394 		/* this is UGLY!  (but is it correct?) */
395 		if ((fc = dbtofsb(bp->b_blkno) - sc->sc_blkno) < 0)
396 			sc->sc_blkno -= min(0377, -fc);
397 		else
398 			sc->sc_blkno += min(0377, fc);
399 		return (MBN_RETRY);
400 
401 	case MTER_RWDING:
402 		return (MBN_SKIP);	/* ignore "rewind started" interrupt */
403 
404 	case MTER_NOTCAP:
405 		printf("mu%d: blank tape\n", MUUNIT(bp->b_dev));
406 
407 	case MTER_TM:
408 	case MTER_EOT:
409 	case MTER_LEOT:
410 		if (sc->sc_blkno > dbtofsb(bp->b_blkno)) {
411 			sc->sc_nxrec = dbtofsb(bp->b_blkno) + fc;
412 			sc->sc_blkno = sc->sc_nxrec;
413 		} else {
414 			sc->sc_blkno = dbtofsb(bp->b_blkno) - fc;
415 			sc->sc_nxrec = sc->sc_blkno - 1;
416 		}
417 		return (MBN_RETRY);
418 
419 	case MTER_FPT:
420 		printf("mu%d: no write ring\n", MUUNIT(bp->b_dev));
421 		bp->b_flags |= B_ERROR;
422 		return (MBN_DONE);
423 
424 	case MTER_OFFLINE:
425 		if (sc->sc_openf > 0) {
426 			sc->sc_openf = -1;
427 			printf("mu%d: offline\n", MUUNIT(bp->b_dev));
428 		}
429 		bp->b_flags |= B_ERROR;
430 		return (MBN_DONE);
431 
432 	case MTER_BOT:
433 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)])
434 			goto done;
435 		/* FALL THROUGH */
436 
437 	default:
438 		printf("mu%d: hard error bn%d er=%o ds=%b\n",
439 		    MUUNIT(bp->b_dev), bp->b_blkno,
440 		    sc->sc_erreg, sc->sc_dsreg, mtds_bits);
441 		mtaddr->mtid = MTID_CLR;		/* reset the TM78 */
442 		DELAY(250);
443 		while ((mtaddr->mtid & MTID_RDY) == 0)	/* wait for it */
444 			;
445 		bp->b_flags |= B_ERROR;
446 		return (MBN_DONE);
447 	}
448 	/* NOTREACHED */
449 }
450 
451 mtread(dev)
452 	dev_t dev;
453 {
454 
455 	mtphys(dev);
456 	if (u.u_error)
457 		return;
458 	physio(mtstrategy, &rmtbuf[MTUNIT(dev)], dev, B_READ, minphys);
459 }
460 
461 mtwrite(dev)
462 {
463 
464 	mtphys(dev);
465 	if (u.u_error)
466 		return;
467 	physio(mtstrategy, &rmtbuf[MTUNIT(dev)], dev, B_WRITE, minphys);
468 }
469 
470 mtphys(dev)
471 	dev_t dev;
472 {
473 	register int mtunit;
474 	register struct mu_softc *sc;
475 	register struct mba_device *mi;
476 	daddr_t a;
477 
478 	mtunit = MTUNIT(dev);
479 	if (mtunit >= NMT || (mi = mtinfo[mtunit]) == 0 || mi->mi_alive == 0) {
480 		u.u_error = ENXIO;
481 		return;
482 	}
483 	a = u.u_offset >> 9;
484 	sc = &mu_softc[MUUNIT(dev)];
485 	sc->sc_blkno = dbtofsb(a);
486 	sc->sc_nxrec = dbtofsb(a)+1;
487 }
488 
489 /*ARGSUSED*/
490 mtioctl(dev, cmd, addr, flag)
491 	dev_t dev;
492 	int cmd;
493 	caddr_t addr;
494 	int flag;
495 {
496 	register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
497 	register struct buf *bp = &cmtbuf[MTUNIT(dev)];
498 	register callcount;
499 	register int n, op;
500 	int fcount;
501 	struct mtop mtop;
502 	struct mtget mtget;
503 	/* we depend of the values and order of the MT codes here */
504 	static mtops[] =
505 	{MT_WTM,MT_SFORWF,MT_SREVF,MT_SFORW,MT_SREV,MT_REW,MT_UNLOAD,MT_SENSE};
506 
507 	switch (cmd) {
508 		case MTIOCTOP:	/* tape operation */
509 		if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) {
510 			u.u_error = EFAULT;
511 			return;
512 		}
513 		switch(mtop.mt_op) {
514 		case MTWEOF:
515 			callcount = mtop.mt_count;
516 			fcount = 1;
517 			break;
518 		case MTFSF: case MTBSF:
519 			callcount = mtop.mt_count;
520 			fcount = 1;
521 			break;
522 		case MTFSR: case MTBSR:
523 			callcount = 1;
524 			fcount = mtop.mt_count;
525 			break;
526 		case MTREW: case MTOFFL:
527 			callcount = 1;
528 			fcount = 1;
529 			break;
530 		default:
531 			u.u_error = ENXIO;
532 			return;
533 		}
534 		if (callcount <= 0 || fcount <= 0) {
535 			u.u_error = ENXIO;
536 			return;
537 		}
538 		op = mtops[mtop.mt_op];
539 		if (op == MT_WTM)
540 			op |= sc->sc_dens;
541 		while (--callcount >= 0) {
542 			register int n;
543 
544 			do {
545 				n = min(fcount, 0xff);
546 				mtcommand(dev, op, n);
547 				fcount -= n;
548 			} while (fcount);
549 			if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) &&
550 			    bp->b_resid) {
551 				u.u_error = EIO;
552 				break;
553 			}
554 			if (bp->b_flags&B_ERROR)
555 				break;
556 		}
557 		geterror(bp);
558 		return;
559 	case MTIOCGET:
560 		mtget.mt_erreg = sc->sc_erreg;
561 		mtget.mt_resid = sc->sc_resid;
562 		mtcommand(dev, MT_SENSE, 1);	/* update drive status */
563 		mtget.mt_dsreg = sc->sc_dsreg;
564 		mtget.mt_type = MT_ISMT;
565 		if (copyout((caddr_t)&mtget, addr, sizeof(mtget)))
566 			u.u_error = EFAULT;
567 		return;
568 	default:
569 		u.u_error = ENXIO;
570 	}
571 }
572 
573 #define	DBSIZE	20
574 
575 mtdump()
576 {
577 	register struct mba_device *mi;
578 	register struct mba_regs *mp;
579 	register struct mtdevice *mtaddr;
580 	int blk, num;
581 	int start;
582 
583 	start = 0;
584 	num = maxfree;
585 #define	phys(a,b)		((b)((int)(a)&0x7fffffff))
586 	if (mtinfo[0] == 0)
587 		return (ENXIO);
588 	mi = phys(mtinfo[0], struct mba_device *);
589 	mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba;
590 	mp->mba_cr = MBCR_IE;
591 	mtaddr = (struct mtdevice *)&mp->mba_drv[mi->mi_drive];
592 #ifdef notyet
593 	mtaddr->mttc = MTTC_PDP11|MTTC_1600BPI;
594 	mtaddr->mtcs1 = MT_DCLR|MT_GO;
595 	while (num > 0) {
596 		blk = num > DBSIZE ? DBSIZE : num;
597 		mtdwrite(start, blk, mtaddr, mp);
598 		start += blk;
599 		num -= blk;
600 	}
601 	mteof(mtaddr);
602 	mteof(mtaddr);
603 	mtwait(mtaddr);
604 	if (mtaddr->mtds&MTDS_ERR)
605 		return (EIO);
606 	mtaddr->mtcs1 = MT_REW|MT_GO;
607 	return (0);
608 }
609 
610 mtdwrite(dbuf, num, mtaddr, mp)
611 	register dbuf, num;
612 	register struct mtdevice *mtaddr;
613 	struct mba_regs *mp;
614 {
615 	register struct pte *io;
616 	register int i;
617 
618 	mtwait(mtaddr);
619 	io = mp->mba_map;
620 	for (i = 0; i < num; i++)
621 		*(int *)io++ = dbuf++ | PG_V;
622 	mtaddr->mtfc = -(num*NBPG);
623 	mp->mba_sr = -1;
624 	mp->mba_bcr = -(num*NBPG);
625 	mp->mba_var = 0;
626 	mtaddr->mtcs1 = MT_WCOM|MT_GO;
627 }
628 
629 mtwait(mtaddr)
630 	struct mtdevice *mtaddr;
631 {
632 	register s;
633 
634 	do
635 		s = mtaddr->mtds;
636 	while ((s & MTDS_DRY) == 0);
637 }
638 
639 mteof(mtaddr)
640 	struct mtdevice *mtaddr;
641 {
642 
643 	mtwait(mtaddr);
644 	mtaddr->mtcs1 = MT_WEOF|MT_GO;
645 #endif notyet
646 }
647 #endif
648