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