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