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