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