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 * @(#)if_dmv.c 7.6 (Berkeley) 10/12/88 18 */ 19 20 /* 21 * DMV-11 Driver 22 * 23 * Qbus Sync DDCMP interface - DMV operated in full duplex, point to point mode 24 * 25 * Written by Bob Kridle of Mt Xinu 26 * starting from if_dmc.c version 6.12 dated 4/23/86 27 */ 28 29 #include "dmv.h" 30 #if NDMV > 0 31 32 #include "param.h" 33 #include "systm.h" 34 #include "mbuf.h" 35 #include "buf.h" 36 #include "ioctl.h" /* must precede tty.h */ 37 #include "tty.h" 38 #include "protosw.h" 39 #include "socket.h" 40 #include "syslog.h" 41 #include "vmmac.h" 42 #include "errno.h" 43 #include "time.h" 44 #include "kernel.h" 45 46 #include "../net/if.h" 47 #include "../net/netisr.h" 48 #include "../net/route.h" 49 50 #ifdef INET 51 #include "../netinet/in.h" 52 #include "../netinet/in_systm.h" 53 #include "../netinet/in_var.h" 54 #include "../netinet/ip.h" 55 #endif 56 57 #include "../vax/cpu.h" 58 #include "../vax/mtpr.h" 59 #include "../vax/pte.h" 60 #include "../vaxuba/ubareg.h" 61 #include "../vaxuba/ubavar.h" 62 #include "if_uba.h" 63 #include "if_dmv.h" 64 65 int dmv_timeout = 8; /* timeout value */ 66 67 /* 68 * Driver information for auto-configuration stuff. 69 */ 70 int dmvprobe(), dmvattach(), dmvinit(), dmvioctl(); 71 int dmvoutput(), dmvreset(), dmvtimeout(); 72 struct uba_device *dmvinfo[NDMV]; 73 u_short dmvstd[] = { 0 }; 74 struct uba_driver dmvdriver = 75 { dmvprobe, 0, dmvattach, 0, dmvstd, "dmv", dmvinfo }; 76 77 /* 78 * Don't really know how many buffers/commands can be queued to a DMV-11. 79 * Manual doesn't say... Perhaps we can look at a DEC driver some day. 80 * These numbers ame from DMC/DMR driver. 81 */ 82 #define NRCV 5 83 #define NXMT 3 84 #define NCMDS (NRCV+NXMT+4) /* size of command queue */ 85 86 #ifdef DEBUG 87 #define printd(f) if (sc->sc_if.if_flags & IFF_DEBUG) \ 88 printf("DMVDEBUG: dmv%d: ", unit), printf(f) 89 #else 90 #define printd(f) /* nil */ 91 #endif 92 93 /* error reporting intervals */ 94 95 #define DMV_RPRTE 1 96 #define DMV_RPTTE 1 97 #define DMV_RPSTE 1 98 #define DMV_RPNXM 1 99 #define DMV_RPMODD 1 100 #define DMV_RPQOVF 1 101 #define DMV_RPCXRL 1 102 103 /* number of errors to accept before trying a reset */ 104 #define DMV_RPUNKNOWN 10 105 106 struct dmv_command { 107 u_char qp_mask; /* Which registers to set up */ 108 #define QP_TRIB 0x01 109 #define QP_SEL4 0x02 110 #define QP_SEL6 0x04 111 #define QP_SEL10 0x08 112 u_char qp_cmd; 113 u_char qp_tributary; 114 u_short qp_sel4; 115 u_short qp_sel6; 116 u_short qp_sel10; 117 struct dmv_command *qp_next; /* next command on queue */ 118 }; 119 120 #define qp_lowbufaddr qp_ 121 122 struct dmvbufs { 123 int ubinfo; /* from uballoc */ 124 short cc; /* buffer size */ 125 short flags; /* access control */ 126 }; 127 128 #define DBUF_OURS 0 /* buffer is available */ 129 #define DBUF_DMVS 1 /* buffer claimed by somebody */ 130 #define DBUF_XMIT 4 /* transmit buffer */ 131 #define DBUF_RCV 8 /* receive buffer */ 132 133 134 /* 135 * DMV software status per interface. 136 * 137 * Each interface is referenced by a network interface structure, 138 * sc_if, which the routing code uses to locate the interface. 139 * This structure contains the output queue for the interface, its address, ... 140 * We also have, for each interface, a set of 7 UBA interface structures 141 * for each, which 142 * contain information about the UNIBUS resources held by the interface: 143 * map registers, buffered data paths, etc. Information is cached in this 144 * structure for use by the if_uba.c routines in running the interface 145 * efficiently. 146 */ 147 struct dmv_softc { 148 struct ifnet sc_if; /* network-visible interface */ 149 short sc_oused; /* output buffers currently in use */ 150 short sc_iused; /* input buffers given to DMV */ 151 short sc_flag; /* flags */ 152 int sc_ubinfo; /* UBA mapping info for base table */ 153 int sc_errors[8]; /* error counters */ 154 #define sc_rte sc_errors[0] /* receive threshhold error */ 155 #define sc_xte sc_errors[1] /* xmit threshhold error */ 156 #define sc_ste sc_errors[2] /* select threshhold error */ 157 #define sc_nxm sc_errors[3] /* non-existant memory */ 158 #define sc_modd sc_errors[4] /* modem disconnect */ 159 #define sc_qovf sc_errors[5] /* command/response queue overflow */ 160 #define sc_cxrl sc_errors[6] /* carrier loss */ 161 #define sc_unknown sc_errors[7] /* other errors - look in DMV manual */ 162 struct dmvbufs sc_rbufs[NRCV]; /* receive buffer info */ 163 struct dmvbufs sc_xbufs[NXMT]; /* transmit buffer info */ 164 struct ifubinfo sc_ifuba; /* UNIBUS resources */ 165 struct ifrw sc_ifr[NRCV]; /* UNIBUS receive buffer maps */ 166 struct ifxmt sc_ifw[NXMT]; /* UNIBUS receive buffer maps */ 167 /* command queue stuff */ 168 struct dmv_command sc_cmdbuf[NCMDS]; 169 struct dmv_command *sc_qhead; /* head of command queue */ 170 struct dmv_command *sc_qtail; /* tail of command queue */ 171 struct dmv_command *sc_qactive; /* command in progress */ 172 struct dmv_command *sc_qfreeh; /* head of list of free cmd buffers */ 173 struct dmv_command *sc_qfreet; /* tail of list of free cmd buffers */ 174 /* end command queue stuff */ 175 } dmv_softc[NDMV]; 176 177 /* flags */ 178 #define DMV_RESTART 0x01 /* software restart in progress */ 179 #define DMV_ONLINE 0x02 /* device managed to transmit */ 180 #define DMV_RUNNING 0x04 /* device initialized */ 181 182 183 /* queue manipulation macros */ 184 #define QUEUE_AT_HEAD(qp, head, tail) \ 185 (qp)->qp_next = (head); \ 186 (head) = (qp); \ 187 if ((tail) == (struct dmv_command *) 0) \ 188 (tail) = (head) 189 190 #define QUEUE_AT_TAIL(qp, head, tail) \ 191 if ((tail)) \ 192 (tail)->qp_next = (qp); \ 193 else \ 194 (head) = (qp); \ 195 (qp)->qp_next = (struct dmv_command *) 0; \ 196 (tail) = (qp) 197 198 #define DEQUEUE(head, tail) \ 199 (head) = (head)->qp_next;\ 200 if ((head) == (struct dmv_command *) 0)\ 201 (tail) = (head) 202 203 dmvprobe(reg) 204 caddr_t reg; 205 { 206 register int br, cvec; 207 register struct dmvdevice *addr = (struct dmvdevice *)reg; 208 register int i; 209 210 #ifdef lint 211 br = 0; cvec = br; br = cvec; 212 dmvrint(0); dmvxint(0); 213 #endif 214 addr->bsel1 = DMV_MCLR; 215 for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) 216 ; 217 if ((addr->bsel1 & DMV_RUN) == 0) { 218 printf("dmvprobe: can't start device\n" ); 219 return (0); 220 } 221 if ((addr->bsel4 != 033) || (addr->bsel6 != 0305)) 222 { 223 printf("dmvprobe: device init failed, bsel4=%o, bsel6=%o\n", 224 addr->bsel4, addr->bsel6); 225 return (0); 226 } 227 addr->bsel0 = DMV_RQI|DMV_IEI|DMV_IEO; 228 DELAY(1000000); 229 addr->bsel1 = DMV_MCLR; 230 for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) 231 ; 232 br = 0x15; /* screwy interrupt structure */ 233 return (1); 234 } 235 236 /* 237 * Interface exists: make available by filling in network interface 238 * record. System will initialize the interface when it is ready 239 * to accept packets. 240 */ 241 dmvattach(ui) 242 register struct uba_device *ui; 243 { 244 register struct dmv_softc *sc = &dmv_softc[ui->ui_unit]; 245 246 sc->sc_if.if_unit = ui->ui_unit; 247 sc->sc_if.if_name = "dmv"; 248 sc->sc_if.if_mtu = DMVMTU; 249 sc->sc_if.if_init = dmvinit; 250 sc->sc_if.if_output = dmvoutput; 251 sc->sc_if.if_ioctl = dmvioctl; 252 sc->sc_if.if_reset = dmvreset; 253 sc->sc_if.if_watchdog = dmvtimeout; 254 sc->sc_if.if_flags = IFF_POINTOPOINT; 255 sc->sc_ifuba.iff_flags = UBA_CANTWAIT; 256 257 if_attach(&sc->sc_if); 258 } 259 260 /* 261 * Reset of interface after UNIBUS reset. 262 * If interface is on specified UBA, reset its state. 263 */ 264 dmvreset(unit, uban) 265 int unit, uban; 266 { 267 register struct uba_device *ui; 268 register struct dmv_softc *sc = &dmv_softc[unit]; 269 270 if (unit >= NDMV || (ui = dmvinfo[unit]) == 0 || ui->ui_alive == 0 || 271 ui->ui_ubanum != uban) 272 return; 273 printf(" dmv%d", unit); 274 sc->sc_flag = 0; 275 sc->sc_if.if_flags &= ~IFF_RUNNING; 276 dmvinit(unit); 277 } 278 279 /* 280 * Initialization of interface; reinitialize UNIBUS usage. 281 */ 282 dmvinit(unit) 283 int unit; 284 { 285 register struct dmv_softc *sc = &dmv_softc[unit]; 286 register struct uba_device *ui = dmvinfo[unit]; 287 register struct dmvdevice *addr; 288 register struct ifnet *ifp = &sc->sc_if; 289 register struct ifrw *ifrw; 290 register struct ifxmt *ifxp; 291 register struct dmvbufs *rp; 292 register struct dmv_command *qp; 293 struct ifaddr *ifa; 294 int base; 295 int s; 296 297 addr = (struct dmvdevice *)ui->ui_addr; 298 299 /* 300 * Check to see that an address has been set 301 * (both local and destination for an address family). 302 */ 303 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 304 if (ifa->ifa_addr.sa_family && ifa->ifa_dstaddr.sa_family) 305 break; 306 if (ifa == (struct ifaddr *) 0) 307 return; 308 309 if ((addr->bsel1&DMV_RUN) == 0) { 310 log(LOG_CRIT, "dmvinit: dmv%d not running\n", unit); 311 ifp->if_flags &= ~IFF_UP; 312 return; 313 } 314 printd(("dmvinit\n")); 315 /* initialize UNIBUS resources */ 316 sc->sc_iused = sc->sc_oused = 0; 317 if ((ifp->if_flags & IFF_RUNNING) == 0) { 318 if (if_ubaminit( 319 &sc->sc_ifuba, 320 ui->ui_ubanum, 321 sizeof(struct dmv_header), 322 (int)btoc(DMVMTU), 323 sc->sc_ifr, 324 NRCV, 325 sc->sc_ifw, 326 NXMT 327 ) == 0) { 328 log(LOG_CRIT, "dmvinit: dmv%d can't allocate uba resources\n", unit); 329 ifp->if_flags &= ~IFF_UP; 330 return; 331 } 332 ifp->if_flags |= IFF_RUNNING; 333 } 334 /* 335 * Limit packets enqueued until we see if we're on the air. 336 */ 337 ifp->if_snd.ifq_maxlen = 3; 338 339 340 /* initialize buffer pool */ 341 /* receives */ 342 ifrw = &sc->sc_ifr[0]; 343 for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 344 rp->ubinfo = ifrw->ifrw_info & 0x3ffff; 345 rp->cc = DMVMTU + sizeof (struct dmv_header); 346 rp->flags = DBUF_OURS|DBUF_RCV; 347 ifrw++; 348 } 349 /* transmits */ 350 ifxp = &sc->sc_ifw[0]; 351 for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { 352 rp->ubinfo = ifxp->ifw_info & 0x3ffff; 353 rp->cc = 0; 354 rp->flags = DBUF_OURS|DBUF_XMIT; 355 ifxp++; 356 } 357 358 /* set up command queues */ 359 sc->sc_qfreeh = sc->sc_qfreet 360 = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive = 361 (struct dmv_command *)0; 362 /* set up free command buffer list */ 363 for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) { 364 QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); 365 } 366 if(sc->sc_flag & DMV_RUNNING) 367 dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQHS,0); 368 else 369 dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_ESTTRIB,0); 370 dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQSUS,0); 371 sc->sc_flag |= (DMV_RESTART|DMV_RUNNING); 372 sc->sc_flag &= ~DMV_ONLINE; 373 addr->bsel0 |= DMV_IEO; 374 } 375 376 /* 377 * Start output on interface. Get another datagram 378 * to send from the interface queue and map it to 379 * the interface before starting output. 380 * 381 * Must be called at spl 5 382 */ 383 dmvstart(dev) 384 dev_t dev; 385 { 386 int unit = minor(dev); 387 register struct dmv_softc *sc = &dmv_softc[unit]; 388 struct mbuf *m; 389 register struct dmvbufs *rp; 390 register int n; 391 392 /* 393 * Dequeue up to NXMT requests and map them to the UNIBUS. 394 * If no more requests, or no dmv buffers available, just return. 395 */ 396 printd(("dmvstart\n")); 397 n = 0; 398 for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) { 399 /* find an available buffer */ 400 if ((rp->flags & DBUF_DMVS) == 0) { 401 IF_DEQUEUE(&sc->sc_if.if_snd, m); 402 if (m == 0) 403 return; 404 /* mark it dmvs */ 405 rp->flags |= (DBUF_DMVS); 406 /* 407 * Have request mapped to UNIBUS for transmission 408 * and start the output. 409 */ 410 rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m); 411 if (++sc->sc_oused == 1) 412 sc->sc_if.if_timer = dmv_timeout; 413 dmvload( 414 sc, 415 DMV_BACCX, 416 QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10, 417 1, 418 rp->ubinfo, 419 (rp->ubinfo>>16)&0x3f, 420 rp->cc 421 ); 422 } 423 n++; 424 } 425 } 426 427 /* 428 * Utility routine to load the DMV device registers. 429 */ 430 dmvload(sc, cmd, mask, tributary, sel4, sel6, sel10) 431 register struct dmv_softc *sc; 432 u_char cmd, tributary, mask; 433 u_short sel4, sel6, sel10; 434 { 435 register struct dmvdevice *addr; 436 register int unit, sps; 437 register struct dmv_command *qp; 438 439 unit = sc - dmv_softc; 440 printd(("dmvload: cmd=%x mask=%x trib=%x sel4=%x sel6=%x sel10=%x\n", 441 (unsigned) cmd, 442 (unsigned) mask, 443 (unsigned) tributary, 444 (unsigned) sel4, 445 (unsigned) sel6, 446 (unsigned) sel10 447 )); 448 addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr; 449 sps = spl5(); 450 451 /* grab a command buffer from the free list */ 452 if ((qp = sc->sc_qfreeh) == (struct dmv_command *)0) 453 panic("dmv command queue overflow"); 454 DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet); 455 456 /* fill in requested info */ 457 qp->qp_cmd = cmd; 458 qp->qp_mask = mask; 459 qp->qp_tributary = tributary; 460 qp->qp_sel4 = sel4; 461 qp->qp_sel6 = sel6; 462 qp->qp_sel10 = sel10; 463 464 if (sc->sc_qactive) { /* command in progress */ 465 if (cmd == DMV_BACCR) { /* supply read buffers first */ 466 QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail); 467 } else { 468 QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail); 469 } 470 } else { /* command port free */ 471 sc->sc_qactive = qp; 472 addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO); 473 } 474 splx(sps); 475 } 476 /* 477 * DMV interface input interrupt. 478 * Ready to accept another command, 479 * pull one off the command queue. 480 */ 481 dmvrint(unit) 482 int unit; 483 { 484 register struct dmv_softc *sc; 485 register struct dmvdevice *addr; 486 register struct dmv_command *qp; 487 register int n; 488 489 addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr; 490 sc = &dmv_softc[unit]; 491 printd(("dmvrint\n")); 492 if ((qp = sc->sc_qactive) == (struct dmv_command *) 0) { 493 log(LOG_WARNING, "dmvrint: dmv%d no command\n", unit); 494 return; 495 } 496 while (addr->bsel2&DMV_RDI) { 497 if(qp->qp_mask&QP_SEL4) 498 addr->wsel4 = qp->qp_sel4; 499 if(qp->qp_mask&QP_SEL6) 500 addr->wsel6 = qp->qp_sel6; 501 if(qp->qp_mask&QP_SEL10) { 502 addr->wsel10 = qp->qp_sel10; 503 qp->qp_cmd |= DMV_22BIT; 504 } 505 if(qp->qp_mask&QP_TRIB) 506 addr->wsel2 = qp->qp_cmd|(qp->qp_tributary << 8); 507 else 508 addr->bsel2 = qp->qp_cmd; 509 QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); 510 if ((sc->sc_qactive = sc->sc_qhead) == (struct dmv_command *)0) 511 break; 512 qp = sc->sc_qactive; 513 DEQUEUE(sc->sc_qhead, sc->sc_qtail); 514 if (addr->bsel2&DMV_RDO) 515 break; 516 } 517 if (!sc->sc_qactive) { 518 if(addr->bsel2&DMV_RDI) { 519 /* clear RQI prior to last command per DMV manual */ 520 addr->bsel0 &= ~DMV_RQI; 521 addr->wsel6 = DMV_NOP; 522 addr->bsel2 = DMV_CNTRLI; 523 } 524 addr->bsel0 = DMV_IEO; 525 } 526 else /* RDO set or DMV still holding CSR */ 527 addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO); 528 529 } 530 531 /* 532 * DMV interface output interrupt. 533 * A transfer may have completed, check for errors. 534 * If it was a read, notify appropriate protocol. 535 * If it was a write, pull the next one off the queue. 536 */ 537 dmvxint(unit) 538 int unit; 539 { 540 register struct dmv_softc *sc; 541 register struct ifnet *ifp; 542 struct uba_device *ui = dmvinfo[unit]; 543 struct dmvdevice *addr; 544 struct mbuf *m; 545 struct ifqueue *inq; 546 int sel2, sel3, sel4, sel6, sel10, pkaddr, len, s; 547 register struct ifrw *ifrw; 548 register struct dmvbufs *rp; 549 register struct ifxmt *ifxp; 550 struct dmv_header *dh; 551 int off, resid; 552 553 addr = (struct dmvdevice *)ui->ui_addr; 554 sc = &dmv_softc[unit]; 555 ifp = &sc->sc_if; 556 557 while (addr->bsel2 & DMV_RDO) { 558 559 sel2 = addr->bsel2; 560 sel3 = addr->bsel3; 561 sel4 = addr->wsel4; /* release port */ 562 sel6 = addr->wsel6; 563 if(sel2 & DMV_22BIT) 564 sel10 = addr->wsel10; 565 addr->bsel2 &= ~DMV_RDO; 566 pkaddr = sel4 | ((sel6 & 0x3f) << 16); 567 printd(("dmvxint: sel2=%x sel4=%x sel6=%x sel10=%x pkaddr=%x\n", 568 (unsigned) sel2, 569 (unsigned) sel4, 570 (unsigned) sel6, 571 (unsigned) sel10, 572 (unsigned) pkaddr 573 )); 574 if((sc->sc_flag & DMV_RUNNING)==0) { 575 log(LOG_WARNING, "dmvxint: dmv%d xint while down\n", unit); 576 return; 577 } 578 switch (sel2 & 07) { 579 case DMV_BDRUS: 580 /* 581 * A read has completed. 582 * Pass packet to type specific 583 * higher-level input routine. 584 */ 585 ifp->if_ipackets++; 586 /* find location in dmvuba struct */ 587 ifrw= &sc->sc_ifr[0]; 588 for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 589 if(rp->ubinfo == pkaddr) 590 break; 591 ifrw++; 592 } 593 if (rp >= &sc->sc_rbufs[NRCV]) 594 panic("dmv rcv"); 595 if ((rp->flags & DBUF_DMVS) == 0) 596 log(LOG_WARNING, "dmvxint: dmv%d done unalloc rbuf\n", unit); 597 598 len = (sel10&0x3fff) - sizeof (struct dmv_header); 599 if (len < 0 || len > DMVMTU) { 600 ifp->if_ierrors++; 601 log(LOG_ERR, "dmvxint: dmv%d bad rcv pkt addr 0x%x len 0x%x\n", 602 unit, pkaddr, len); 603 goto setup; 604 } 605 /* 606 * Deal with trailer protocol: if type is trailer 607 * get true type from first 16-bit word past data. 608 * Remember that type was trailer by setting off. 609 */ 610 dh = (struct dmv_header *)ifrw->ifrw_addr; 611 dh->dmv_type = ntohs((u_short)dh->dmv_type); 612 #define dmvdataaddr(dh, off, type) ((type)(((caddr_t)((dh)+1)+(off)))) 613 if (dh->dmv_type >= DMV_TRAILER && 614 dh->dmv_type < DMV_TRAILER+DMV_NTRAILER) { 615 off = (dh->dmv_type - DMV_TRAILER) * 512; 616 if (off >= DMVMTU) 617 goto setup; /* sanity */ 618 dh->dmv_type = ntohs(*dmvdataaddr(dh, off, u_short *)); 619 resid = ntohs(*(dmvdataaddr(dh, off+2, u_short *))); 620 if (off + resid > len) 621 goto setup; /* sanity */ 622 len = off + resid; 623 } else 624 off = 0; 625 if (len == 0) 626 goto setup; 627 628 /* 629 * Pull packet off interface. Off is nonzero if 630 * packet has trailing header; dmv_get will then 631 * force this header information to be at the front, 632 * but we still have to drop the type and length 633 * which are at the front of any trailer data. 634 */ 635 m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp); 636 if (m == 0) 637 goto setup; 638 switch (dh->dmv_type) { 639 #ifdef INET 640 case DMV_IPTYPE: 641 schednetisr(NETISR_IP); 642 inq = &ipintrq; 643 break; 644 #endif 645 default: 646 m_freem(m); 647 goto setup; 648 } 649 650 s = splimp(); 651 if (IF_QFULL(inq)) { 652 IF_DROP(inq); 653 m_freem(m); 654 } else 655 IF_ENQUEUE(inq, m); 656 splx(s); 657 setup: 658 /* is this needed? */ 659 rp->ubinfo = ifrw->ifrw_info & 0x3ffff; 660 dmvload( 661 sc, 662 DMV_BACCR, 663 QP_SEL4|QP_SEL6|QP_SEL10, 664 0, 665 rp->ubinfo, 666 (rp->ubinfo>>16)&0x3f, 667 rp->cc 668 ); 669 break; 670 case DMV_BDXSA: 671 /* 672 * A write has completed, start another 673 * transfer if there is more data to send. 674 */ 675 ifp->if_opackets++; 676 /* find associated dmvbuf structure */ 677 ifxp = &sc->sc_ifw[0]; 678 for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { 679 if(rp->ubinfo == pkaddr) 680 break; 681 ifxp++; 682 } 683 if (rp >= &sc->sc_xbufs[NXMT]) { 684 log(LOG_ERR, "dmv%d: bad packet address 0x%x\n", 685 unit, pkaddr); 686 break; 687 } 688 if ((rp->flags & DBUF_DMVS) == 0) 689 log(LOG_ERR, "dmvxint: dmv%d unallocated packet 0x%x\n", 690 unit, pkaddr); 691 /* mark buffer free */ 692 if (ifxp->ifw_xtofree) { 693 (void)m_freem(ifxp->ifw_xtofree); 694 ifxp->ifw_xtofree = 0; 695 } 696 rp->flags &= ~DBUF_DMVS; 697 if (--sc->sc_oused == 0) 698 sc->sc_if.if_timer = 0; 699 else 700 sc->sc_if.if_timer = dmv_timeout; 701 if ((sc->sc_flag & DMV_ONLINE) == 0) { 702 extern int ifqmaxlen; 703 704 /* 705 * We're on the air. 706 * Open the queue to the usual value. 707 */ 708 sc->sc_flag |= DMV_ONLINE; 709 ifp->if_snd.ifq_maxlen = ifqmaxlen; 710 } 711 break; 712 713 case DMV_CNTRLO: 714 /* ACCUMULATE STATISTICS */ 715 switch(sel6&DMV_EEC) { 716 case DMV_ORUN: 717 if(sc->sc_flag & DMV_RESTART) { 718 load_rec_bufs(sc); 719 sc->sc_flag &= ~DMV_RESTART; 720 log(LOG_INFO, 721 "dmv%d: far end on-line\n", unit); 722 } else { 723 log(LOG_WARNING, 724 "dmv%d: far end restart\n", unit); 725 goto restart; 726 } 727 break; 728 case DMV_RTE: 729 ifp->if_ierrors++; 730 if ((sc->sc_rte++ % DMV_RPRTE) == 0) 731 log(LOG_WARNING, 732 "dmv%d: receive threshold error\n", 733 unit); 734 break; 735 case DMV_TTE: 736 ifp->if_oerrors++; 737 if ((sc->sc_xte++ % DMV_RPTTE) == 0) 738 log(LOG_WARNING, 739 "dmv%d: transmit threshold error\n", 740 unit); 741 break; 742 case DMV_STE: 743 if ((sc->sc_ste++ % DMV_RPSTE) == 0) 744 log(LOG_WARNING, 745 "dmv%d: select threshold error\n", 746 unit); 747 break; 748 case DMV_NXM: 749 if ((sc->sc_nxm++ % DMV_RPNXM) == 0) 750 log(LOG_WARNING, 751 "dmv%d: nonexistent memory error\n", 752 unit); 753 break; 754 case DMV_MODD: 755 if ((sc->sc_modd++ % DMV_RPMODD) == 0) { 756 log(LOG_WARNING, 757 "dmv%d: modem disconnected error\n", 758 unit); 759 goto restart; 760 } 761 break; 762 case DMV_CXRL: 763 if ((sc->sc_cxrl++ % DMV_RPCXRL) == 0) 764 log(LOG_WARNING, 765 "dmv%d: carrier loss error\n", 766 unit); 767 break; 768 case DMV_QOVF: 769 log(LOG_WARNING, 770 "dmv%d: response queue overflow\n", 771 unit); 772 sc->sc_qovf++; 773 goto restart; 774 775 default: 776 log(LOG_WARNING, 777 "dmv%d: unknown error %o\n", 778 unit, sel6&DMV_EEC); 779 if ((sc->sc_unknown++ % DMV_RPUNKNOWN) == 0) 780 goto restart; 781 break; 782 } 783 break; 784 785 case DMV_BDRUNUS: 786 case DMV_BDXSN: 787 case DMV_BDXNS: 788 log(LOG_INFO, 789 "dmv%d: buffer disp for halted trib %o\n", 790 unit, sel2&0x7 791 ); 792 break; 793 794 case DMV_MDEFO: 795 if((sel6&0x1f) == 020) { 796 log(LOG_INFO, 797 "dmv%d: buffer return complete sel3=%x\n", 798 unit, sel3); 799 } else { 800 log(LOG_INFO, 801 "dmv%d: info resp sel3=%x sel4=%x sel6=%x\n", 802 unit, sel3, sel4, sel6 803 ); 804 } 805 break; 806 807 default: 808 log(LOG_WARNING, "dmv%d: bad control %o\n", 809 unit, sel2&0x7 810 ); 811 break; 812 } 813 } 814 dmvstart(unit); 815 return; 816 restart: 817 dmvrestart(unit); 818 } 819 820 load_rec_bufs(sc) 821 register struct dmv_softc *sc; 822 { 823 register struct dmvbufs *rp; 824 825 /* queue first NRCV buffers for DMV to fill */ 826 for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 827 rp->flags |= DBUF_DMVS; 828 dmvload( 829 sc, 830 DMV_BACCR, 831 QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10, 832 1, 833 rp->ubinfo, 834 (rp->ubinfo>>16)&0x3f, 835 rp->cc 836 ); 837 sc->sc_iused++; 838 } 839 } 840 841 /* 842 * DMV output routine. 843 * Encapsulate a packet of type family for the dmv. 844 * Use trailer local net encapsulation if enough data in first 845 * packet leaves a multiple of 512 bytes of data in remainder. 846 */ 847 dmvoutput(ifp, m0, dst) 848 register struct ifnet *ifp; 849 register struct mbuf *m0; 850 struct sockaddr *dst; 851 { 852 int type, error, s; 853 register struct mbuf *m = m0; 854 register struct dmv_header *dh; 855 register int off; 856 857 if ((ifp->if_flags & IFF_UP) == 0) { 858 error = ENETDOWN; 859 goto bad; 860 } 861 862 switch (dst->sa_family) { 863 #ifdef INET 864 case AF_INET: 865 off = m->m_pkthdr.len - m->m_len; 866 if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 867 if (off > 0 && (off & 0x1ff) == 0 && 868 (m->m_flags & M_EXT) == 0 && 869 m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) { 870 type = DMV_TRAILER + (off>>9); 871 m->m_data -= 2 * sizeof (u_short); 872 m->m_len += 2 * sizeof (u_short); 873 *mtod(m, u_short *) = htons((u_short)DMV_IPTYPE); 874 *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 875 goto gottrailertype; 876 } 877 type = DMV_IPTYPE; 878 off = 0; 879 goto gottype; 880 #endif 881 882 case AF_UNSPEC: 883 dh = (struct dmv_header *)dst->sa_data; 884 type = dh->dmv_type; 885 goto gottype; 886 887 default: 888 log(LOG_ERR, "dmvoutput, dmv%d can't handle af%d\n", 889 ifp->if_unit, dst->sa_family); 890 error = EAFNOSUPPORT; 891 goto bad; 892 } 893 894 gottrailertype: 895 /* 896 * Packet to be sent as a trailer; move first packet 897 * (control information) to end of chain. 898 */ 899 while (m->m_next) 900 m = m->m_next; 901 m->m_next = m0; 902 m = m0->m_next; 903 m0->m_next = 0; 904 m0 = m; 905 906 gottype: 907 /* 908 * Add local network header 909 * (there is space for a uba on a vax to step on) 910 */ 911 M_PREPEND(m, sizeof(struct dmv_header), M_DONTWAIT); 912 if (m == 0) { 913 error = ENOBUFS; 914 goto bad; 915 } 916 dh = mtod(m, struct dmv_header *); 917 dh->dmv_type = htons((u_short)type); 918 919 /* 920 * Queue message on interface, and start output if interface 921 * not yet active. 922 */ 923 s = splimp(); 924 if (IF_QFULL(&ifp->if_snd)) { 925 IF_DROP(&ifp->if_snd); 926 m_freem(m); 927 splx(s); 928 return (ENOBUFS); 929 } 930 IF_ENQUEUE(&ifp->if_snd, m); 931 dmvstart(ifp->if_unit); 932 splx(s); 933 return (0); 934 935 bad: 936 m_freem(m0); 937 return (error); 938 } 939 940 941 /* 942 * Process an ioctl request. 943 */ 944 /* ARGSUSED */ 945 dmvioctl(ifp, cmd, data) 946 register struct ifnet *ifp; 947 int cmd; 948 caddr_t data; 949 { 950 int s = splimp(), error = 0; 951 struct mbuf *m; 952 register struct dmv_softc *sc = &dmv_softc[ifp->if_unit]; 953 954 switch (cmd) { 955 956 case SIOCSIFADDR: 957 ifp->if_flags |= IFF_UP; 958 if ((ifp->if_flags & IFF_RUNNING) == 0) 959 dmvinit(ifp->if_unit); 960 break; 961 962 case SIOCSIFDSTADDR: 963 if ((ifp->if_flags & IFF_RUNNING) == 0) 964 dmvinit(ifp->if_unit); 965 break; 966 967 case SIOCSIFFLAGS: 968 if ((ifp->if_flags & IFF_UP) == 0 && 969 sc->sc_flag & DMV_RUNNING) 970 dmvdown(ifp->if_unit); 971 else if (ifp->if_flags & IFF_UP && 972 (sc->sc_flag & DMV_RUNNING) == 0) 973 dmvrestart(ifp->if_unit); 974 break; 975 976 default: 977 error = EINVAL; 978 } 979 splx(s); 980 return (error); 981 } 982 983 /* 984 * Restart after a fatal error. 985 * Clear device and reinitialize. 986 */ 987 dmvrestart(unit) 988 int unit; 989 { 990 register struct dmvdevice *addr; 991 register int i; 992 993 dmvdown(unit); 994 995 addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr); 996 /* 997 * Let the DMV finish the MCLR. 998 */ 999 for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) 1000 ; 1001 if ((addr->bsel1 & DMV_RUN) == 0) { 1002 log(LOG_ERR, "dmvrestart: can't start device\n" ); 1003 return (0); 1004 } 1005 if ((addr->bsel4 != 033) || (addr->bsel6 != 0305)) 1006 { 1007 log(LOG_ERR, "dmv%d: device init failed, bsel4=%o, bsel6=%o\n", 1008 unit, addr->bsel4, addr->bsel6); 1009 return (0); 1010 } 1011 1012 /* restart DMV */ 1013 dmvinit(unit); 1014 dmv_softc[unit].sc_if.if_collisions++; /* why not? */ 1015 } 1016 1017 /* 1018 * Reset a device and mark down. 1019 * Flush output queue and drop queue limit. 1020 */ 1021 dmvdown(unit) 1022 int unit; 1023 { 1024 struct dmv_softc *sc = &dmv_softc[unit]; 1025 register struct ifxmt *ifxp; 1026 1027 ((struct dmvdevice *)(dmvinfo[unit]->ui_addr))->bsel1 = DMV_MCLR; 1028 sc->sc_flag &= ~(DMV_RUNNING | DMV_ONLINE); 1029 1030 for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) { 1031 if (ifxp->ifw_xtofree) { 1032 (void) m_freem(ifxp->ifw_xtofree); 1033 ifxp->ifw_xtofree = 0; 1034 } 1035 } 1036 sc->sc_oused = 0; 1037 if_qflush(&sc->sc_if.if_snd); 1038 1039 /* 1040 * Limit packets enqueued until we're back on the air. 1041 */ 1042 sc->sc_if.if_snd.ifq_maxlen = 3; 1043 } 1044 1045 /* 1046 * Watchdog timeout to see that transmitted packets don't 1047 * lose interrupts. The device has to be online. 1048 */ 1049 dmvtimeout(unit) 1050 int unit; 1051 { 1052 register struct dmv_softc *sc; 1053 struct dmvdevice *addr; 1054 1055 sc = &dmv_softc[unit]; 1056 if (sc->sc_flag & DMV_ONLINE) { 1057 addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr); 1058 log(LOG_ERR, "dmv%d: output timeout, bsel0=%b bsel2=%b\n", 1059 unit, addr->bsel0 & 0xff, DMV0BITS, 1060 addr->bsel2 & 0xff, DMV2BITS); 1061 dmvrestart(unit); 1062 } 1063 } 1064 #endif 1065