now compiles under 4.3
[unix-history] / usr / src / sys / vax / if / if_hdh.c
CommitLineData
e6dd5973 1/* @(#)if_hdh.c 6.2 (Berkeley) %G% */
a0c9a57d
MK
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
31File:
32 if_hdh.c
33
34Author:
35 Art Berggreen
36
37Project:
38 4.2BSD HDH
39
40Function:
41 Device specific driver for IF-11/HDH under 4.2BSD
42 networking code.
43
44Revision 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
e6dd5973
MK
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"
a0c9a57d
MK
74
75#include "../net/if.h"
76#include "../netimp/if_imp.h"
77
78#include "../vax/cpu.h"
79#include "../vax/mtpr.h"
a0c9a57d
MK
80#include "../vaxuba/ubareg.h"
81#include "../vaxuba/ubavar.h"
82
e6dd5973
MK
83#include "if_hdhreg.h"
84#include "if_uba.h"
85
a0c9a57d
MK
86int hdhprobe(), hdhattach(), hdhrint(), hdhxint();
87struct uba_device *hdhinfo[NHDH];
88u_short hdhstd[] = { 0 };
89struct uba_driver hdhdriver =
90 { hdhprobe, 0, hdhattach, 0, hdhstd, "hdh", hdhinfo };
91
92#define HDHUNIT(x) minor(x)
93
94int 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
138struct 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
149struct 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
154struct 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 */
170hdhprobe(reg)
171caddr_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 */
208hdhattach(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)
e6dd5973 219 return;;
a0c9a57d
MK
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 */
231hdhreset(unit, uban)
232int 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);
e6dd5973
MK
245 sc->hdh_if->if_flags &= ~IFF_RUNNING;
246 sc->hdh_flags = 0;
a0c9a57d
MK
247 (*sc->hdh_if->if_init)(unit);
248}
249
250/*
251 * Initialize the imp interface.
252 */
253
254static 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
275hdhinit(unit)
276int 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
e6dd5973 297 if (sc->hdh_flags & HDH_STARTED)
a0c9a57d 298 return(1);
a0c9a57d
MK
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
e6dd5973 313 sc->hdh_if->if_flags |= IFF_RUNNING;
a0c9a57d
MK
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 */
338hdhstart(dev)
339dev_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 */
376hdh_iorq(unit, lcn, len, func)
377int 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
429start_chn(unit)
430int 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 */
458hdhintr(unit)
459int 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 */
557hdh_data(unit, lcn, cc, rcnt)
558int 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++;
e6dd5973
MK
573 m = if_rubaget(&sc->hdh_ifuba[lcn>>1], rcnt, 0,
574 sc->hdh_if);
a0c9a57d
MK
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 */
595hdh_supr(unit, lcn, cc, rcnt)
596int 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
662snd_supr(unit, msg, len)
663int unit, len;
664char *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