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