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