1 /* @(#)if_hdh.c 6.2 (Berkeley) 11/11/85 */ 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(), hdhrint(), hdhxint(); 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 #endif 178 179 br = 0x15; /* priority 21 (5 on UNIBUS) */ 180 181 #ifdef HDHDEBUG 182 cvec = 0270; /* use constant for now ... */ 183 #else 184 185 #ifdef VAXVMS /* if VMS */ 186 cvec = 0270; /* we can't allocate vectors */ 187 #else 188 cvec = (uba_hd[numuba].uh_lastiv -= 4); /* available vector */ 189 #endif VAXVMS 190 191 #endif HDHDEBUG 192 193 addr->ioini = (char) 0; /* init UMC regs */ 194 addr->staack = (char) 0; /* pass vector */ 195 addr->ionmi = (char) 0; /* and kick UMC */ 196 addr->iochn = (char) (cvec >> 2); 197 addr->csr = (short) HDH_RST; 198 addr->csr = (short) (HDH_IEN|HDH_DMA|HDH_WRT); /* set enables */ 199 DELAY(5000); /* give the UMC some time */ 200 return(1); 201 } 202 203 /* 204 * Call the IMP module to allow it to set up its internal 205 * state, then tie the two modules together by setting up 206 * the back pointers to common data structures. 207 */ 208 hdhattach(ui) 209 struct uba_device *ui; 210 { 211 register struct hdh_softc *sc = &hdh_softc[ui->ui_unit]; 212 register struct impcb *ip; 213 struct ifimpcb { 214 struct ifnet ifimp_if; 215 struct impcb ifimp_impcb; 216 } *ifimp; 217 218 if ((ifimp = (struct ifimpcb *)impattach(ui, hdhreset)) == 0) 219 return;; 220 sc->hdh_if = &ifimp->ifimp_if; 221 ip = &ifimp->ifimp_impcb; 222 sc->hdh_ic = ip; 223 ip->ic_init = hdhinit; 224 ip->ic_start = hdhstart; 225 sc->hdh_ifuba[ui->ui_unit].ifu_flags = UBA_CANTWAIT; 226 } 227 228 /* 229 * Reset interface after UNIBUS reset. 230 */ 231 hdhreset(unit, uban) 232 int unit, uban; 233 { 234 register struct uba_device *ui = hdhinfo[unit]; 235 register struct hdh_softc *sc = &hdh_softc[unit]; 236 237 #ifdef HDHDEBUG 238 printf("HDH RESET\n"); 239 #endif HDHDEBUG 240 241 if ((unit >= NHDH) || (ui == 0) || (ui->ui_alive == 0) 242 || (ui->ui_ubanum != uban)) 243 return; 244 printf(" hdh%d", unit); 245 sc->hdh_if->if_flags &= ~IFF_RUNNING; 246 sc->hdh_flags = 0; 247 (*sc->hdh_if->if_init)(unit); 248 } 249 250 /* 251 * Initialize the imp interface. 252 */ 253 254 static char init_blk[] = 255 { 256 HDHINIT, /* SYSINIT opcode */ 257 HDHRQUP & 0xff, /* control code (LSB) */ 258 (HDHRQUP>>8) & 0xff, /* control code (MSB) */ 259 10, /* command extension len */ 260 0, /* loopback mode (off) */ 261 3, /* our address (3=DTE) */ 262 1, /* their address (1=DCE) */ 263 3, /* frame ack t1 timeout */ 264 3, /* poll ack timeout */ 265 30, /* adm wait timeout */ 266 3, /* rej wait timeout */ 267 10, /* max retries */ 268 3, /* watchdog timeout */ 269 0xaa /* baud rate (0xaa=38.4KB) */ 270 /* (output on RS-232 pin 24, */ 271 /* send/receive timing is always */ 272 /* taken from pins 15/17) */ 273 }; 274 275 hdhinit(unit) 276 int unit; 277 { 278 register struct hdh_softc *sc; 279 register struct hdhregs *addr; 280 register struct uba_device *ui; 281 register struct umc_chan *up; 282 register struct mbuf *m, *n; 283 int i, s, ubano; 284 285 #ifdef HDHDEBUG 286 printf("HDH INIT\n"); 287 #endif HDHDEBUG 288 289 if (unit >= NHDH || (ui = hdhinfo[unit]) == NULL 290 || ui->ui_alive == 0) { 291 printf("hdh%d: not alive\n", unit); 292 return(0); 293 } 294 addr = (struct hdhregs *)ui->ui_addr; 295 sc = &hdh_softc[unit]; 296 297 if (sc->hdh_flags & HDH_STARTED) 298 return(1); 299 300 /* 301 * Alloc uba resources 302 */ 303 for(i=0;i<NHDHCH;i++) { 304 if (if_ubainit(&sc->hdh_ifuba[i], ui->ui_ubanum, 0, 305 (int)btoc(IMPMTU)) == 0) { 306 printf("hdh%d: cannot get chan %d uba resources\n", 307 unit, i); 308 ui->ui_alive = 0; 309 return(0); 310 } 311 } 312 313 sc->hdh_if->if_flags |= IFF_RUNNING; 314 sc->hdh_flags = HDH_STARTED; 315 316 /* 317 * hang a supervisor read (for line status) 318 */ 319 hdh_iorq(unit, HDHSUPR, IMPMTU, HDHRDB); 320 321 /* 322 * hang a data read 323 */ 324 hdh_iorq(unit, HDHDATR, IMPMTU, HDHRDB+HDHSTR); 325 326 /* 327 * bring up line to IMP 328 */ 329 330 snd_supr(unit, init_blk, sizeof(init_blk)); 331 332 return(1); 333 } 334 335 /* 336 * Start an output operation on an mbuf. 337 */ 338 hdhstart(dev) 339 dev_t dev; 340 { 341 int unit = HDHUNIT(dev); 342 register struct hdh_softc *sc = &hdh_softc[unit]; 343 register struct mbuf *m; 344 int len; 345 346 /* 347 * If output isn't active, attempt to 348 * start sending a new packet. 349 */ 350 351 if (sc->hdh_ic->ic_oactive) { 352 printf("hdh%d: start on active unit\n", unit); 353 return; 354 } 355 356 if ((sc->hdh_flags & HDH_UP) == 0) { 357 sc->hdh_ic->ic_oactive = 0; /* Link not up, can't xmit */ 358 return; 359 } 360 361 IF_DEQUEUE(&sc->hdh_if->if_snd, m); 362 if (m == 0) { 363 sc->hdh_ic->ic_oactive = 0; 364 return; 365 } 366 367 len = if_wubaput(&sc->hdh_ifuba[DATA], m); /* copy data to mapped mem */ 368 sc->hdh_ic->ic_oactive = 1; 369 370 hdh_iorq(unit, HDHDATW, len, HDHWRT+HDHEOS); 371 } 372 373 /* 374 * Start i/o operation on a UMC logical channel 375 */ 376 hdh_iorq(unit, lcn, len, func) 377 int unit, lcn, len, func; 378 { 379 register struct hdh_softc *sc = &hdh_softc[unit]; 380 register struct hdh_chan *hc = &sc->hdh_chan[lcn]; 381 register int info, s; 382 383 /* 384 * If channel is busy (shouldn't be), drop. 385 */ 386 if (hc->hc_flags & HCBUSY) { 387 printf("hdh%d: channel busy lcn=%d\n", unit, lcn); 388 return; 389 } 390 391 /* get appropriate UNIBUS mapping info */ 392 393 if (lcn & 1) /* read or write? */ 394 info = sc->hdh_ifuba[lcn>>1].ifu_w.ifrw_info; 395 else 396 info = sc->hdh_ifuba[lcn>>1].ifu_r.ifrw_info; 397 398 /* set channel info */ 399 400 hc->hc_flags |= HCBUSY; 401 hc->hc_chan = lcn; 402 hc->hc_adx = (char)((info & 0x30000) >> 12); 403 hc->hc_addr = (unsigned short)(info & 0xffff); 404 hc->hc_cnt = len; 405 hc->hc_func = (char)func; 406 hc->hc_sbfc = 0; 407 408 s = splimp(); 409 /* 410 * If UMC comm regs busy, queue start i/o for later. 411 */ 412 if (sc->hdh_sioq.sioq_head) { 413 (sc->hdh_sioq.sioq_tail)->hc_next = hc; 414 sc->hdh_sioq.sioq_tail = hc; 415 hc->hc_next = 0; 416 splx(s); 417 return; 418 } 419 420 /* start i/o on channel now */ 421 422 sc->hdh_sioq.sioq_head = hc; 423 sc->hdh_sioq.sioq_tail = hc; 424 hc->hc_next = 0; 425 start_chn(unit); 426 splx(s); 427 } 428 429 start_chn(unit) 430 int unit; 431 { 432 register struct hdh_softc *sc = &hdh_softc[unit]; 433 register struct hdh_chan *hc = sc->hdh_sioq.sioq_head; 434 register struct hdhregs *addr = (struct hdhregs *)hdhinfo[unit]->ui_addr; 435 436 /* 437 * Set up comm regs. 438 */ 439 addr->iochn = hc->hc_chan; 440 addr->ioadx = hc->hc_adx; 441 addr->ioadl = hc->hc_addr; 442 addr->iocnt = hc->hc_cnt; 443 addr->iofcn = hc->hc_func; 444 addr->iosbf = hc->hc_sbfc; 445 addr->ioini = 1; 446 447 /* signal UMC if necessary */ 448 449 if (!(addr->ionmi)) { 450 addr->ionmi = 1; 451 addr->csr = HDH_DMA|HDH_WRT|HDH_IEN|HDH_NMI; 452 } 453 } 454 455 /* 456 * IF-11/HDH interrupt handler 457 */ 458 hdhintr(unit) 459 int unit; 460 { 461 register struct hdh_softc *sc = &hdh_softc[unit]; 462 register struct hdh_chan *hc; 463 register struct hdhregs *addr = (struct hdhregs *)hdhinfo[unit]->ui_addr; 464 register struct mbuf *m; 465 int lcn, type, cc, cnt, s; 466 467 /* 468 * Check for hardware errors. 469 */ 470 if (addr->csr & HDH_UER) { 471 printf("hdh%d: hard error csr=%b\n", unit, addr->csr, HDH_BITS); 472 addr->csr = 0; /* disable i/f */ 473 return; 474 } 475 /* 476 * Get logical channel info. 477 */ 478 if ((lcn = addr->stachn) >= (NHDHCH*2)) { 479 printf("hdh%d: unknown channel lcn=%d\n", unit, lcn); 480 return; 481 } 482 483 hc = &sc->hdh_chan[lcn]; 484 485 type = addr->statyp; 486 cc = addr->stacc; 487 cnt = hc->hc_cnt - addr->stacnt; 488 489 /* Figure out what kind of interrupt it was */ 490 491 switch(type) { 492 493 case HDHSACK: /* start i/o accepted */ 494 if (hc != sc->hdh_sioq.sioq_head) { 495 printf("hdh%d: STARTIO error lcn=%d hc=%x sq=%x\n", 496 unit, lcn, hc, sc->hdh_sioq.sioq_head); 497 return; 498 } 499 500 /* try to start any queued i/o request */ 501 502 if (sc->hdh_sioq.sioq_head = sc->hdh_sioq.sioq_head->hc_next) { 503 start_chn(unit); 504 } 505 break; 506 507 case HDHDONE: /* i/o completion */ 508 switch (cc) { 509 510 case HDHIOCABT: 511 printf("hdh%d: I/O abort ", unit); 512 goto daterr; 513 514 case HDHIOCERR: 515 printf("hdh%d: program error ", unit); 516 goto daterr; 517 518 case HDHIOCOVR: 519 printf("hdh%d: overrun error ", unit); 520 goto daterr; 521 522 case HDHIOCUBE: 523 printf("hdh%d: NXM timeout or UB parity error ", unit); 524 525 daterr: 526 printf("lcn=%d func=%x\n", lcn, hc->hc_func); 527 if (hc->hc_func & HDHRDB) 528 sc->hdh_if->if_ierrors++; 529 else 530 sc->hdh_if->if_oerrors++; 531 } 532 533 hc->hc_flags &= ~HCBUSY; 534 535 /* was it supervisor or data traffic? */ 536 537 if (lcn > HDHSUPW) 538 hdh_data(unit, lcn, cc, cnt); 539 else 540 hdh_supr(unit, lcn, cc, cnt); 541 542 } 543 544 /* 545 * Ack the interrupt 546 */ 547 addr->staack = 1; 548 if (!(addr->ionmi)) { 549 addr->ionmi = 1; 550 addr->csr = HDH_DMA|HDH_WRT|HDH_IEN|HDH_NMI; 551 } 552 } 553 554 /* 555 * data channel interrupt completion handler 556 */ 557 hdh_data(unit, lcn, cc, rcnt) 558 int unit, lcn, cc, rcnt; 559 { 560 register struct hdh_softc *sc = &hdh_softc[unit]; 561 register struct hdh_chan *hc = &sc->hdh_chan[lcn]; 562 register struct mbuf *m; 563 564 565 /* was it read or write? */ 566 567 if (hc->hc_func & HDHRDB) { 568 if (cc == HDHIOCOK) { 569 /* 570 * Queue good packet for input 571 */ 572 sc->hdh_if->if_ipackets++; 573 m = if_rubaget(&sc->hdh_ifuba[lcn>>1], rcnt, 0, 574 sc->hdh_if); 575 impinput(unit, m); 576 } 577 578 /* hang a new data read */ 579 580 hdh_iorq(unit, lcn, IMPMTU, HDHRDB+HDHSTR); 581 582 } else { 583 /* 584 * fire up next output 585 */ 586 sc->hdh_if->if_opackets++; 587 sc->hdh_ic->ic_oactive = 0; 588 hdhstart(unit); 589 } 590 } 591 592 /* 593 * supervisor channel interrupt completion handler 594 */ 595 hdh_supr(unit, lcn, cc, rcnt) 596 int unit, lcn, cc, rcnt; 597 { 598 register struct hdh_softc *sc = &hdh_softc[unit]; 599 register struct hdh_chan *hc = &sc->hdh_chan[lcn]; 600 register struct uba_device *ui; 601 short *p; 602 int i; 603 604 605 /* was it read or write? */ 606 607 if (hc->hc_func & HDHRDB) { 608 if (cc == HDHIOCOK) { 609 p = (short *)(sc->hdh_ifuba[lcn>>1].ifu_r.ifrw_addr); 610 611 /* figure out what kind of supervisor message */ 612 613 switch (*p) { 614 615 case HDHIACK: 616 case HDHLNACK: 617 break; 618 619 case HDHLNUP: 620 printf("hdh%d: LINE UP\n", unit); 621 sc->hdh_flags |= HDH_UP; 622 hdhstart(unit); 623 break; 624 625 case HDHLNDN: 626 if (sc->hdh_flags & HDH_UP) 627 printf("hdh%d: LINE DOWN\n", unit); 628 sc->hdh_flags &= ~HDH_UP; 629 break; 630 631 case HDHLOOP: 632 break; 633 634 case HDHSQERR: 635 printf("hdh%d: HOST SEQUENCE ERROR\n", unit); 636 break; 637 638 case HDHSQRCV: 639 printf("hdh%d: IMP SEQUENCE ERROR\n", unit); 640 break; 641 642 case HDHDTERR: 643 printf("hdh%d: HOST DATA ERROR\n", unit); 644 break; 645 646 case HDHTIMO: 647 printf("hdh%d: TIMEOUT\n", unit); 648 break; 649 650 default: 651 printf("hdh%d: supervisor error, code=%x\n", 652 unit, *p); 653 } 654 } 655 656 /* hang a new supr read */ 657 658 hdh_iorq(unit, HDHSUPR, IMPMTU, HDHRDB+HDHSTR); 659 } 660 } 661 662 snd_supr(unit, msg, len) 663 int unit, len; 664 char *msg; 665 { 666 register struct hdh_softc *sc = &hdh_softc[unit]; 667 register struct hdh_chan *hc = &sc->hdh_chan[HDHSUPW]; 668 register struct mbuf *m; 669 register char *p; 670 register int cnt; 671 672 if ((m = m_get(M_DONTWAIT, MT_DATA)) == NULL) { 673 printf("hdh%d: cannot get supervisor cmnd buffer\n", unit); 674 return(0); 675 } 676 677 cnt = len; 678 m->m_len = len; 679 p = mtod(m, char *); 680 681 while(cnt--) *p++ = *msg++; 682 683 cnt = if_wubaput(&sc->hdh_ifuba[SUPR], m); 684 685 hdh_iorq(unit, HDHSUPW, cnt, HDHWRT+HDHEOS); 686 687 return(1); 688 } 689 690 #endif NHDH 691