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