1 /* @(#)if_hdh.c 6.5 (Berkeley) 02/21/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(), 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 uba_device *ui; 280 int i; 281 282 #ifdef HDHDEBUG 283 printf("HDH INIT\n"); 284 #endif HDHDEBUG 285 286 if (unit >= NHDH || (ui = hdhinfo[unit]) == NULL 287 || ui->ui_alive == 0) { 288 printf("hdh%d: not alive\n", unit); 289 return(0); 290 } 291 sc = &hdh_softc[unit]; 292 293 if (sc->hdh_flags & HDH_STARTED) 294 return(1); 295 296 /* 297 * Alloc uba resources 298 */ 299 for(i=0;i<NHDHCH;i++) { 300 if (if_ubainit(&sc->hdh_ifuba[i], ui->ui_ubanum, 0, 301 (int)btoc(IMPMTU)) == 0) { 302 printf("hdh%d: cannot get chan %d uba resources\n", 303 unit, i); 304 ui->ui_alive = 0; 305 return(0); 306 } 307 } 308 309 sc->hdh_if->if_flags |= IFF_RUNNING; 310 sc->hdh_flags = HDH_STARTED; 311 312 /* 313 * hang a supervisor read (for line status) 314 */ 315 hdh_iorq(unit, HDHSUPR, IMPMTU, HDHRDB); 316 317 /* 318 * hang a data read 319 */ 320 hdh_iorq(unit, HDHDATR, IMPMTU, HDHRDB+HDHSTR); 321 322 /* 323 * bring up line to IMP 324 */ 325 326 snd_supr(unit, init_blk, sizeof(init_blk)); 327 328 return(1); 329 } 330 331 /* 332 * Start an output operation on an mbuf. 333 */ 334 hdhstart(dev) 335 dev_t dev; 336 { 337 int unit = HDHUNIT(dev); 338 register struct hdh_softc *sc = &hdh_softc[unit]; 339 register struct mbuf *m; 340 int len; 341 342 /* 343 * If output isn't active, attempt to 344 * start sending a new packet. 345 */ 346 347 if (sc->hdh_ic->ic_oactive) { 348 printf("hdh%d: start on active unit\n", unit); 349 return; 350 } 351 352 if ((sc->hdh_flags & HDH_UP) == 0) { 353 sc->hdh_ic->ic_oactive = 0; /* Link not up, can't xmit */ 354 return; 355 } 356 357 IF_DEQUEUE(&sc->hdh_if->if_snd, m); 358 if (m == 0) { 359 sc->hdh_ic->ic_oactive = 0; 360 return; 361 } 362 363 len = if_wubaput(&sc->hdh_ifuba[DATA], m); /* copy data to mapped mem */ 364 sc->hdh_ic->ic_oactive = 1; 365 366 hdh_iorq(unit, HDHDATW, len, HDHWRT+HDHEOS); 367 } 368 369 /* 370 * Start i/o operation on a UMC logical channel 371 */ 372 hdh_iorq(unit, lcn, len, func) 373 int unit, lcn, len, func; 374 { 375 register struct hdh_softc *sc = &hdh_softc[unit]; 376 register struct hdh_chan *hc = &sc->hdh_chan[lcn]; 377 register int info, s; 378 379 /* 380 * If channel is busy (shouldn't be), drop. 381 */ 382 if (hc->hc_flags & HCBUSY) { 383 printf("hdh%d: channel busy lcn=%d\n", unit, lcn); 384 return; 385 } 386 387 /* get appropriate UNIBUS mapping info */ 388 389 if (lcn & 1) /* read or write? */ 390 info = sc->hdh_ifuba[lcn>>1].ifu_w.ifrw_info; 391 else 392 info = sc->hdh_ifuba[lcn>>1].ifu_r.ifrw_info; 393 394 /* set channel info */ 395 396 hc->hc_flags |= HCBUSY; 397 hc->hc_chan = lcn; 398 hc->hc_adx = (char)((info & 0x30000) >> 12); 399 hc->hc_addr = (unsigned short)(info & 0xffff); 400 hc->hc_cnt = len; 401 hc->hc_func = (char)func; 402 hc->hc_sbfc = 0; 403 404 s = splimp(); 405 /* 406 * If UMC comm regs busy, queue start i/o for later. 407 */ 408 if (sc->hdh_sioq.sioq_head) { 409 (sc->hdh_sioq.sioq_tail)->hc_next = hc; 410 sc->hdh_sioq.sioq_tail = hc; 411 hc->hc_next = 0; 412 splx(s); 413 return; 414 } 415 416 /* start i/o on channel now */ 417 418 sc->hdh_sioq.sioq_head = hc; 419 sc->hdh_sioq.sioq_tail = hc; 420 hc->hc_next = 0; 421 start_chn(unit); 422 splx(s); 423 } 424 425 start_chn(unit) 426 int unit; 427 { 428 register struct hdh_softc *sc = &hdh_softc[unit]; 429 register struct hdh_chan *hc = sc->hdh_sioq.sioq_head; 430 register struct hdhregs *addr = (struct hdhregs *)hdhinfo[unit]->ui_addr; 431 432 /* 433 * Set up comm regs. 434 */ 435 addr->iochn = hc->hc_chan; 436 addr->ioadx = hc->hc_adx; 437 addr->ioadl = hc->hc_addr; 438 addr->iocnt = hc->hc_cnt; 439 addr->iofcn = hc->hc_func; 440 addr->iosbf = hc->hc_sbfc; 441 addr->ioini = 1; 442 443 /* signal UMC if necessary */ 444 445 if (!(addr->ionmi)) { 446 addr->ionmi = 1; 447 addr->csr = HDH_DMA|HDH_WRT|HDH_IEN|HDH_NMI; 448 } 449 } 450 451 /* 452 * IF-11/HDH interrupt handler 453 */ 454 hdhintr(unit) 455 int unit; 456 { 457 register struct hdh_softc *sc = &hdh_softc[unit]; 458 register struct hdh_chan *hc; 459 register struct hdhregs *addr = (struct hdhregs *)hdhinfo[unit]->ui_addr; 460 int lcn, type, cc, cnt; 461 462 /* 463 * Check for hardware errors. 464 */ 465 if (addr->csr & HDH_UER) { 466 printf("hdh%d: hard error csr=%b\n", unit, addr->csr, HDH_BITS); 467 addr->csr = 0; /* disable i/f */ 468 return; 469 } 470 /* 471 * Get logical channel info. 472 */ 473 if ((lcn = addr->stachn) >= (NHDHCH*2)) { 474 printf("hdh%d: unknown channel lcn=%d\n", unit, lcn); 475 return; 476 } 477 478 hc = &sc->hdh_chan[lcn]; 479 480 type = addr->statyp; 481 cc = addr->stacc; 482 cnt = hc->hc_cnt - addr->stacnt; 483 484 /* Figure out what kind of interrupt it was */ 485 486 switch(type) { 487 488 case HDHSACK: /* start i/o accepted */ 489 if (hc != sc->hdh_sioq.sioq_head) { 490 printf("hdh%d: STARTIO error lcn=%d hc=%x sq=%x\n", 491 unit, lcn, hc, sc->hdh_sioq.sioq_head); 492 return; 493 } 494 495 /* try to start any queued i/o request */ 496 497 if (sc->hdh_sioq.sioq_head = sc->hdh_sioq.sioq_head->hc_next) { 498 start_chn(unit); 499 } 500 break; 501 502 case HDHDONE: /* i/o completion */ 503 switch (cc) { 504 505 case HDHIOCABT: 506 printf("hdh%d: I/O abort ", unit); 507 goto daterr; 508 509 case HDHIOCERR: 510 printf("hdh%d: program error ", unit); 511 goto daterr; 512 513 case HDHIOCOVR: 514 printf("hdh%d: overrun error ", unit); 515 goto daterr; 516 517 case HDHIOCUBE: 518 printf("hdh%d: NXM timeout or UB parity error ", unit); 519 520 daterr: 521 printf("lcn=%d func=%x\n", lcn, hc->hc_func); 522 if (hc->hc_func & HDHRDB) 523 sc->hdh_if->if_ierrors++; 524 else 525 sc->hdh_if->if_oerrors++; 526 } 527 528 hc->hc_flags &= ~HCBUSY; 529 530 /* was it supervisor or data traffic? */ 531 532 if (lcn > HDHSUPW) 533 hdh_data(unit, lcn, cc, cnt); 534 else 535 hdh_supr(unit, lcn, cc); 536 537 } 538 539 /* 540 * Ack the interrupt 541 */ 542 addr->staack = 1; 543 if (!(addr->ionmi)) { 544 addr->ionmi = 1; 545 addr->csr = HDH_DMA|HDH_WRT|HDH_IEN|HDH_NMI; 546 } 547 } 548 549 /* 550 * data channel interrupt completion handler 551 */ 552 hdh_data(unit, lcn, cc, rcnt) 553 int unit, lcn, cc, rcnt; 554 { 555 register struct hdh_softc *sc = &hdh_softc[unit]; 556 register struct hdh_chan *hc = &sc->hdh_chan[lcn]; 557 register struct mbuf *m; 558 559 560 /* was it read or write? */ 561 562 if (hc->hc_func & HDHRDB) { 563 if (cc == HDHIOCOK) { 564 /* 565 * Queue good packet for input 566 */ 567 sc->hdh_if->if_ipackets++; 568 m = if_rubaget(&sc->hdh_ifuba[lcn>>1], rcnt, 0, 569 sc->hdh_if); 570 impinput(unit, m); 571 } 572 573 /* hang a new data read */ 574 575 hdh_iorq(unit, lcn, IMPMTU, HDHRDB+HDHSTR); 576 577 } else { 578 /* 579 * fire up next output 580 */ 581 sc->hdh_if->if_opackets++; 582 sc->hdh_ic->ic_oactive = 0; 583 hdhstart(unit); 584 } 585 } 586 587 /* 588 * supervisor channel interrupt completion handler 589 */ 590 hdh_supr(unit, lcn, cc) 591 int unit, lcn, cc; 592 { 593 register struct hdh_softc *sc = &hdh_softc[unit]; 594 register struct hdh_chan *hc = &sc->hdh_chan[lcn]; 595 short *p; 596 597 598 /* was it read or write? */ 599 600 if (hc->hc_func & HDHRDB) { 601 if (cc == HDHIOCOK) { 602 p = (short *)(sc->hdh_ifuba[lcn>>1].ifu_r.ifrw_addr); 603 604 /* figure out what kind of supervisor message */ 605 606 switch (*p) { 607 608 case HDHIACK: 609 case HDHLNACK: 610 break; 611 612 case HDHLNUP: 613 printf("hdh%d: LINE UP\n", unit); 614 sc->hdh_flags |= HDH_UP; 615 hdhstart(unit); 616 break; 617 618 case HDHLNDN: 619 if (sc->hdh_flags & HDH_UP) 620 printf("hdh%d: LINE DOWN\n", unit); 621 sc->hdh_flags &= ~HDH_UP; 622 break; 623 624 case HDHLOOP: 625 break; 626 627 case HDHSQERR: 628 printf("hdh%d: HOST SEQUENCE ERROR\n", unit); 629 break; 630 631 case HDHSQRCV: 632 printf("hdh%d: IMP SEQUENCE ERROR\n", unit); 633 break; 634 635 case HDHDTERR: 636 printf("hdh%d: HOST DATA ERROR\n", unit); 637 break; 638 639 case HDHTIMO: 640 printf("hdh%d: TIMEOUT\n", unit); 641 break; 642 643 default: 644 printf("hdh%d: supervisor error, code=%x\n", 645 unit, *p); 646 } 647 } 648 649 /* hang a new supr read */ 650 651 hdh_iorq(unit, HDHSUPR, IMPMTU, HDHRDB+HDHSTR); 652 } 653 } 654 655 snd_supr(unit, msg, len) 656 int unit, len; 657 char *msg; 658 { 659 register struct hdh_softc *sc = &hdh_softc[unit]; 660 register struct mbuf *m; 661 register char *p; 662 register int cnt; 663 664 if ((m = m_get(M_DONTWAIT, MT_DATA)) == NULL) { 665 printf("hdh%d: cannot get supervisor cmnd buffer\n", unit); 666 return(0); 667 } 668 669 cnt = len; 670 m->m_len = len; 671 p = mtod(m, char *); 672 673 while(cnt--) *p++ = *msg++; 674 675 cnt = if_wubaput(&sc->hdh_ifuba[SUPR], m); 676 677 hdh_iorq(unit, HDHSUPW, cnt, HDHWRT+HDHEOS); 678 679 return(1); 680 } 681 #endif NHDH 682