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