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