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