1 /* @(#)if_hdh.c 7.2 (Berkeley) 08/07/87 */ 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 + 2)) == 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 + 2, HDHRDB); 317 318 /* 319 * hang a data read 320 */ 321 hdh_iorq(unit, HDHDATR, IMPMTU + 2, 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 + 2, 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 + 2, 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 681