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