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