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