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