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