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