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