xref: /csrg-svn/sys/tahoe/vba/mp.c (revision 37607)
1 /*
2  * Copyright (c) 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Computer Consoles Inc.
7  *
8  * Redistribution and use in source and binary forms are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the University of California, Berkeley.  The name of the
14  * University may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  *
20  *	@(#)mp.c	7.9 (Berkeley) 05/01/89
21  */
22 
23 #include "mp.h"
24 #if NMP > 0
25 /*
26  * Multi Protocol Communications Controller (MPCC).
27  * Asynchronous Terminal Protocol Support.
28  */
29 #include "param.h"
30 #include "ioctl.h"
31 #include "tty.h"
32 #include "dir.h"
33 #include "user.h"
34 #include "map.h"
35 #include "buf.h"
36 #include "conf.h"
37 #include "file.h"
38 #include "uio.h"
39 #include "errno.h"
40 #include "syslog.h"
41 #include "vmmac.h"
42 #include "kernel.h"
43 #include "clist.h"
44 
45 #include "machine/pte.h"
46 #include "machine/mtpr.h"
47 
48 #include "../tahoevba/vbavar.h"
49 #include "../tahoevba/mpreg.h"
50 
51 #define	MPCHUNK	16
52 #define	MPPORT(n)	((n) & 0xf)
53 #define	MPUNIT(n)	((n) >> 4)
54 
55 /*
56  * Driver information for auto-configuration stuff.
57  */
58 int     mpprobe(), mpattach(), mpintr();
59 struct  vba_device *mpinfo[NMP];
60 long    mpstd[] = { 0 };
61 struct  vba_driver mpdriver =
62     { mpprobe, 0, mpattach, 0, mpstd, "mp", mpinfo };
63 
64 int	mpstart();
65 int	mpparam();
66 struct	mpevent *mpparam2();
67 struct	mpevent *mp_getevent();
68 
69 /*
70  * The following structure is needed to deal with mpcc's convoluted
71  * method for locating it's mblok structures (hold your stomach).
72  * When an mpcc is reset at boot time it searches host memory
73  * looking for a string that says ``ThIs Is MpCc''.  The mpcc
74  * then reads the structure to locate the pointer to it's mblok
75  * structure (you can wretch now).
76  */
77 struct mpbogus {
78 	char	s[12];			/* `ThIs Is MpCc'' */
79 	u_char	status;
80 	u_char	unused;
81 	u_short	magic;
82 	struct	mblok *mb;
83 	struct	mblok *mbloks[NMP];	/* can support at most 16 mpcc's */
84 } mpbogus = { 'T','h','I','s',' ','I','s',' ','M','p','C','c' };
85 
86 /*
87  * Software state per unit.
88  */
89 struct	mpsoftc {
90 	u_int	ms_ivec;		/* interrupt vector */
91 	u_int	ms_softCAR;		/* software carrier for async */
92 	struct	mblok *ms_mb;		/* mpcc status area */
93 	struct	vb_buf ms_buf;		/* vba resources for ms_mb */
94 	struct	hxmtl ms_hxl[MPMAXPORT];/* host transmit list */
95 	struct	asyncparam ms_async[MPMAXPORT][MPINSET];/* async structs */
96 	char	ms_cbuf[MPMAXPORT][MPOUTSET][CBSIZE];/* input character buffers */
97 } mp_softc[NMP];
98 
99 struct	speedtab
100 mpspeedtab[] = {
101 	9600,	M9600,	  /* baud rate = 9600 */
102 	4800,	M4800,	  /* baud rate = 4800 */
103 	2400,	M2400,	  /* baud rate = 2400 */
104 	1800,	M1800,	  /* baud rate = 1800 */
105 	1200,	M1200,	  /* baud rate = 1200 */
106 	600,	M600,	  /* baud rate = 600 */
107 	300,	M300,	  /* baud rate = 300 */
108 	200,	M200,	  /* baud rate = 200 */
109 	150,	M150,	  /* baud rate = 150 */
110 	134,	M134_5,	  /* baud rate = 134.5 */
111 	110,	M110,	  /* baud rate = 110 */
112 	75,	M75,	  /* baud rate = 75 */
113 	50,	M50,	  /* baud rate = 50 */
114 	0,	M0,	  /* baud rate = 0 */
115 	2000,	M2000,	  /* baud rate = 2000 */
116 	3600,	M3600,	  /* baud rate = 3600 */
117 	7200,	M7200,	  /* baud rate = 7200 */
118 	19200,	M19200,	  /* baud rate = 19,200 */
119 	24000,	M24000,	  /* baud rate = 24,000 */
120 	28400,	M28400,	  /* baud rate = 28,400 */
121 	37800,	M37800,	  /* baud rate = 37,800 */
122 	40300,	M40300,	  /* baud rate = 40,300 */
123 	48000,	M48000,	  /* baud rate = 48,000 */
124 	52000,	M52000,	  /* baud rate = 52,000 */
125 	56800,	M56800,	  /* baud rate = 56,800 */
126 	EXTA,	MEXTA,	  /* baud rate = Ext A */
127 	EXTB,	MEXTB,	  /* baud rate = Ext B */
128 	-1,	-1,
129 };
130 
131 struct	tty mp_tty[NMP*MPCHUNK];
132 #ifndef lint
133 int	nmp = NMP*MPCHUNK;
134 #endif
135 
136 int	ttrstrt();
137 
138 mpprobe(reg, vi)
139 	caddr_t reg;
140 	struct vba_device *vi;
141 {
142 	register int br, cvec;
143 	register struct mpsoftc *ms;
144 
145 #ifdef lint
146 	br = 0; cvec = br; br = cvec;
147 	mpintr(0);
148 	mpdlintr(0);
149 #endif
150 	if (badaddr(reg, 2))
151 		return (0);
152 	ms = &mp_softc[vi->ui_unit];
153 	/*
154 	 * Allocate page tables and mblok
155 	 * structure (mblok in non-cached memory).
156 	 */
157 	if (vbainit(&ms->ms_buf, sizeof (struct mblok), VB_32BIT) == 0) {
158 		printf("mp%d: vbainit failed\n", vi->ui_unit);
159 		return (0);
160 	}
161 	ms->ms_mb = (struct mblok *)ms->ms_buf.vb_rawbuf;
162 	ms->ms_ivec = MPINTRBASE + 2*vi->ui_unit;	/* XXX */
163 	br = 0x14, cvec = ms->ms_ivec;			/* XXX */
164 	return (sizeof (*reg));
165 }
166 
167 mpattach(vi)
168 	register struct vba_device *vi;
169 {
170 	register struct mpsoftc *ms = &mp_softc[vi->ui_unit];
171 
172 	ms->ms_softCAR = vi->ui_flags;
173 	/*
174 	 * Setup pointer to mblok, initialize bogus
175 	 * status block used by mpcc to locate the pointer
176 	 * and then poke the mpcc to get it to search host
177 	 * memory to find mblok pointer.
178 	 */
179 	mpbogus.mbloks[vi->ui_unit] = (struct mblok *)ms->ms_buf.vb_physbuf;
180 	*(short *)vi->ui_addr = 0x100;		/* magic */
181 }
182 
183 /*
184  * Open an mpcc port.
185  */
186 /* ARGSUSED */
187 mpopen(dev, mode)
188 	dev_t dev;
189 {
190 	register struct tty *tp;
191 	register struct mpsoftc *ms;
192 	int error, s, port, unit, mpu;
193 	struct vba_device *vi;
194 	struct mpport *mp;
195 	struct mpevent *ev;
196 
197 	unit = minor(dev);
198 	mpu = MPUNIT(unit);
199 	if (mpu >= NMP || (vi = mpinfo[mpu]) == 0 || vi->ui_alive == 0)
200 		return (ENXIO);
201 	tp = &mp_tty[unit];
202 	if (tp->t_state & TS_XCLUDE && u.u_uid != 0)
203 		return (EBUSY);
204 	ms = &mp_softc[mpu];
205 	port = MPPORT(unit);
206 	if (ms->ms_mb->mb_proto[port] != MPPROTO_ASYNC ||
207 	    ms->ms_mb->mb_status != MP_OPOPEN)
208 		return (ENXIO);
209 	mp = &ms->ms_mb->mb_port[port];		/* host mpcc struct */
210 	s = spl8();
211 	/*
212 	 * serialize open and close events
213 	 */
214 	while ((mp->mp_flags & MP_PROGRESS) || ((tp->t_state & TS_WOPEN) &&
215 		!(mode&O_NONBLOCK) && !(tp->t_cflag&CLOCAL)))
216 		sleep((caddr_t)&tp->t_canq, TTIPRI);
217 restart:
218 	tp->t_state |= TS_WOPEN;
219 	tp->t_addr = (caddr_t)ms;
220 	tp->t_oproc = mpstart;
221 	tp->t_param = mpparam;
222 	tp->t_dev = dev;
223 	if ((tp->t_state & TS_ISOPEN) == 0) {
224 		ttychars(tp);
225 		if (tp->t_ispeed == 0) {
226 		tp->t_ispeed = TTYDEF_SPEED;
227 		tp->t_ospeed = TTYDEF_SPEED;
228 		tp->t_iflag = TTYDEF_IFLAG;
229 		tp->t_oflag = TTYDEF_OFLAG;
230 		tp->t_lflag = TTYDEF_LFLAG;
231 		tp->t_cflag = TTYDEF_CFLAG;
232 		}
233 		/*
234 		 * Initialize port state: init MPCC interface
235 		 * structures for port and setup modem control.
236 		 */
237 		error = mpportinit(ms, mp, port);
238 		if (error)
239 			goto bad;
240 		ev = mpparam2(tp, &tp->t_termios);
241 		if (ev == 0) {
242 			error = ENOBUFS;
243 			goto bad;
244 		}
245 		mp->mp_flags |= MP_PROGRESS;
246 		mpcmd(ev, EVCMD_OPEN, 0, ms->ms_mb, port);
247 		/*
248 		 * wait for port to start
249 		 */
250 		while (mp->mp_proto != MPPROTO_ASYNC)
251 			sleep((caddr_t)&tp->t_canq, TTIPRI);
252 		ttsetwater(tp);
253 		mp->mp_flags &= ~MP_PROGRESS;
254 	}
255 	while (!(mode&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) &&
256 	       (tp->t_state & TS_CARR_ON) == 0) {
257 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
258 		/*
259 		 * a mpclose() might have disabled port. if so restart
260 		 */
261 		if (mp->mp_proto != MPPROTO_ASYNC)
262 			goto restart;
263 		tp->t_state |= TS_WOPEN;
264 	}
265 	error = (*linesw[tp->t_line].l_open)(dev,tp);
266 done:
267 	splx(s);
268 	/*
269 	 * wakeup those processes waiting for the open to complete
270 	 */
271 	wakeup((caddr_t)&tp->t_canq);
272 	return (error);
273 bad:
274 	tp->t_state &= ~TS_WOPEN;
275 	goto done;
276 }
277 
278 /*
279  * Close an mpcc port.
280  */
281 /* ARGSUSED */
282 mpclose(dev, flag)
283 	dev_t dev;
284 {
285 	register struct tty *tp;
286 	register struct mpport *mp;
287 	register struct mpevent *ev;
288 	int s, port, unit, error;
289 	struct mblok *mb;
290 
291 	unit = minor(dev);
292 	tp = &mp_tty[unit];
293 	port = MPPORT(unit);
294 	mb = mp_softc[MPUNIT(unit)].ms_mb;
295 	mp = &mb->mb_port[port];
296 	s = spl8();
297 	if (mp->mp_flags & MP_PROGRESS) {
298 		if (mp->mp_flags & MP_REMBSY) {
299 			mp->mp_flags &= ~MP_REMBSY;
300 			splx(s);
301 			return (0);
302 		}
303 		while (mp->mp_flags & MP_PROGRESS)
304 			sleep((caddr_t)&tp->t_canq, TTIPRI);
305 	}
306 	error = 0;
307 	mp->mp_flags |= MP_PROGRESS;
308 	(*linesw[tp->t_line].l_close)(tp);
309 	ev = mp_getevent(mp, unit, 1);
310 	if (ev == 0) {
311 		error = ENOBUFS;
312 		mp->mp_flags &= ~MP_PROGRESS;
313 		goto out;
314 	}
315 	if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0)
316 		mpmodem(unit, MMOD_OFF);
317 	else
318 		mpmodem(unit, MMOD_ON);
319 	mpcmd(ev, EVCMD_CLOSE, 0, mb, port);
320 	ttyclose(tp);
321 out:
322 	if (mp->mp_flags & MP_REMBSY)
323 		mpclean(mb, port);
324 	else
325 		while (mp->mp_flags & MP_PROGRESS)
326 			sleep((caddr_t)&tp->t_canq,TTIPRI);
327 	splx(s);
328 	return (error);
329 }
330 
331 /*
332  * Read from an mpcc port.
333  */
334 mpread(dev, uio, flag)
335 	dev_t dev;
336 	struct uio *uio;
337 {
338 	struct tty *tp;
339 
340 	tp = &mp_tty[minor(dev)];
341 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
342 }
343 
344 /*
345  * Write to an mpcc port.
346  */
347 mpwrite(dev, uio, flag)
348 	dev_t dev;
349 	struct uio *uio;
350 {
351 	struct tty *tp;
352 
353 	tp = &mp_tty[minor(dev)];
354 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
355 }
356 
357 /*
358  * Ioctl for a mpcc port
359  */
360 mpioctl(dev, cmd, data, flag)
361 	dev_t dev;
362 	caddr_t data;
363 {
364 	register struct tty *tp;
365 	register struct mpsoftc *ms;
366 	register struct mpport *mp;
367 	register struct mpevent *ev;
368 	int s, port, error, unit;
369 	struct mblok *mb;
370 
371 	unit = minor(dev);
372 	tp = &mp_tty[unit];
373 	ms = &mp_softc[MPUNIT(unit)];
374 	mb = ms->ms_mb;
375 	port = MPPORT(unit);
376 	mp = &mb->mb_port[port];
377 	if (mp->mp_proto != MPPROTO_ASYNC)
378 		return(ENXIO);
379 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
380 	if (error >= 0)
381 		return (error);
382 	error = ttioctl(tp, cmd, data, flag);
383 	if (error >= 0)
384 		return (error);
385 	switch (cmd) {
386 	case TIOCSBRK:			/* send break */
387 	case TIOCCBRK:			/* clear break */
388 		s = spl8();
389 		while (mp->mp_flags & MP_IOCTL) {
390 			sleep((caddr_t)&tp->t_canq, TTIPRI);
391 			if (mp->mp_proto != MPPROTO_ASYNC) {
392 				mp->mp_flags &= ~MP_IOCTL;
393 				splx(s);
394 				return(ENXIO);
395 			}
396 		}
397 		ev = mp_getevent(mp, unit, 0);
398 		if (ev) {
399 			mp->mp_flags |= MP_IOCTL;
400 			mpcmd(ev, EVCMD_IOCTL,
401 			    (cmd == TIOCSBRK ? A_BRKON : A_BRKOFF), mb, port);
402 		} else
403 			error = ENOBUFS;
404 		splx(s);
405 		break;
406 	case TIOCSDTR:			/* set dtr control line */
407 		break;
408 	case TIOCCDTR:			/* clear dtr control line */
409 		break;
410 	default:
411 		error = ENOTTY;
412 		break;
413 	}
414 	return (error);
415 }
416 
417 mpparam(tp, t)
418 	struct tty *tp;
419 	struct termios *t;
420 {
421 	register struct mpevent *ev;
422 	int unit = minor(tp->t_dev);
423 	struct mpsoftc *ms = &mp_softc[MPUNIT(unit)];
424 	struct mblok *mb = ms->ms_mb;
425 
426 	ev = mpparam2(tp, t);
427 	if (ev == 0)
428 		return (ENOBUFS);
429 	mpcmd(ev, EVCMD_IOCTL, A_CHGALL, mb, MPPORT(unit));
430 	return (0);
431 }
432 
433 struct mpevent *
434 mpparam2(tp, t)
435 	register struct tty *tp;
436 	struct termios *t;
437 {
438 	register struct mpevent *ev;
439 	register struct mpport *mp;
440 	int unit = minor(tp->t_dev);
441 	struct mblok *mb;
442 	struct mpsoftc *ms;
443 	register struct asyncparam *asp;
444 	int port, speedcode;
445 
446 	ms = &mp_softc[MPUNIT(unit)];
447 	mb = ms->ms_mb;
448 	port = MPPORT(unit);
449 	mp = &mb->mb_port[port];
450 	ev = mp_getevent(mp, unit, 0);	/* XXX */
451 	speedcode = ttspeedtab(t->c_ospeed, mpspeedtab);
452 	if (ev == 0 || speedcode < 0) {
453 printf("mp mpunit %d port %d param2 failed ev: %x speed %d, wanted %d\n",
454 			MPUNIT(unit), port, ev, speedcode, t->c_ospeed);
455 		return (0);	/* XXX */
456 	}
457 	/* YUCK */
458 	asp = &ms->ms_async[port][mp->mp_on?mp->mp_on-1:MPINSET-1];
459 	asp->ap_xon = t->c_cc[VSTART];
460 	asp->ap_xoff = t->c_cc[VSTOP];
461 	if (!(t->c_iflag&IXON) || (asp->ap_xon == _POSIX_VDISABLE) ||
462 	    (asp->ap_xoff == _POSIX_VDISABLE))
463 		asp->ap_xena = MPA_DIS;
464 	else
465 		asp->ap_xena = MPA_ENA;
466 	asp->ap_xany = ((t->c_iflag & IXANY) ? MPA_ENA : MPA_DIS);
467 #ifdef notnow
468 	if (t->t_cflag&CSIZE) == CS8) {
469 #endif
470 		asp->ap_data = MPCHAR_8;
471 		asp->ap_parity = MPPAR_NONE;
472 #ifdef notnow
473 	} else {
474 		asp->ap_data = MPCHAR_7;
475 		if ((t->c_flags & (EVENP|ODDP)) == ODDP) /* XXX */
476 			asp->ap_parity = MPPAR_ODD;
477 		else
478 			asp->ap_parity = MPPAR_EVEN;
479 	}
480 #endif
481 	asp->ap_loop = MPA_DIS;		/* disable loopback */
482 	asp->ap_rtimer = A_RCVTIM;	/* default receive timer */
483 	if (t->c_ospeed == B110)
484 		asp->ap_stop = MPSTOP_2;
485 	else
486 		asp->ap_stop = MPSTOP_1;
487 	if (t->c_ospeed == 0) {
488 		tp->t_state |= TS_HUPCLS;
489 		setm(&asp->ap_modem, 0, DROP);
490 		seti(&asp->ap_intena, A_DCD);
491 		return (ev);
492 	}
493 	if (t->c_ospeed == EXTA || t->c_ospeed == EXTB)
494 		asp->ap_baud = M19200;
495 	else
496 		asp->ap_baud = speedcode;
497 	if (1 || ms->ms_softCAR & (1<<port)) /* XXX HARDWIRE FOR NOW */
498 		setm(&asp->ap_modem, A_DTR, ASSERT);
499 	else
500 		setm(&asp->ap_modem, A_DTR, AUTO);
501 	seti(&asp->ap_intena, A_DCD);
502 	return(ev);
503 }
504 
505 mpstart(tp)
506 	register struct tty *tp;
507 {
508 	register struct mpevent *ev;
509 	register struct mpport *mp;
510 	struct mblok *mb;
511 	struct mpsoftc *ms;
512 	int port, unit, xcnt, n, s, i;
513 	struct	hxmtl *hxp;
514 	struct clist outq;
515 
516 	s = spl8();
517 	unit = minor(tp->t_dev);
518 	ms = &mp_softc[MPUNIT(unit)];
519 	mb = ms->ms_mb;
520 	port = MPPORT(unit);
521 	mp = &mb->mb_port[port];
522 	hxp = &ms->ms_hxl[port];
523 	xcnt = 0;
524 	outq = tp->t_outq;
525 	for (i = 0; i < MPXMIT; i++) {
526 		if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
527 			break;
528 		if (outq.c_cc <= tp->t_lowat) {
529 			if (tp->t_state & TS_ASLEEP) {
530 				tp->t_state &= ~TS_ASLEEP;
531 				wakeup((caddr_t)&tp->t_outq);
532 			}
533 			if (tp->t_wsel) {
534 				selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
535 				tp->t_wsel = 0;
536 				tp->t_state &= ~TS_WCOLL;
537 			}
538 		}
539 		if (outq.c_cc == 0)
540 			break;
541 		/*
542 		 * If we're not currently busy outputting,
543 		 * and there is data to be output, set up
544 		 * port transmit structure to send to mpcc.
545 		 */
546 		if (1) /* || tp->t_flags & (RAW|LITOUT))  XXX FIX */
547 			n = ndqb(&outq, 0);
548 		else {
549 			n = ndqb(&outq, 0200);
550 			if (n == 0) {
551 				if (xcnt > 0)
552 					break;
553 				n = getc(&outq);
554 				timeout(ttrstrt, (caddr_t)tp, (n&0177)+6);
555 				tp->t_state |= TS_TIMEOUT;
556 				break;
557 			}
558 		}
559 		hxp->dblock[i] = (caddr_t)kvtophys(outq.c_cf);
560 		hxp->size[i] = n;
561 		xcnt++;		/* count of xmts to send */
562 		ndadvance(&outq, n);
563 	}
564 	/*
565 	 * If data to send, poke mpcc.
566 	 */
567 	if (xcnt) {
568 		ev = mp_getevent(mp, unit, 0);
569 		if (ev == 0) {
570 			tp->t_state &= ~(TS_BUSY|TS_TIMEOUT);
571 		} else {
572 			tp->t_state |= TS_BUSY;
573 			ev->ev_count = xcnt;
574 			mpcmd(ev, EVCMD_WRITE, 0, mb, MPPORT(unit));
575 		}
576 	}
577 	splx(s);
578 }
579 
580 /*
581  * Advance cc bytes from q  but don't free memory.
582  */
583 ndadvance(q, cc)
584 	register struct clist *q;
585 	register cc;
586 {
587 	register struct cblock *bp;
588 	char *end;
589 	int rem, s;
590 
591 	s = spltty();
592 	if (q->c_cc <= 0)
593 		goto out;
594 	while (cc>0 && q->c_cc) {
595 		bp = (struct cblock *)((int)q->c_cf & ~CROUND);
596 		if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) {
597 			end = q->c_cl;
598 		} else {
599 			end = (char *)((int)bp + sizeof (struct cblock));
600 		}
601 		rem = end - q->c_cf;
602 		if (cc >= rem) {
603 			cc -= rem;
604 			q->c_cc -= rem;
605 			q->c_cf = bp->c_next->c_info;
606 		} else {
607 			q->c_cc -= cc;
608 			q->c_cf += cc;
609 			break;
610 		}
611 	}
612 	if (q->c_cc <= 0) {
613 		q->c_cf = q->c_cl = NULL;
614 		q->c_cc = 0;
615 	}
616 out:
617 	splx(s);
618 }
619 
620 /*
621  * Stop output on a line, e.g. for ^S/^Q or output flush.
622  */
623 /* ARGSUSED */
624 mpstop(tp, rw)
625 	register struct tty *tp;
626 	int rw;
627 {
628 	register struct mpport *mp;
629 	register struct mpevent *ev;
630 	int unit = minor(tp->t_dev);
631 	int port;
632 	struct mblok *mb;
633 	int s;
634 
635 	s = spl8();
636 	if (tp->t_state & TS_BUSY) {
637 		if ((tp->t_state & TS_TTSTOP) == 0) {
638 			tp->t_state |= TS_FLUSH;
639 			port = MPPORT(unit);
640 			mb = mp_softc[MPUNIT(unit)].ms_mb;
641 			mp = &mb->mb_port[port];
642 			ev = mp_getevent(mp, unit, 0);
643 			if (ev == 0) {
644 				splx(s);
645 				return;
646 			}
647 			mpcmd(ev, EVCMD_WRITE, A_FLUSH, mb, port);
648 		}
649 	}
650 	splx(s);
651 }
652 
653 /*
654  * Initialize an async port's MPCC state.
655  */
656 mpportinit(ms, mp, port)
657 	register struct mpsoftc *ms;
658 	register struct mpport *mp;
659 	int port;
660 {
661 	register struct mpevent *ev;
662 	register int i;
663 	caddr_t ptr;
664 
665 	mp->mp_on = mp->mp_off = 0;
666 	mp->mp_nextrcv = 0;
667 	mp->mp_flags = 0;
668 	ev = &mp->mp_recvq[0];
669 	for (i = 0; ev < &mp->mp_recvq[MPINSET]; ev++, i++) {
670 		ev->ev_status = EVSTATUS_FREE;
671 		ev->ev_cmd = 0;
672 		ev->ev_opts = 0;
673 		ev->ev_error = 0;
674 		ev->ev_flags = 0;
675 		ev->ev_count = 0;
676 		ev->ev_un.hxl = (struct hxmtl *) kvtophys(&ms->ms_hxl[port]);
677 		ev->ev_params = (caddr_t) kvtophys(&ms->ms_async[port][i]);
678 	}
679 	ev = &mp->mp_sendq[0];
680 	for (i = 0; ev < &mp->mp_sendq[MPOUTSET]; ev++, i++) {
681 		/* init so that L2 can't send any events */
682 		/* to host until open has completed      */
683 		ev->ev_status = EVSTATUS_FREE;
684 		ev->ev_cmd = 0;
685 		ev->ev_opts = 0;
686 		ev->ev_error = 0;
687 		ev->ev_flags = 0;
688 		ev->ev_count = 0;
689 		ptr = (caddr_t) &ms->ms_cbuf[port][i][0];
690 		ev->ev_un.rcvblk = (u_char *)kvtophys(ptr);
691 		ev->ev_params = (caddr_t) kvtophys(ptr);
692 	}
693 	return (0);
694 }
695 
696 /*
697  * Send an event to an mpcc.
698  */
699 mpcmd(ev, cmd, flags, mb, port)
700 	register struct mpevent *ev;
701 	struct mblok *mb;
702 {
703 	int s;
704 
705 	s = spl8();
706 	/* move host values to inbound entry */
707 	ev->ev_cmd = cmd;
708 	ev->ev_opts = flags;
709 	/* show event ready for mpcc */
710 	ev->ev_status = EVSTATUS_GO;
711 	mpintmpcc(mb, port);
712 	splx(s);
713 }
714 
715 /*
716  * Return the next available event entry for the indicated port.
717  */
718 struct mpevent *
719 mp_getevent(mp, unit, cls_req)
720 	register struct mpport *mp;
721 	int unit;
722 	int cls_req;
723 {
724 	register struct mpevent *ev;
725 	int i, s;
726 
727 	s = spl8();
728 	ev = &mp->mp_recvq[mp->mp_on];
729 	if (ev->ev_status != EVSTATUS_FREE)
730 		goto bad;
731 	/*
732 	 * If not a close request, verify one extra
733 	 * event is available for closing the port.
734 	 */
735 	if (!cls_req) {
736 		if ((i = mp->mp_on + 1) >= MPINSET)
737 			i = 0;
738 		if (mp->mp_recvq[i].ev_status != EVSTATUS_FREE)
739 			goto bad;
740 	}
741 	/* init inbound fields marking this entry as busy */
742 	ev->ev_cmd = 0;
743 	ev->ev_opts = 0;
744 	ev->ev_error = 0;
745 	ev->ev_flags = 0;
746 	ev->ev_count = 0;
747 	ev->ev_status = EVSTATUS_BUSY;
748 	/* adjust pointer to next available inbound entry */
749 	adjptr(mp->mp_on, MPINSET);
750 	splx(s);
751 	return (ev);
752 bad:
753 	splx(s);
754 	log(LOG_ERR, "mp%d: port%d, out of events\n",
755 	    MPUNIT(unit), MPPORT(unit));
756 	return ((struct mpevent *)0);
757 }
758 
759 mpmodem(unit, flag)
760 	int unit, flag;
761 {
762 	struct mpsoftc *ms = &mp_softc[MPUNIT(unit)];
763 	int port = MPPORT(unit);
764 	register struct mpport *mp;
765 	register struct asyncparam *asp;
766 
767 	mp = &ms->ms_mb->mb_port[port];
768 	asp = &ms->ms_async[port][mp->mp_on?mp->mp_on-1:MPINSET-1];
769 	if (flag == MMOD_ON) {
770 		if (1 || ms->ms_softCAR & (1 << port))/* XXX HARDWIRE FOR NOW */
771 			setm(&asp->ap_modem, A_DTR, ASSERT);
772 		else
773 			setm(&asp->ap_modem, A_DTR, AUTO);
774 		seti(&asp->ap_intena, A_DCD);
775 	} else {
776 		setm(&asp->ap_modem, 0, DROP);
777 		seti(&asp->ap_intena, 0);
778 	}
779 }
780 
781 /*
782  * Set up the modem control structure according to mask.
783  * Each set bit in the mask means assert the corresponding
784  * modem control line, otherwise, it will be dropped.
785  * RTS is special since it can either be asserted, dropped
786  * or put in auto mode for auto modem control.
787  */
788 static
789 setm(mc, mask, rts)
790 	register struct mdmctl *mc;
791 	register int mask;
792 {
793 
794 	mc->mc_rngdsr = (mask & A_RNGDSR) ? ASSERT : DROP;
795 	mc->mc_rate = (mask & A_RATE) ? ASSERT : DROP;
796 	mc->mc_dcd = (mask & A_DCD) ? ASSERT : DROP;
797 	mc->mc_sectx = (mask & A_SECTX) ? ASSERT : DROP;
798 	mc->mc_cts = (mask & A_CTS) ? ASSERT : DROP;
799 	mc->mc_secrx = (mask & A_SECRX) ? ASSERT : DROP;
800 	mc->mc_dtr = (mask & A_DTR) ? ASSERT : DROP;
801 	mc->mc_rts = rts;
802 }
803 
804 /*
805  * Set up the status change enable field from mask.
806  * When a signal is enabled in this structure and
807  * and a change in state on a corresponding modem
808  * control line occurs, a status change event will
809  * be delivered to the host.
810  */
811 static
812 seti(mc, mask)
813 	register struct mdmctl *mc;
814 	register int mask;
815 {
816 
817 	mc->mc_rngdsr = (mask & A_RNGDSR) ? MDM_ON : MDM_OFF;
818 	mc->mc_rate = (mask & A_RATE) ? MDM_ON : MDM_OFF;
819 	mc->mc_dcd = (mask & A_DCD) ? MDM_ON : MDM_OFF;
820 	mc->mc_sectx = (mask & A_SECTX) ? MDM_ON : MDM_OFF;
821 	mc->mc_cts = (mask & A_CTS) ? MDM_ON : MDM_OFF;
822 	mc->mc_secrx = (mask & A_SECRX) ? MDM_ON : MDM_OFF;
823 	mc->mc_dtr = (mask & A_DTR) ? MDM_ON : MDM_OFF;
824 	mc->mc_rts = (mask & A_RTS) ? MDM_ON : MDM_OFF;
825 }
826 
827 mpcleanport(mb, port)
828 	struct mblok *mb;
829 	int port;
830 {
831 	register struct mpport *mp;
832 	register struct tty *tp;
833 
834 	mp = &mb->mb_port[port];
835 	if (mp->mp_proto == MPPROTO_ASYNC) {
836 		mp->mp_flags = MP_REMBSY;
837 		/* signal loss of carrier and close */
838 		tp = &mp_tty[mb->mb_unit*MPCHUNK+port];
839 		ttyflush(tp, FREAD|FWRITE);
840 		(void) (*linesw[tp->t_line].l_modem)(tp, 0);
841 	}
842 }
843 
844 mpclean(mb, port)
845 	register struct mblok *mb;
846 	int port;
847 {
848 	register struct mpport *mp;
849 	register struct mpevent *ev;
850 	register int i;
851 	u_char list[2];
852 	int unit;
853 
854 	mp = &mb->mb_port[port];
855 	unit = mb->mb_unit;
856 	for (i = mp->mp_off; i != mp->mp_on; i = (i+1 % MPINSET)) {
857 		ev = &mp->mp_recvq[i];
858 		ev->ev_error = ENXIO;
859 		ev->ev_status = EVSTATUS_DONE;
860 	}
861 	list[0] = port, list[1] = MPPORT_EOL;
862 	mpxintr(unit, list);
863 	mprintr(unit, list);
864 	/* Clear async for port */
865 	mp->mp_proto = MPPROTO_UNUSED;
866 	mp->mp_flags = 0;
867 	mp->mp_on = 0;
868 	mp->mp_off = 0;
869 	mp->mp_nextrcv = 0;
870 
871 	mp_tty[unit*MPCHUNK + port].t_state = 0;
872 	for (ev = &mp->mp_sendq[0]; ev < &mp->mp_sendq[MPOUTSET]; ev++) {
873 		ev->ev_status = EVSTATUS_FREE;
874 		ev->ev_cmd = 0;
875 		ev->ev_error = 0;
876 		ev->ev_un.rcvblk = 0;
877 		ev->ev_params = 0;
878 	}
879 	for (ev = &mp->mp_recvq[0]; ev < &mp->mp_recvq[MPINSET]; ev++) {
880 		ev->ev_status = EVSTATUS_FREE;
881 		ev->ev_cmd = 0;
882 		ev->ev_error = 0;
883 		ev->ev_params = 0;
884 	}
885 }
886 
887 /*
888  * MPCC interrupt handler.
889  */
890 mpintr(mpcc)
891 	int mpcc;
892 {
893 	register struct mblok *mb;
894 	register struct his *his;
895 
896 	mb = mp_softc[mpcc].ms_mb;
897 	if (mb == 0) {
898 		printf("mp%d: stray interrupt\n", mpcc);
899 		return;
900 	}
901 	his = &mb->mb_hostint;
902 	his->semaphore &= ~MPSEMA_AVAILABLE;
903 	/*
904 	 * Check for events to be processed.
905 	 */
906 	if (his->proto[MPPROTO_ASYNC].outbdone[0] != MPPORT_EOL)
907 		mprintr(mpcc, his->proto[MPPROTO_ASYNC].outbdone);
908 	if (his->proto[MPPROTO_ASYNC].inbdone[0] != MPPORT_EOL)
909 		mpxintr(mpcc, his->proto[MPPROTO_ASYNC].inbdone);
910 	if (mb->mb_harderr || mb->mb_softerr)
911 		mperror(mb, mpcc);
912 	his->semaphore |= MPSEMA_AVAILABLE;
913 }
914 
915 /*
916  * Handler for processing completion of transmitted events.
917  */
918 mpxintr(unit, list)
919 	register u_char *list;
920 {
921 	register struct mpport *mp;
922 	register struct mpevent *ev;
923 	register struct mblok *mb;
924 	register struct tty *tp;
925 	register struct asyncparam *ap;
926 	struct mpsoftc *ms;
927 	int port, i, j;
928 #	define nextevent(mp) &mp->mp_recvq[mp->mp_off]
929 
930 	ms = &mp_softc[unit];
931 	mb = mp_softc[unit].ms_mb;
932 	for (j = 0; j < MPMAXPORT && ((port = *list++) != MPPORT_EOL); j++) {
933 		/*
934 		 * Process each completed entry in the inbound queue.
935 		 */
936 		mp = &mb->mb_port[port];
937 		tp = &mp_tty[unit*MPCHUNK + port];
938 		ev = nextevent(mp);
939 		for (; ev->ev_status & EVSTATUS_DONE; ev = nextevent(mp)) {
940 			/* YUCK */
941 			ap = &ms->ms_async[port][mp->mp_off];
942 			mppurge((caddr_t)ap, (int)sizeof (*ap));
943 			switch (ev->ev_cmd) {
944 			case EVCMD_OPEN:
945 				/*
946 				 * Open completion, start all reads and
947 				 * assert modem status information.
948 				 */
949 				for (i = 0; i < MPOUTSET; i++)
950 					mp->mp_sendq[i].ev_status = EVSTATUS_GO;
951 				(*linesw[tp->t_line].l_modem)
952 				    (tp, ap->ap_modem.mc_dcd == ASSERT);
953 				mp_freein(ev);
954 				adjptr(mp->mp_off, MPINSET);
955 				mp->mp_proto = MPPROTO_ASYNC;	/* XXX */
956 				wakeup((caddr_t)&tp->t_canq);
957 				break;
958 			case EVCMD_CLOSE:
959 				/*
960 				 * Close completion, flush all pending
961 				 * transmissions, free resources, and
962 				 * cleanup mpcc port state.
963 				 */
964 				for (i = 0; i < MPOUTSET; i++) {
965 					mp->mp_sendq[i].ev_status =
966 					    EVSTATUS_FREE;
967 					mp->mp_sendq[i].ev_un.rcvblk = 0;
968 					mp->mp_sendq[i].ev_params = 0;
969 				}
970 				mp_freein(ev);
971 				adjptr(mp->mp_off, MPINSET);
972 				tp->t_state &= ~(TS_CARR_ON|TS_BUSY|TS_FLUSH);
973 				mp->mp_on = mp->mp_off = mp->mp_nextrcv = 0;
974 				mp->mp_flags &= ~MP_PROGRESS;
975 				mp->mp_proto = MPPROTO_UNUSED;
976 				wakeup((caddr_t)&tp->t_canq);
977 				break;
978 			case EVCMD_IOCTL:
979 				mp_freein(ev);
980 				adjptr(mp->mp_off, MPINSET);
981 				mp->mp_flags &= ~MP_IOCTL;
982 				wakeup((caddr_t)&tp->t_canq);
983 				break;
984 			case EVCMD_WRITE:
985 				/*
986 				 * Transmission completed, update tty
987 				 * state and restart output.
988 				 */
989 				if (ev->ev_opts != A_FLUSH) {
990 					tp->t_state &= ~TS_BUSY;
991 					if (tp->t_state & TS_FLUSH)
992 						tp->t_state &= ~TS_FLUSH;
993 					else {
994 						register int cc = 0, n;
995 						struct hxmtl *hxp;
996 
997 						hxp = &ms->ms_hxl[port];
998 						for (n=0;n < ev->ev_count; n++)
999 							cc += hxp->size[n];
1000 						ndflush(&tp->t_outq, cc);
1001 					}
1002 				}
1003 				switch (ev->ev_error) {
1004 				case A_SIZERR:  /*# error in xmt data size */
1005 					mplog(unit, port, A_XSIZE, 0);
1006 					break;
1007 				case A_NXBERR:  /*# no more xmt evt buffers */
1008 					mplog(unit, port, A_NOXBUF, 0);
1009 					break;
1010 				}
1011 				mp_freein(ev);
1012 				adjptr(mp->mp_off, MPINSET);
1013 				mpstart(tp);
1014 				break;
1015 			default:
1016 				mplog(unit, port, A_INVCMD, (int)ev->ev_cmd);
1017 				mp_freein(ev);
1018 				adjptr(mp->mp_off, MPINSET);
1019 				break;
1020 			}
1021 		}
1022 	}
1023 #undef	nextevent
1024 }
1025 
1026 mp_freein(ev)
1027 	register struct mpevent *ev;
1028 {
1029 	/* re-init all values in this entry */
1030 	ev->ev_cmd = 0;
1031 	ev->ev_opts = 0;
1032 	ev->ev_error = 0;
1033 	ev->ev_flags = 0;
1034 	ev->ev_count = 0;
1035 	/* show this entry is available for use */
1036 	ev->ev_status = EVSTATUS_FREE;
1037 }
1038 
1039 /*
1040  * Handler for processing received events.
1041  */
1042 mprintr(unit, list)
1043 	u_char *list;
1044 {
1045 	register struct tty *tp;
1046 	register struct mpport *mp;
1047 	register struct mpevent *ev;
1048 	struct mblok *mb;
1049 	register int cc;
1050 	register char *cp;
1051 	struct mpsoftc *ms;
1052 	caddr_t ptr;
1053 	char *rcverr;
1054 	int port, i;
1055 
1056 	ms = &mp_softc[unit];
1057 	mb = mp_softc[unit].ms_mb;
1058 	for (i = 0; i < MPMAXPORT && (port = *list++) != MPPORT_EOL; i++) {
1059 		tp = &mp_tty[unit*MPCHUNK + port];
1060 		mp = &mb->mb_port[port];
1061 		ev = &mp->mp_sendq[mp->mp_nextrcv];
1062 		while (ev->ev_status & EVSTATUS_DONE) {
1063 			switch(ev->ev_cmd) {
1064 			case EVCMD_STATUS:
1065 				/*
1066 				 * Status change, look for carrier changes.
1067 				 */
1068 				switch(ev->ev_opts) {
1069 				case DCDASRT:
1070 					(*linesw[tp->t_line].l_modem)(tp, 1);
1071 					wakeup((caddr_t)&tp->t_canq);
1072 					break;
1073 				case DCDDROP:
1074 					(*linesw[tp->t_line].l_modem)(tp, 0);
1075 					wakeup((caddr_t)&tp->t_canq);
1076 					break;
1077 				case NORBUF:
1078 				case NOEBUF:
1079 					mplog(unit, port,
1080 					    "out of receive events", 0);
1081 					break;
1082 				default:
1083 					mplog(unit, port,
1084 					    "unexpect status command",
1085 					    (int)ev->ev_opts);
1086 					break;
1087 				}
1088 				break;
1089 			case EVCMD_READ:
1090 				/*
1091 			 	 * Process received data.
1092 			 	 */
1093 				if ((tp->t_state & TS_ISOPEN) == 0) {
1094 					wakeup((caddr_t)&tp->t_rawq);
1095 					break;
1096 				}
1097 				if ((cc = ev->ev_count) == 0)
1098 					break;
1099 				cp = ms->ms_cbuf[port][mp->mp_nextrcv];
1100 				mppurge(cp, CBSIZE);
1101 				while (cc-- > 0) {
1102 					/*
1103 				 	 * A null character is inserted,
1104 					 * potentially when a break or framing
1105 					 * error occurs. If we're not in raw
1106 					 * mode, substitute the interrupt
1107 					 * character.
1108 				 	 */
1109 					/*** XXX - FIXUP ***/
1110 					if (*cp == 0 &&
1111 				            (ev->ev_error == BRKASRT ||
1112 				             ev->ev_error == FRAMERR))
1113 						if ((tp->t_flags&RAW) == 0)
1114 							;
1115 							/* XXX was break */
1116 					(*linesw[tp->t_line].l_rint)(*cp++, tp);
1117 				}
1118 				/* setup for next read */
1119 				ptr = (caddr_t)&mp_softc[unit].ms_cbuf[port][mp->mp_nextrcv][0];
1120 				ev->ev_un.rcvblk = (u_char *)kvtophys(ptr);
1121 				ev->ev_params = (caddr_t) kvtophys(ptr);
1122 				switch(ev->ev_error) {
1123 				case RCVDTA:
1124 					/* Normal (good) rcv data do not
1125 					 * report the following they are
1126 					 * "normal" errors
1127 					 */
1128 				case FRAMERR:
1129 					/* frame error */
1130 				case BRKASRT:
1131 					/* Break condition */
1132 				case PARERR:
1133 					/* parity error */
1134 					rcverr = (char *)0;
1135 					break;
1136 				case OVRNERR:
1137 					/* Overrun error */
1138 					rcverr = "overrun error";
1139 					break;
1140 				case OVFERR:
1141 					/* Overflow error */
1142 					rcverr = "overflow error";
1143 					break;
1144 				default:
1145 					rcverr = "undefined rcv error";
1146 					break;
1147 				}
1148 				if (rcverr != (char *)0)
1149 					mplog(unit, port, rcverr,
1150 					      (int)ev->ev_error);
1151 				break;
1152 			default:
1153 				mplog(unit, port, "unexpected command",
1154 					(int)ev->ev_cmd);
1155 				break;
1156 			}
1157 			ev->ev_cmd = 0;
1158 			ev->ev_opts = 0;
1159 			ev->ev_error = 0;
1160 			ev->ev_flags = 0;
1161 			ev->ev_count = 0;
1162 			ev->ev_status = EVSTATUS_GO;	/* start next read */
1163 			adjptr(mp->mp_nextrcv, MPOUTSET);
1164 			ev = &mp->mp_sendq[mp->mp_nextrcv];
1165 		}
1166 	}
1167 }
1168 
1169 /*
1170  * Log an mpcc diagnostic.
1171  */
1172 mplog(unit, port, cp, flags)
1173 	char *cp;
1174 {
1175 
1176 	if (flags)
1177 		log(LOG_ERR, "mp%d: port%d, %s (%d)\n",
1178 		    unit, port, cp, flags);
1179 	else
1180 		log(LOG_ERR, "mp%d: port%d, %s\n", unit, port, cp);
1181 }
1182 
1183 int	MPHOSTINT = 1;
1184 
1185 mptimeint(mb)
1186 	register struct mblok *mb;
1187 {
1188 
1189         mb->mb_mpintcnt = 0;
1190         mb->mb_mpintclk = (caddr_t)0;
1191 	*(u_short *)mpinfo[mb->mb_unit]->ui_addr = 2;
1192 }
1193 
1194 /*
1195  * Interupt mpcc
1196  */
1197 mpintmpcc(mb, port)
1198 	register struct mblok *mb;
1199 {
1200 
1201         mb->mb_intr[port] |= MPSEMA_WORK;
1202         if (++mb->mb_mpintcnt == MPHOSTINT) {
1203                 mb->mb_mpintcnt = 0;
1204 		*(u_short *)mpinfo[mb->mb_unit]->ui_addr = 2;
1205                 if (mb->mb_mpintclk) {
1206                         untimeout(mptimeint, (caddr_t)mb);
1207                         mb->mb_mpintclk = 0;
1208                 }
1209         } else {
1210                 if (mb->mb_mpintclk == 0) {
1211                         timeout(mptimeint, (caddr_t)mb, 4);
1212                         mb->mb_mpintclk = (caddr_t)1;
1213                 }
1214         }
1215 }
1216 
1217 static char *mpherrmsg[] = {
1218 	"",
1219 	"Bus error",				/* MPBUSERR */
1220 	"Address error",			/* ADDRERR */
1221 	"Undefined ecc interrupt",		/* UNDECC */
1222 	"Undefined interrupt",			/* UNDINT */
1223 	"Power failure occurred",		/* PWRFL */
1224 	"Stray transmit done interrupt",	/* NOXENTRY */
1225 	"Two fast timers on one port",		/* TWOFTMRS */
1226 	"Interrupt queue full",			/* INTQFULL */
1227 	"Interrupt queue ack error",		/* INTQERR */
1228 	"Uncorrectable dma parity error",	/* CBPERR */
1229 	"32 port ACAP failed power up",		/* ACPDEAD */
1230 };
1231 #define	NHERRS	(sizeof (mpherrmsg) / sizeof (mpherrmsg[0]))
1232 
1233 mperror(mb, unit)
1234 	register struct mblok *mb;
1235 	int unit;
1236 {
1237 	register char *cp;
1238 	register int i;
1239 
1240 	if (mb->mb_softerr) {
1241 		switch (mb->mb_softerr) {
1242 		case DMAPERR:   /* dma parity error */
1243 			cp = "dma parity error";
1244 			break;
1245 		case ECCERR:
1246 			cp = "local memory ecc error";
1247 			break;
1248 		default:
1249 			cp = "unknown error";
1250 			break;
1251 		}
1252 		log(LOG_ERR, "mp%d: soft error, %s", unit, cp);
1253 		mb->mb_softerr = 0;
1254 	}
1255 	if (mb->mb_harderr) {
1256 		if (mb->mb_harderr < NHERRS)
1257 			cp = mpherrmsg[mb->mb_harderr];
1258 		else
1259 			cp = "unknown error";
1260 		log(LOG_ERR, "mp%d: hard error, %s", unit, cp);
1261 		if (mb->mb_status == MP_OPOPEN) {
1262 			for (i = 0; i < MPMAXPORT; i++) {
1263 				mpcleanport(mb, i);
1264 				mb->mb_proto[i] = MPPROTO_UNUSED;
1265 			}
1266 		}
1267 		mb->mb_harderr = 0;
1268 		mb->mb_status = 0;
1269 	}
1270 }
1271 
1272 mppurge(addr, cc)
1273 	register caddr_t addr;
1274 	register int cc;
1275 {
1276 
1277 	for (; cc >= 0; addr += NBPG, cc -= NBPG)
1278 		mtpr(P1DC, addr);
1279 }
1280 
1281 /*
1282  * MPCC Download Pseudo-device.
1283  */
1284 char	mpdlbuf[MPDLBUFSIZE];
1285 int	mpdlbusy;		/* interlock on download buffer */
1286 int	mpdlerr;
1287 
1288 mpdlopen(dev)
1289 	dev_t dev;
1290 {
1291 	int unit, mpu;
1292 	struct vba_device *vi;
1293 
1294 	unit = minor(dev);
1295 	mpu = MPUNIT(unit);
1296 	if (mpu >= NMP || (vi = mpinfo[mpu]) == 0 || vi->ui_alive == 0)
1297 		return (ENODEV);
1298 	return (0);
1299 }
1300 
1301 mpdlwrite(dev, uio)
1302 	dev_t dev;
1303 	struct uio *uio;
1304 {
1305 	register struct mpsoftc *ms = &mp_softc[MPUNIT(minor(dev))];
1306 	register struct mpdl *dl;
1307 	int error;
1308 
1309 	if (ms->ms_mb == 0 || ms->ms_mb->mb_status != MP_DLOPEN)
1310 		return (EFAULT);
1311 	dl = &ms->ms_mb->mb_dl;
1312 	dl->mpdl_count = uio->uio_iov->iov_len;
1313 	dl->mpdl_data = (caddr_t) kvtophys(mpdlbuf);
1314 	if (error = uiomove(mpdlbuf, (int)dl->mpdl_count, UIO_WRITE, uio))
1315 		return (error);
1316 	uio->uio_resid -= dl->mpdl_count;    /* set up return from write */
1317 	dl->mpdl_cmd = MPDLCMD_NORMAL;
1318 	error = mpdlwait(dl);
1319 	return (error);
1320 }
1321 
1322 mpdlclose(dev)
1323 	dev_t dev;
1324 {
1325 	register struct mblok *mb = mp_softc[MPUNIT(minor(dev))].ms_mb;
1326 
1327 	if (mb == 0 || mb->mb_status != MP_DLDONE) {
1328 		mpbogus.status = 0;
1329 		if (mpbogus.mb == mpbogus.mbloks[MPUNIT(minor(dev))])
1330 			mpdlbusy--;
1331 		return (EEXIST);
1332 	}
1333 	mb->mb_status = MP_OPOPEN;
1334 	mpbogus.status = 0;
1335 	/* set to dead, for board handshake */
1336 	mb->mb_hostint.imok = MPIMOK_DEAD;
1337 	return (0);
1338 }
1339 
1340 int	mpdltimeout();
1341 
1342 /* ARGSUSED */
1343 mpdlioctl(dev, cmd, data, flag)
1344 	dev_t dev;
1345 	caddr_t data;
1346 {
1347 	register struct mblok *mb;
1348 	register struct mpdl *dl;
1349 	int unit, error, s, i;
1350 
1351 	mb = mp_softc[unit=MPUNIT(minor(dev))].ms_mb;
1352 	if (mb == 0)
1353 		return (EEXIST);
1354 	dl = &mb->mb_dl;
1355 	error = 0;
1356 	switch (cmd) {
1357 	case MPIOPORTMAP:
1358 		bcopy(data, (caddr_t)mb->mb_proto, sizeof (mb->mb_proto));
1359 		break;
1360 	case MPIOHILO:
1361 		bcopy(data, (caddr_t)&mb->mb_hiport, 2*(sizeof(mb->mb_hiport)));
1362 		break;
1363 	case MPIOENDDL:
1364 		dl->mpdl_count = 0;
1365 		dl->mpdl_data = 0;
1366 		dl->mpdl_cmd = MPIOENDDL&IOCPARM_MASK;
1367 		error = mpdlwait(dl);
1368 		mpccinit(unit);
1369 		mb->mb_status = MP_DLDONE;
1370 		mpdlbusy--;
1371 		break;
1372 	case MPIOENDCODE:
1373 		dl->mpdl_count = 0;
1374 		dl->mpdl_data = 0;
1375 		dl->mpdl_cmd = MPIOENDCODE&IOCPARM_MASK;
1376 		error = mpdlwait(dl);
1377 		break;
1378 	case MPIOASYNCNF:
1379 		bcopy(data, mpdlbuf, sizeof (struct abdcf));
1380 		dl->mpdl_data = (caddr_t) kvtophys(mpdlbuf);
1381 		dl->mpdl_count = sizeof (struct abdcf);
1382 		dl->mpdl_cmd = MPIOASYNCNF&IOCPARM_MASK;
1383 		error = mpdlwait(dl);
1384 		break;
1385 	case MPIOSTARTDL:
1386 		while (mpdlbusy)
1387 			sleep((caddr_t)&mpdlbusy, PZERO+1);
1388 		mpdlbusy++;
1389 		/* initialize the downloading interface */
1390 		mpbogus.magic = MPMAGIC;
1391 		mpbogus.mb = mpbogus.mbloks[unit];
1392 		mpbogus.status = 1;
1393 		dl->mpdl_status = EVSTATUS_FREE;
1394 		dl->mpdl_count = 0;
1395 		dl->mpdl_cmd = 0;
1396 		dl->mpdl_data = (char *) 0;
1397 		mpdlerr = 0;
1398 		mb->mb_magic = MPMAGIC;
1399         	mb->mb_ivec = mp_softc[unit].ms_ivec+1;	/* download vector */
1400 		mb->mb_status = MP_DLPEND;
1401 		mb->mb_diagswitch[0] = 'A';
1402 		mb->mb_diagswitch[1] = 'P';
1403 		s = spl8();
1404 		*(u_short *)mpinfo[unit]->ui_addr = 2;
1405 		timeout(mpdltimeout, (caddr_t)mb, 30*hz);
1406 		sleep((caddr_t)&mb->mb_status, PZERO+1);
1407 		splx(s);
1408 		if (mb->mb_status == MP_DLOPEN) {
1409 			untimeout(mpdltimeout, (caddr_t)mb);
1410 		} else if (mb->mb_status == MP_DLTIME) {
1411 			mpbogus.status = 0;
1412 			error = ETIMEDOUT;
1413 		} else {
1414 			mpbogus.status = 0;
1415 			error = ENXIO;
1416 			log(LOG_ERR, "mp%d: start download: unknown status %x",
1417 			    unit, mb->mb_status);
1418 		}
1419 		bzero((caddr_t)mb->mb_port, sizeof (mb->mb_port));
1420 		break;
1421 	case MPIORESETBOARD:
1422 		s = spl8();
1423 		if (mb->mb_imokclk)
1424 			mb->mb_imokclk = 0;
1425 		*(u_short *)mpinfo[unit]->ui_addr = 0x100;
1426 		if (mb->mb_status == MP_DLOPEN || mb->mb_status == MP_DLDONE) {
1427 			mpdlerr = MP_DLERROR;
1428 			dl->mpdl_status = EVSTATUS_FREE;
1429 			wakeup((caddr_t)&dl->mpdl_status);
1430 			mpbogus.status = 0;
1431 		}
1432 		for (i = 0; i < MPMAXPORT; i++) {
1433 			if (mb->mb_harderr || mb->mb_softerr)
1434 				mperror(mb, i);
1435 			mpcleanport(mb, i);
1436 			mb->mb_proto[i] = MPPROTO_UNUSED;
1437 		}
1438 		mb->mb_status = 0;
1439 		splx(s);
1440 		break;
1441 	default:
1442 		error = EINVAL;
1443 		break;
1444 	}
1445 	return (error);
1446 }
1447 
1448 mpccinit(unit)
1449 	int unit;
1450 {
1451         register struct mblok *mb = mp_softc[unit].ms_mb;
1452         register struct his *his;
1453         register int i, j;
1454 
1455         mb->mb_status = MP_DLDONE;
1456         mb->mb_ivec = mp_softc[unit].ms_ivec;
1457         mb->mb_magic = MPMAGIC;
1458         /* Init host interface structure */
1459         his = &mb->mb_hostint;
1460         his->semaphore = MPSEMA_AVAILABLE;
1461         for (i = 0; i < NMPPROTO; i++)
1462                 for (j = 0; j < MPMAXPORT; j++) {
1463                         his->proto[i].inbdone[j] = MPPORT_EOL;
1464                         his->proto[i].outbdone[j] = MPPORT_EOL;
1465                 }
1466         mb->mb_unit = unit;
1467 }
1468 
1469 mpdlintr(mpcc)
1470 	int mpcc;
1471 {
1472 	register struct mblok *mb;
1473 	register struct mpdl *dl;
1474 
1475 	mb = mp_softc[mpcc].ms_mb;
1476 	if (mb == 0) {
1477 		printf("mp%d: stray download interrupt\n", mpcc);
1478 		return;
1479 	}
1480 	dl = &mb->mb_dl;
1481 	switch (mb->mb_status) {
1482 	case MP_DLOPEN:
1483 		if (dl->mpdl_status != EVSTATUS_DONE)
1484 			mpdlerr = MP_DLERROR;
1485 		dl->mpdl_status = EVSTATUS_FREE;
1486 		wakeup((caddr_t)&dl->mpdl_status);
1487 		return;
1488 	case MP_DLPEND:
1489 		mb->mb_status = MP_DLOPEN;
1490 		wakeup((caddr_t)&mb->mb_status);
1491 		/* fall thru... */
1492 	case MP_DLTIME:
1493 		return;
1494 	case MP_OPOPEN:
1495 		if (mb->mb_imokclk)
1496 			mb->mb_imokclk = 0;
1497 		mb->mb_nointcnt = 0;		/* reset no interrupt count */
1498 		mb->mb_hostint.imok = MPIMOK_DEAD;
1499 		mb->mb_imokclk = (caddr_t)1;
1500 		break;
1501 	default:
1502 		log(LOG_ERR, "mp%d: mpdlintr, status %x\n",
1503 		    mpcc, mb->mb_status);
1504 		break;
1505 	}
1506 }
1507 
1508 mpdltimeout(mp)
1509 	struct mblok *mp;
1510 {
1511 
1512 	mp->mb_status = MP_DLTIME;
1513 	wakeup((caddr_t)&mp->mb_status);
1514 }
1515 
1516 /*
1517  * Wait for a transfer to complete or a timeout to occur.
1518  */
1519 mpdlwait(dl)
1520 	register struct mpdl *dl;
1521 {
1522 	int s, error = 0;
1523 
1524 	s = spl8();
1525 	dl->mpdl_status = EVSTATUS_GO;
1526 	while (dl->mpdl_status != EVSTATUS_FREE) {
1527 		sleep((caddr_t)&dl->mpdl_status, PZERO+1);
1528 		if (mpdlerr == MP_DLERROR)
1529 			error = EIO;
1530 	}
1531 	splx(s);
1532 	return (error);
1533 }
1534 #endif
1535