1: /* @(#)if_hdh.c 7.1 (Berkeley) 6/5/86 */ 2: 3: 4: /************************************************************************\ 5: 6: ________________________________________________________ 7: / \ 8: | AAA CCCCCCCCCCCCCC CCCCCCCCCCCCCC | 9: | AAAAA CCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCC | 10: | AAAAAAA CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC | 11: | AAAA AAAA CCCC CCCC | 12: | AAAA AAAA CCCC CCCC | 13: | AAAA AAAA CCCC CCCC | 14: | AAAA AAAA CCCC CCCC | 15: | AAAA AAAAAAAAAAA CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC | 16: | AAAA AAAAAAAAAAA CCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCC | 17: | AAAA AAAAAAAAA CCCCCCCCCCCCCC CCCCCCCCCCCCCC | 18: \________________________________________________________/ 19: 20: Copyright (c) 1984 by Advanced Computer Communications 21: 720 Santa Barbara Street, Santa Barbara, California 93101 22: (805) 963-9431 23: 24: This software may be duplicated and used on systems 25: which are licensed to run U.C. Berkeley versions of 26: the UNIX operating system. Any duplication of any 27: part of this software must include a copy of ACC's 28: copyright notice. 29: 30: 31: File: 32: if_hdh.c 33: 34: Author: 35: Art Berggreen 36: 37: Project: 38: 4.2BSD HDH 39: 40: Function: 41: Device specific driver for IF-11/HDH under 4.2BSD 42: networking code. 43: 44: Revision History: 45: 31-Aug-1984: V1.0 - First Implementation. A.B. 46: 6-Nov-1984: V1.1 - Supress extra "LINE DOWN" msgs. A.B. 47: 13-Jan-1984: V1.2 - Add conditionals for TWG. A.B. 48: 49: \************************************************************************/ 50: 51: 52: 53: 54: /* $Header$ */ 55: 56: #include "hdh.h" 57: #ifdef NHDH > 0 58: 59: /* 60: * 61: * ACC IF-11/HDH interface 62: * 63: */ 64: 65: #include "../machine/pte.h" 66: 67: #include "param.h" 68: #include "systm.h" 69: #include "mbuf.h" 70: #include "buf.h" 71: #include "protosw.h" 72: #include "socket.h" 73: #include "vmmac.h" 74: 75: #include "../net/if.h" 76: #include "../netimp/if_imp.h" 77: 78: #include "../vax/cpu.h" 79: #include "../vax/mtpr.h" 80: #include "../vaxuba/ubareg.h" 81: #include "../vaxuba/ubavar.h" 82: 83: #include "if_hdhreg.h" 84: #include "if_uba.h" 85: 86: int hdhprobe(), hdhattach(), hdhintr(); 87: struct uba_device *hdhinfo[NHDH]; 88: u_short hdhstd[] = { 0 }; 89: struct uba_driver hdhdriver = 90: { hdhprobe, 0, hdhattach, 0, hdhstd, "hdh", hdhinfo }; 91: 92: #define HDHUNIT(x) minor(x) 93: 94: int hdhinit(), hdhstart(), hdhreset(); 95: 96: /* 97: * "Lower half" of IMP interface driver. 98: * 99: * Each IMP interface is handled by a common module which handles 100: * the IMP-host protocol and a hardware driver which manages the 101: * hardware specific details of talking with the IMP. 102: * 103: * The hardware portion of the IMP driver handles DMA and related 104: * management of UNIBUS resources. The IMP protocol module interprets 105: * contents of these messages and "controls" the actions of the 106: * hardware module during IMP resets, but not, for instance, during 107: * UNIBUS resets. 108: * 109: * The two modules are coupled at "attach time", and ever after, 110: * through the imp interface structure. Higher level protocols, 111: * e.g. IP, interact with the IMP driver, rather than the HDH. 112: */ 113: 114: #define NHDHCH 2 /* no. of FDX channels for HDH */ 115: #define SUPR 0 /* supervisor channel */ 116: #define DATA 1 /* data channel */ 117: #define HDHSUPR 0 /* supervisor read */ 118: #define HDHSUPW 1 /* supervisor write */ 119: #define HDHDATR 2 /* data read */ 120: #define HDHDATW 3 /* data write */ 121: 122: #define HDH_UP 2 /* HDH protocol is up */ 123: #define HDH_STARTED 1 /* HDH has been initialized */ 124: 125: #define HCBUSY 1 /* HDH HDX channel busy flag */ 126: 127: /* 128: /* The IF-11/HDH has four independent dath flow channels between the 129: /* front-end and the host. Two are used for reading and writing 130: /* control messages and two are used for data flow. Each IF-11/HDH 131: /* has a device dependent data structure (hdh_softc) which contains 132: /* an array of four channel dependent structures (hdh_chan) to maintain 133: /* the context of each channel. Channel structures can be linked into 134: /* a queue of I/O requests pending for the hardware interface. 135: /* UNIBUS mapping resources are allocated for each channel pair. 136: */ 137: 138: struct hdh_chan { /* HDH HDX channel structure */ 139: struct hdh_chan *hc_next; /* link for Start I/O queuing */ 140: char hc_chan; /* HDX chan number */ 141: char hc_adx; /* extended UNIBUS address bits */ 142: short hc_addr; /* lower UNIBUS address bits */ 143: short hc_cnt; /* byte count */ 144: char hc_func; /* UMC I/O function */ 145: char hc_sbfc; /* UMC I/O subfunction */ 146: short hc_flags; /* status flags */ 147: }; 148: 149: struct hdh_sioq { /* Start I/O queue head structure */ 150: struct hdh_chan *sioq_head; /* pointer to queue head */ 151: struct hdh_chan *sioq_tail; /* pointer to queue tail */ 152: }; 153: 154: struct hdh_softc { /* HDH device dependent structure */ 155: struct ifnet *hdh_if; /* pointer to IMP's ifnet struct */ 156: struct impcb *hdh_ic; /* data structure shared with IMP */ 157: struct ifuba hdh_ifuba[NHDHCH]; /* UNIBUS resources */ 158: struct hdh_chan hdh_chan[2*NHDHCH]; /* HDX HDH channels */ 159: struct hdh_sioq hdh_sioq; /* start i/o queue */ 160: short hdh_flags; /* various status conditions */ 161: } hdh_softc[NHDH]; 162: 163: 164: /* 165: * Normally, code goes here to cause the device to interrupt to determine its 166: * interrupt vector. However, since the UMC must be told its vector in order 167: * to interrupt, we allocate and return an unused vector and initialize the 168: * UMC. 169: */ 170: hdhprobe(reg) 171: caddr_t reg; 172: { 173: register int br, cvec; 174: struct hdhregs *addr = (struct hdhregs *)reg; 175: #ifdef lint 176: br = 0; cvec = br; br = cvec; 177: hdhintr(0); 178: #endif 179: 180: br = 0x15; /* priority 21 (5 on UNIBUS) */ 181: 182: #ifdef HDHDEBUG 183: cvec = 0270; /* use constant for now ... */ 184: #else 185: 186: #ifdef VAXVMS /* if VMS */ 187: cvec = 0270; /* we can't allocate vectors */ 188: #else 189: cvec = (uba_hd[numuba].uh_lastiv -= 4); /* available vector */ 190: #endif VAXVMS 191: 192: #endif HDHDEBUG 193: 194: addr->ioini = (char) 0; /* init UMC regs */ 195: addr->staack = (char) 0; /* pass vector */ 196: addr->ionmi = (char) 0; /* and kick UMC */ 197: addr->iochn = (char) (cvec >> 2); 198: addr->csr = (short) HDH_RST; 199: addr->csr = (short) (HDH_IEN|HDH_DMA|HDH_WRT); /* set enables */ 200: DELAY(5000); /* give the UMC some time */ 201: return(1); 202: } 203: 204: /* 205: * Call the IMP module to allow it to set up its internal 206: * state, then tie the two modules together by setting up 207: * the back pointers to common data structures. 208: */ 209: hdhattach(ui) 210: struct uba_device *ui; 211: { 212: register struct hdh_softc *sc = &hdh_softc[ui->ui_unit]; 213: register struct impcb *ip; 214: struct ifimpcb { 215: struct ifnet ifimp_if; 216: struct impcb ifimp_impcb; 217: } *ifimp; 218: 219: if ((ifimp = (struct ifimpcb *)impattach(ui, hdhreset)) == 0) 220: return;; 221: sc->hdh_if = &ifimp->ifimp_if; 222: ip = &ifimp->ifimp_impcb; 223: sc->hdh_ic = ip; 224: ip->ic_init = hdhinit; 225: ip->ic_start = hdhstart; 226: sc->hdh_ifuba[ui->ui_unit].ifu_flags = UBA_CANTWAIT; 227: } 228: 229: /* 230: * Reset interface after UNIBUS reset. 231: */ 232: hdhreset(unit, uban) 233: int unit, uban; 234: { 235: register struct uba_device *ui = hdhinfo[unit]; 236: register struct hdh_softc *sc = &hdh_softc[unit]; 237: 238: #ifdef HDHDEBUG 239: printf("HDH RESET\n"); 240: #endif HDHDEBUG 241: 242: if ((unit >= NHDH) || (ui == 0) || (ui->ui_alive == 0) 243: || (ui->ui_ubanum != uban)) 244: return; 245: printf(" hdh%d", unit); 246: sc->hdh_if->if_flags &= ~IFF_RUNNING; 247: sc->hdh_flags = 0; 248: (*sc->hdh_if->if_init)(unit); 249: } 250: 251: /* 252: * Initialize the imp interface. 253: */ 254: 255: static char init_blk[] = 256: { 257: HDHINIT, /* SYSINIT opcode */ 258: HDHRQUP & 0xff, /* control code (LSB) */ 259: (HDHRQUP>>8) & 0xff, /* control code (MSB) */ 260: 10, /* command extension len */ 261: 0, /* loopback mode (off) */ 262: 3, /* our address (3=DTE) */ 263: 1, /* their address (1=DCE) */ 264: 3, /* frame ack t1 timeout */ 265: 3, /* poll ack timeout */ 266: 30, /* adm wait timeout */ 267: 3, /* rej wait timeout */ 268: 10, /* max retries */ 269: 3, /* watchdog timeout */ 270: 0xaa /* baud rate (0xaa=38.4KB) */ 271: /* (output on RS-232 pin 24, */ 272: /* send/receive timing is always */ 273: /* taken from pins 15/17) */ 274: }; 275: 276: hdhinit(unit) 277: int unit; 278: { 279: register struct hdh_softc *sc; 280: register struct uba_device *ui; 281: int i; 282: 283: #ifdef HDHDEBUG 284: printf("HDH INIT\n"); 285: #endif HDHDEBUG 286: 287: if (unit >= NHDH || (ui = hdhinfo[unit]) == NULL 288: || ui->ui_alive == 0) { 289: printf("hdh%d: not alive\n", unit); 290: return(0); 291: } 292: sc = &hdh_softc[unit]; 293: 294: if (sc->hdh_flags & HDH_STARTED) 295: return(1); 296: 297: /* 298: * Alloc uba resources 299: */ 300: for(i=0;i<NHDHCH;i++) { 301: if (if_ubainit(&sc->hdh_ifuba[i], ui->ui_ubanum, 0, 302: (int)btoc(IMPMTU)) == 0) { 303: printf("hdh%d: cannot get chan %d uba resources\n", 304: unit, i); 305: ui->ui_alive = 0; 306: return(0); 307: } 308: } 309: 310: sc->hdh_if->if_flags |= IFF_RUNNING; 311: sc->hdh_flags = HDH_STARTED; 312: 313: /* 314: * hang a supervisor read (for line status) 315: */ 316: hdh_iorq(unit, HDHSUPR, IMPMTU, HDHRDB); 317: 318: /* 319: * hang a data read 320: */ 321: hdh_iorq(unit, HDHDATR, IMPMTU, HDHRDB+HDHSTR); 322: 323: /* 324: * bring up line to IMP 325: */ 326: 327: snd_supr(unit, init_blk, sizeof(init_blk)); 328: 329: return(1); 330: } 331: 332: /* 333: * Start an output operation on an mbuf. 334: */ 335: hdhstart(dev) 336: dev_t dev; 337: { 338: int unit = HDHUNIT(dev); 339: register struct hdh_softc *sc = &hdh_softc[unit]; 340: register struct mbuf *m; 341: int len; 342: 343: /* 344: * If output isn't active, attempt to 345: * start sending a new packet. 346: */ 347: 348: if (sc->hdh_ic->ic_oactive) { 349: printf("hdh%d: start on active unit\n", unit); 350: return; 351: } 352: 353: if ((sc->hdh_flags & HDH_UP) == 0) { 354: sc->hdh_ic->ic_oactive = 0; /* Link not up, can't xmit */ 355: return; 356: } 357: 358: IF_DEQUEUE(&sc->hdh_if->if_snd, m); 359: if (m == 0) { 360: sc->hdh_ic->ic_oactive = 0; 361: return; 362: } 363: 364: len = if_wubaput(&sc->hdh_ifuba[DATA], m); /* copy data to mapped mem */ 365: sc->hdh_ic->ic_oactive = 1; 366: 367: hdh_iorq(unit, HDHDATW, len, HDHWRT+HDHEOS); 368: } 369: 370: /* 371: * Start i/o operation on a UMC logical channel 372: */ 373: hdh_iorq(unit, lcn, len, func) 374: int unit, lcn, len, func; 375: { 376: register struct hdh_softc *sc = &hdh_softc[unit]; 377: register struct hdh_chan *hc = &sc->hdh_chan[lcn]; 378: register int info, s; 379: 380: /* 381: * If channel is busy (shouldn't be), drop. 382: */ 383: if (hc->hc_flags & HCBUSY) { 384: printf("hdh%d: channel busy lcn=%d\n", unit, lcn); 385: return; 386: } 387: 388: /* get appropriate UNIBUS mapping info */ 389: 390: if (lcn & 1) /* read or write? */ 391: info = sc->hdh_ifuba[lcn>>1].ifu_w.ifrw_info; 392: else 393: info = sc->hdh_ifuba[lcn>>1].ifu_r.ifrw_info; 394: 395: /* set channel info */ 396: 397: hc->hc_flags |= HCBUSY; 398: hc->hc_chan = lcn; 399: hc->hc_adx = (char)((info & 0x30000) >> 12); 400: hc->hc_addr = (unsigned short)(info & 0xffff); 401: hc->hc_cnt = len; 402: hc->hc_func = (char)func; 403: hc->hc_sbfc = 0; 404: 405: s = splimp(); 406: /* 407: * If UMC comm regs busy, queue start i/o for later. 408: */ 409: if (sc->hdh_sioq.sioq_head) { 410: (sc->hdh_sioq.sioq_tail)->hc_next = hc; 411: sc->hdh_sioq.sioq_tail = hc; 412: hc->hc_next = 0; 413: splx(s); 414: return; 415: } 416: 417: /* start i/o on channel now */ 418: 419: sc->hdh_sioq.sioq_head = hc; 420: sc->hdh_sioq.sioq_tail = hc; 421: hc->hc_next = 0; 422: start_chn(unit); 423: splx(s); 424: } 425: 426: start_chn(unit) 427: int unit; 428: { 429: register struct hdh_softc *sc = &hdh_softc[unit]; 430: register struct hdh_chan *hc = sc->hdh_sioq.sioq_head; 431: register struct hdhregs *addr = (struct hdhregs *)hdhinfo[unit]->ui_addr; 432: 433: /* 434: * Set up comm regs. 435: */ 436: addr->iochn = hc->hc_chan; 437: addr->ioadx = hc->hc_adx; 438: addr->ioadl = hc->hc_addr; 439: addr->iocnt = hc->hc_cnt; 440: addr->iofcn = hc->hc_func; 441: addr->iosbf = hc->hc_sbfc; 442: addr->ioini = 1; 443: 444: /* signal UMC if necessary */ 445: 446: if (!(addr->ionmi)) { 447: addr->ionmi = 1; 448: addr->csr = HDH_DMA|HDH_WRT|HDH_IEN|HDH_NMI; 449: } 450: } 451: 452: /* 453: * IF-11/HDH interrupt handler 454: */ 455: hdhintr(unit) 456: int unit; 457: { 458: register struct hdh_softc *sc = &hdh_softc[unit]; 459: register struct hdh_chan *hc; 460: register struct hdhregs *addr = (struct hdhregs *)hdhinfo[unit]->ui_addr; 461: int lcn, type, cc, cnt; 462: 463: /* 464: * Check for hardware errors. 465: */ 466: if (addr->csr & HDH_UER) { 467: printf("hdh%d: hard error csr=%b\n", unit, addr->csr, HDH_BITS); 468: addr->csr = 0; /* disable i/f */ 469: return; 470: } 471: /* 472: * Get logical channel info. 473: */ 474: if ((lcn = addr->stachn) >= (NHDHCH*2)) { 475: printf("hdh%d: unknown channel lcn=%d\n", unit, lcn); 476: return; 477: } 478: 479: hc = &sc->hdh_chan[lcn]; 480: 481: type = addr->statyp; 482: cc = addr->stacc; 483: cnt = hc->hc_cnt - addr->stacnt; 484: 485: /* Figure out what kind of interrupt it was */ 486: 487: switch(type) { 488: 489: case HDHSACK: /* start i/o accepted */ 490: if (hc != sc->hdh_sioq.sioq_head) { 491: printf("hdh%d: STARTIO error lcn=%d hc=%x sq=%x\n", 492: unit, lcn, hc, sc->hdh_sioq.sioq_head); 493: return; 494: } 495: 496: /* try to start any queued i/o request */ 497: 498: if (sc->hdh_sioq.sioq_head = sc->hdh_sioq.sioq_head->hc_next) { 499: start_chn(unit); 500: } 501: break; 502: 503: case HDHDONE: /* i/o completion */ 504: switch (cc) { 505: 506: case HDHIOCABT: 507: printf("hdh%d: I/O abort ", unit); 508: goto daterr; 509: 510: case HDHIOCERR: 511: printf("hdh%d: program error ", unit); 512: goto daterr; 513: 514: case HDHIOCOVR: 515: printf("hdh%d: overrun error ", unit); 516: goto daterr; 517: 518: case HDHIOCUBE: 519: printf("hdh%d: NXM timeout or UB parity error ", unit); 520: 521: daterr: 522: printf("lcn=%d func=%x\n", lcn, hc->hc_func); 523: if (hc->hc_func & HDHRDB) 524: sc->hdh_if->if_ierrors++; 525: else 526: sc->hdh_if->if_oerrors++; 527: } 528: 529: hc->hc_flags &= ~HCBUSY; 530: 531: /* was it supervisor or data traffic? */ 532: 533: if (lcn > HDHSUPW) 534: hdh_data(unit, lcn, cc, cnt); 535: else 536: hdh_supr(unit, lcn, cc); 537: 538: } 539: 540: /* 541: * Ack the interrupt 542: */ 543: addr->staack = 1; 544: if (!(addr->ionmi)) { 545: addr->ionmi = 1; 546: addr->csr = HDH_DMA|HDH_WRT|HDH_IEN|HDH_NMI; 547: } 548: } 549: 550: /* 551: * data channel interrupt completion handler 552: */ 553: hdh_data(unit, lcn, cc, rcnt) 554: int unit, lcn, cc, rcnt; 555: { 556: register struct hdh_softc *sc = &hdh_softc[unit]; 557: register struct hdh_chan *hc = &sc->hdh_chan[lcn]; 558: register struct mbuf *m; 559: 560: 561: /* was it read or write? */ 562: 563: if (hc->hc_func & HDHRDB) { 564: if (cc == HDHIOCOK) { 565: /* 566: * Queue good packet for input 567: */ 568: sc->hdh_if->if_ipackets++; 569: m = if_rubaget(&sc->hdh_ifuba[lcn>>1], rcnt, 0, 570: sc->hdh_if); 571: impinput(unit, m); 572: } 573: 574: /* hang a new data read */ 575: 576: hdh_iorq(unit, lcn, IMPMTU, HDHRDB+HDHSTR); 577: 578: } else { 579: /* 580: * fire up next output 581: */ 582: sc->hdh_if->if_opackets++; 583: sc->hdh_ic->ic_oactive = 0; 584: hdhstart(unit); 585: } 586: } 587: 588: /* 589: * supervisor channel interrupt completion handler 590: */ 591: hdh_supr(unit, lcn, cc) 592: int unit, lcn, cc; 593: { 594: register struct hdh_softc *sc = &hdh_softc[unit]; 595: register struct hdh_chan *hc = &sc->hdh_chan[lcn]; 596: short *p; 597: 598: 599: /* was it read or write? */ 600: 601: if (hc->hc_func & HDHRDB) { 602: if (cc == HDHIOCOK) { 603: p = (short *)(sc->hdh_ifuba[lcn>>1].ifu_r.ifrw_addr); 604: 605: /* figure out what kind of supervisor message */ 606: 607: switch (*p) { 608: 609: case HDHIACK: 610: case HDHLNACK: 611: break; 612: 613: case HDHLNUP: 614: printf("hdh%d: LINE UP\n", unit); 615: sc->hdh_flags |= HDH_UP; 616: hdhstart(unit); 617: break; 618: 619: case HDHLNDN: 620: if (sc->hdh_flags & HDH_UP) 621: printf("hdh%d: LINE DOWN\n", unit); 622: sc->hdh_flags &= ~HDH_UP; 623: break; 624: 625: case HDHLOOP: 626: break; 627: 628: case HDHSQERR: 629: printf("hdh%d: HOST SEQUENCE ERROR\n", unit); 630: break; 631: 632: case HDHSQRCV: 633: printf("hdh%d: IMP SEQUENCE ERROR\n", unit); 634: break; 635: 636: case HDHDTERR: 637: printf("hdh%d: HOST DATA ERROR\n", unit); 638: break; 639: 640: case HDHTIMO: 641: printf("hdh%d: TIMEOUT\n", unit); 642: break; 643: 644: default: 645: printf("hdh%d: supervisor error, code=%x\n", 646: unit, *p); 647: } 648: } 649: 650: /* hang a new supr read */ 651: 652: hdh_iorq(unit, HDHSUPR, IMPMTU, HDHRDB+HDHSTR); 653: } 654: } 655: 656: snd_supr(unit, msg, len) 657: int unit, len; 658: char *msg; 659: { 660: register struct hdh_softc *sc = &hdh_softc[unit]; 661: register struct mbuf *m; 662: register char *p; 663: register int cnt; 664: 665: if ((m = m_get(M_DONTWAIT, MT_DATA)) == NULL) { 666: printf("hdh%d: cannot get supervisor cmnd buffer\n", unit); 667: return; 668: } 669: 670: cnt = len; 671: m->m_len = len; 672: p = mtod(m, char *); 673: 674: while(cnt--) *p++ = *msg++; 675: 676: cnt = if_wubaput(&sc->hdh_ifuba[SUPR], m); 677: 678: hdh_iorq(unit, HDHSUPW, cnt, HDHWRT+HDHEOS); 679: } 680: #endif NHDH