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