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