xref: /csrg-svn/sys/vax/if/if_css.c (revision 7468)
1*7468Ssam /*      if_css.c     4.1     82/07/20     */
2*7468Ssam 
3*7468Ssam #include "css.h"
4*7468Ssam 
5*7468Ssam /*
6*7468Ssam  * DEC/CSS IMP11-A ARPAnet IMP interface driver.
7*7468Ssam  * Since "imp11a" is such a mouthful, it is called
8*7468Ssam  * "css" after the LH/DH being called "acc".
9*7468Ssam  *
10*7468Ssam  * Configuration notes:
11*7468Ssam  *
12*7468Ssam  * As delivered from DEC/CSS, it
13*7468Ssam  * is addressed and vectored as two DR11-B's.  This makes
14*7468Ssam  * Autoconfig almost IMPOSSIBLE.  To make it work, the
15*7468Ssam  * interrupt vectors must be restrapped to make the vectors
16*7468Ssam  * consecutive.  The 020 hole between the CSR addresses is
17*7468Ssam  * tolerated, althought that could be cleaned-up also.
18*7468Ssam  *
19*7468Ssam  * Additionally, the TRANSMIT side of the IMP11-A has the
20*7468Ssam  * lower address of the two subunits, so the vector ordering
21*7468Ssam  * in the CONFIG file is reversed from most other devices.
22*7468Ssam  * It should be:
23*7468Ssam  *
24*7468Ssam  * device css0 ....  cssxint cssrint
25*7468Ssam  *
26*7468Ssam  * If you get it wrong, it will still autoconfig, but will just
27*7468Ssam  * sit there with RECIEVE IDLE indicated on the front panel.
28*7468Ssam  */
29*7468Ssam 
30*7468Ssam #include "../h/param.h"
31*7468Ssam #include "../h/systm.h"
32*7468Ssam #include "../h/mbuf.h"
33*7468Ssam #include "../h/pte.h"
34*7468Ssam #include "../h/buf.h"
35*7468Ssam #include "../h/protosw.h"
36*7468Ssam #include "../h/socket.h"
37*7468Ssam #include "../h/ubareg.h"
38*7468Ssam #include "../h/ubavar.h"
39*7468Ssam #include "../h/cpu.h"
40*7468Ssam #include "../h/mtpr.h"
41*7468Ssam #include "../h/vmmac.h"
42*7468Ssam #include "../net/if_css.h"
43*7468Ssam #include "../net/in.h"
44*7468Ssam #include "../net/in_systm.h"
45*7468Ssam #include "../net/if.h"
46*7468Ssam #include "../net/if_imp.h"
47*7468Ssam #include "../net/if_uba.h"
48*7468Ssam 
49*7468Ssam int     cssprobe(), cssattach(), cssrint(), cssxint();
50*7468Ssam struct  uba_device *cssinfo[NCSS];
51*7468Ssam u_short cssstd[] = { 0 };
52*7468Ssam struct  uba_driver cssdriver =
53*7468Ssam         { cssprobe, 0, cssattach, 0, cssstd, "css", cssinfo };
54*7468Ssam #define CSSUNIT(x)      minor(x)
55*7468Ssam 
56*7468Ssam int     cssinit(), cssstart(), cssreset();
57*7468Ssam 
58*7468Ssam /*
59*7468Ssam  * "Lower half" of IMP interface driver.
60*7468Ssam  *
61*7468Ssam  * Each IMP interface is handled by a common module which handles
62*7468Ssam  * the IMP-host protocol and a hardware driver which manages the
63*7468Ssam  * hardware specific details of talking with the IMP.
64*7468Ssam  *
65*7468Ssam  * The hardware portion of the IMP driver handles DMA and related
66*7468Ssam  * management of UNIBUS resources.  The IMP protocol module interprets
67*7468Ssam  * contents of these messages and "controls" the actions of the
68*7468Ssam  * hardware module during IMP resets, but not, for instance, during
69*7468Ssam  * UNIBUS resets.
70*7468Ssam  *
71*7468Ssam  * The two modules are coupled at "attach time", and ever after,
72*7468Ssam  * through the imp interface structure.  Higher level protocols,
73*7468Ssam  * e.g. IP, interact with the IMP driver, rather than the CSS.
74*7468Ssam  */
75*7468Ssam struct  css_softc {
76*7468Ssam         struct  ifnet *css_if;          /* pointer to IMP's ifnet struct */
77*7468Ssam         struct  impcb *css_ic;          /* data structure shared with IMP */
78*7468Ssam         struct  ifuba css_ifuba;        /* UNIBUS resources */
79*7468Ssam         struct  mbuf *css_iq;           /* input reassembly queue */
80*7468Ssam         short   css_olen;               /* size of last message sent */
81*7468Ssam         char    css_flush;              /* flush remainder of message */
82*7468Ssam } css_softc[NCSS];
83*7468Ssam 
84*7468Ssam /*
85*7468Ssam  * Reset the IMP and cause a transmitter interrupt by
86*7468Ssam  * performing a null DMA.
87*7468Ssam  */
88*7468Ssam cssprobe(reg)
89*7468Ssam         caddr_t reg;
90*7468Ssam {
91*7468Ssam         register int br, cvec;          /* r11, r10 value-result */
92*7468Ssam         register struct cssdevice *addr = (struct cssdevice *)reg;
93*7468Ssam 
94*7468Ssam COUNT(CSSPROBE);
95*7468Ssam #ifdef lint
96*7468Ssam         br = 0; cvec = br; br = cvec;
97*7468Ssam         cssrint(0); cssxint(0);
98*7468Ssam #endif
99*7468Ssam 
100*7468Ssam 
101*7468Ssam         addr->css_icsr = CSS_CLR;
102*7468Ssam         addr->css_ocsr = CSS_CLR;
103*7468Ssam         DELAY(50000);
104*7468Ssam 	addr->css_icsr = 0;
105*7468Ssam 	addr->css_ocsr = 0;
106*7468Ssam         DELAY(50000);
107*7468Ssam 
108*7468Ssam 	addr->css_oba = 0;
109*7468Ssam 	addr->css_owc = -1;
110*7468Ssam         addr->css_ocsr = CSS_IE | CSS_GO;	/* enable interrupts */
111*7468Ssam         DELAY(50000);
112*7468Ssam         addr->css_ocsr = 0;
113*7468Ssam 
114*7468Ssam         return (1);
115*7468Ssam }
116*7468Ssam 
117*7468Ssam /*
118*7468Ssam  * Call the IMP module to allow it to set up its internal
119*7468Ssam  * state, then tie the two modules together by setting up
120*7468Ssam  * the back pointers to common data structures.
121*7468Ssam  */
122*7468Ssam cssattach(ui)
123*7468Ssam         struct uba_device *ui;
124*7468Ssam {
125*7468Ssam         register struct css_softc *sc = &css_softc[ui->ui_unit];
126*7468Ssam         register struct impcb *ip;
127*7468Ssam         struct ifimpcb {
128*7468Ssam                 struct  ifnet ifimp_if;
129*7468Ssam                 struct  impcb ifimp_impcb;
130*7468Ssam         } *ifimp;
131*7468Ssam 
132*7468Ssam COUNT(CSSATTACH);
133*7468Ssam         if ((ifimp = (struct ifimpcb *)impattach(ui)) == 0)
134*7468Ssam                 panic("cssattach");             /* XXX */
135*7468Ssam         sc->css_if = &ifimp->ifimp_if;
136*7468Ssam         ip = &ifimp->ifimp_impcb;
137*7468Ssam         sc->css_ic = ip;
138*7468Ssam         ip->ic_init = cssinit;
139*7468Ssam         ip->ic_start = cssstart;
140*7468Ssam 	sc->css_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEED16;
141*7468Ssam #ifdef notdef
142*7468Ssam 	sc->css_ifuba.ifu_flags =| UBA_NEEDBDP;
143*7468Ssam #endif
144*7468Ssam }
145*7468Ssam 
146*7468Ssam /*
147*7468Ssam  * Reset interface after UNIBUS reset.
148*7468Ssam  * If interface is on specified uba, reset its state.
149*7468Ssam  */
150*7468Ssam cssreset(unit, uban)
151*7468Ssam         int unit, uban;
152*7468Ssam {
153*7468Ssam         register struct uba_device *ui;
154*7468Ssam         struct css_softc *sc;
155*7468Ssam 
156*7468Ssam COUNT(CSSCLR);
157*7468Ssam         if (unit >= NCSS || (ui = cssinfo[unit]) == 0 || ui->ui_alive == 0 ||
158*7468Ssam             ui->ui_ubanum != uban)
159*7468Ssam                 return;
160*7468Ssam         printf(" css%d", unit);
161*7468Ssam         sc = &css_softc[unit];
162*7468Ssam         /* must go through IMP to allow it to set state */
163*7468Ssam         (*sc->css_if->if_init)(unit);
164*7468Ssam }
165*7468Ssam 
166*7468Ssam /*
167*7468Ssam  * Initialize interface: clear recorded pending operations,
168*7468Ssam  * and retrieve, and reinitialize UNIBUS resources.
169*7468Ssam  */
170*7468Ssam cssinit(unit)
171*7468Ssam         int unit;
172*7468Ssam {
173*7468Ssam         register struct css_softc *sc;
174*7468Ssam         register struct uba_device *ui;
175*7468Ssam         register struct cssdevice *addr;
176*7468Ssam         int x, info;
177*7468Ssam 
178*7468Ssam COUNT(CSSINIT);
179*7468Ssam 	if (unit >= NCSS || (ui = cssinfo[unit]) == 0 || ui->ui_alive == 0) {
180*7468Ssam 		printf("css%d: not alive\n", unit);
181*7468Ssam 		return(0);
182*7468Ssam 	}
183*7468Ssam 	sc = &css_softc[unit];
184*7468Ssam 
185*7468Ssam 	/*
186*7468Ssam 	 * Header length is 0 to if_ubainit since we have to pass
187*7468Ssam 	 * the IMP leader up to the protocol interpretaion
188*7468Ssam 	 * routines.  If we had the deader length as
189*7468Ssam 	 * sizeof(struct imp_leader), then the if_ routines
190*7468Ssam 	 * would assume we handle it on input and output.
191*7468Ssam 	 */
192*7468Ssam 
193*7468Ssam         if (if_ubainit(&sc->css_ifuba, ui->ui_ubanum, 0,(int)btoc(IMPMTU)) == 0) {
194*7468Ssam                 printf("css%d: can't initialize\n", unit);
195*7468Ssam 		ui->ui_alive = 0;
196*7468Ssam 		return(0);
197*7468Ssam         }
198*7468Ssam         addr = (struct cssdevice *)ui->ui_addr;
199*7468Ssam 
200*7468Ssam         /* reset the imp interface. */
201*7468Ssam         x = spl5();
202*7468Ssam         addr->css_icsr = CSS_CLR;
203*7468Ssam         addr->css_ocsr = CSS_CLR;
204*7468Ssam 	DELAY(100);
205*7468Ssam 	addr->css_icsr = 0;
206*7468Ssam 	addr->css_ocsr = 0;
207*7468Ssam         addr->css_icsr = IN_HRDY;       /* close the relay */
208*7468Ssam 	DELAY(5000);
209*7468Ssam         splx(x);
210*7468Ssam 
211*7468Ssam         /*
212*7468Ssam 	 * This may hang if the imp isn't really there.
213*7468Ssam 	 * Will test and verify safe operation.
214*7468Ssam 	 */
215*7468Ssam 
216*7468Ssam 	x = 500;
217*7468Ssam 	while (x-- > 0) {
218*7468Ssam 		if ((addr->css_icsr & (IN_HRDY|IN_IMPNR)) == IN_HRDY)
219*7468Ssam 			break;
220*7468Ssam                 addr->css_icsr = IN_HRDY;	/* close the relay */
221*7468Ssam                 DELAY(5000);
222*7468Ssam         }
223*7468Ssam 
224*7468Ssam 	if (x <= 0) {
225*7468Ssam 		printf("css%d: imp doesn't respond, icsr=%b\n", unit,
226*7468Ssam 			CSS_INBITS, addr->css_icsr);
227*7468Ssam 		goto down;
228*7468Ssam 	}
229*7468Ssam 
230*7468Ssam         /*
231*7468Ssam          * Put up a read.  We can't restart any outstanding writes
232*7468Ssam          * until we're back in synch with the IMP (i.e. we've flushed
233*7468Ssam          * the NOOPs it throws at us).
234*7468Ssam 	 * Note: IMPMTU includes the leader.
235*7468Ssam          */
236*7468Ssam 
237*7468Ssam         x = spl5();
238*7468Ssam         info = sc->css_ifuba.ifu_r.ifrw_info;
239*7468Ssam         addr->css_iba = (u_short)info;
240*7468Ssam         addr->css_iwc = -(IMPMTU >> 1);
241*7468Ssam         addr->css_icsr =
242*7468Ssam                 IN_HRDY | CSS_IE | IN_WEN | ((info & 0x30000) >> 12) | CSS_GO;
243*7468Ssam         splx(x);
244*7468Ssam 	return(1);
245*7468Ssam 
246*7468Ssam down:
247*7468Ssam 	ui->ui_alive = 0;
248*7468Ssam 	return(0);
249*7468Ssam }
250*7468Ssam 
251*7468Ssam /*
252*7468Ssam  * Start output on an interface.
253*7468Ssam  */
254*7468Ssam cssstart(dev)
255*7468Ssam         dev_t dev;
256*7468Ssam {
257*7468Ssam         int unit = CSSUNIT(dev), info;
258*7468Ssam         struct uba_device *ui = cssinfo[unit];
259*7468Ssam         register struct css_softc *sc = &css_softc[unit];
260*7468Ssam         register struct cssdevice *addr;
261*7468Ssam         struct mbuf *m;
262*7468Ssam         u_short cmd;
263*7468Ssam 
264*7468Ssam COUNT(CSSSTART);
265*7468Ssam         if (sc->css_ic->ic_oactive)
266*7468Ssam                 goto restart;
267*7468Ssam 
268*7468Ssam         /*
269*7468Ssam          * Not already active, deqeue a request and
270*7468Ssam          * map it onto the UNIBUS.  If no more
271*7468Ssam          * requeusts, just return.
272*7468Ssam          */
273*7468Ssam         IF_DEQUEUE(&sc->css_if->if_snd, m);
274*7468Ssam         if (m == 0) {
275*7468Ssam                 sc->css_ic->ic_oactive = 0;
276*7468Ssam                 return;
277*7468Ssam         }
278*7468Ssam         sc->css_olen = if_wubaput(&sc->css_ifuba, m);
279*7468Ssam 
280*7468Ssam restart:
281*7468Ssam         /*
282*7468Ssam          * Have request mapped to UNIBUS for transmission.
283*7468Ssam          * Purge any stale data from the BDP, and start the output.
284*7468Ssam          */
285*7468Ssam 	if (sc->css_ifuba.ifu_flags & UBA_NEEDBDP)
286*7468Ssam 		UBAPURGE(sc->css_ifuba.ifu_uba, sc->css_ifuba.ifu_w.ifrw_bdp);
287*7468Ssam         addr = (struct cssdevice *)ui->ui_addr;
288*7468Ssam         info = sc->css_ifuba.ifu_w.ifrw_info;
289*7468Ssam         addr->css_oba = (u_short)info;
290*7468Ssam         addr->css_owc = -((sc->css_olen + 1) >> 1);
291*7468Ssam         cmd = CSS_IE | OUT_ENLB | ((info & 0x30000) >> 12) | CSS_GO;
292*7468Ssam         addr->css_ocsr = cmd;
293*7468Ssam         sc->css_ic->ic_oactive = 1;
294*7468Ssam }
295*7468Ssam 
296*7468Ssam /*
297*7468Ssam  * Output interrupt handler.
298*7468Ssam  */
299*7468Ssam cssxint(unit)
300*7468Ssam {
301*7468Ssam         register struct uba_device *ui = cssinfo[unit];
302*7468Ssam         register struct css_softc *sc = &css_softc[unit];
303*7468Ssam         register struct cssdevice *addr;
304*7468Ssam 
305*7468Ssam COUNT(CSSXINT);
306*7468Ssam         addr = (struct cssdevice *)ui->ui_addr;
307*7468Ssam         if (sc->css_ic->ic_oactive == 0) {
308*7468Ssam                 printf("css%d: stray output interrupt csr=%b\n",
309*7468Ssam 			unit, addr->css_ocsr, CSS_OUTBITS);
310*7468Ssam                 return;
311*7468Ssam         }
312*7468Ssam         sc->css_if->if_opackets++;
313*7468Ssam         sc->css_ic->ic_oactive = 0;
314*7468Ssam         if (addr->css_ocsr & CSS_ERR){
315*7468Ssam                 sc->css_if->if_oerrors++;
316*7468Ssam                 printf("css%d: output error, ocsr=%b icsr=%b\n", unit,
317*7468Ssam                         addr->css_ocsr, CSS_OUTBITS,
318*7468Ssam 			addr->css_icsr, CSS_INBITS);
319*7468Ssam 	}
320*7468Ssam 	if (sc->css_ifuba.ifu_xtofree) {
321*7468Ssam 		m_freem(sc->css_ifuba.ifu_xtofree);
322*7468Ssam 		sc->css_ifuba.ifu_xtofree = 0;
323*7468Ssam 	}
324*7468Ssam 	if (sc->css_if->if_snd.ifq_head)
325*7468Ssam 		cssstart(unit);
326*7468Ssam }
327*7468Ssam 
328*7468Ssam /*
329*7468Ssam  * Input interrupt handler
330*7468Ssam  */
331*7468Ssam cssrint(unit)
332*7468Ssam {
333*7468Ssam         register struct css_softc *sc = &css_softc[unit];
334*7468Ssam         register struct cssdevice *addr;
335*7468Ssam         register struct ifqueue *inq;
336*7468Ssam         struct mbuf *m;
337*7468Ssam         int len, info;
338*7468Ssam 
339*7468Ssam COUNT(CSSRINT);
340*7468Ssam         sc->css_if->if_ipackets++;
341*7468Ssam 
342*7468Ssam         /*
343*7468Ssam          * Purge BDP; flush message if error indicated.
344*7468Ssam          */
345*7468Ssam 
346*7468Ssam         addr = (struct cssdevice *)cssinfo[unit]->ui_addr;
347*7468Ssam 	if (sc->css_ifuba.ifu_flags & UBA_NEEDBDP)
348*7468Ssam 		UBAPURGE(sc->css_ifuba.ifu_uba, sc->css_ifuba.ifu_r.ifrw_bdp);
349*7468Ssam         if (addr->css_icsr & CSS_ERR) {
350*7468Ssam                 printf("css%d: recv error, csr=%b\n", unit,
351*7468Ssam                     addr->css_icsr, CSS_INBITS);
352*7468Ssam                 sc->css_if->if_ierrors++;
353*7468Ssam                 sc->css_flush = 1;
354*7468Ssam         }
355*7468Ssam 
356*7468Ssam         if (sc->css_flush) {
357*7468Ssam                 if (addr->css_icsr & IN_EOM)
358*7468Ssam                         sc->css_flush = 0;
359*7468Ssam                 goto setup;
360*7468Ssam         }
361*7468Ssam 
362*7468Ssam         len = IMPMTU + (addr->css_iwc << 1);
363*7468Ssam 	if (len < 0 || len > IMPMTU) {
364*7468Ssam 		printf("css%d: bad length=%d\n", len);
365*7468Ssam 		sc->css_if->if_ierrors++;
366*7468Ssam 		goto setup;
367*7468Ssam 	}
368*7468Ssam 
369*7468Ssam         /*
370*7468Ssam          * The last parameter is always 0 since using
371*7468Ssam          * trailers on the ARPAnet is insane.
372*7468Ssam          */
373*7468Ssam         m = if_rubaget(&sc->css_ifuba, len, 0);
374*7468Ssam         if (m == 0)
375*7468Ssam                 goto setup;
376*7468Ssam         if ((addr->css_icsr & IN_EOM) == 0) {
377*7468Ssam 		if (sc->css_iq)
378*7468Ssam 			m_cat(sc->css_iq, m);
379*7468Ssam 		else
380*7468Ssam 			sc->css_iq = m;
381*7468Ssam 		goto setup;
382*7468Ssam 	}
383*7468Ssam 	if (sc->css_iq) {
384*7468Ssam 		m_cat(sc->css_iq, m);
385*7468Ssam 		m = sc->css_iq;
386*7468Ssam 		sc->css_iq = 0;
387*7468Ssam         }
388*7468Ssam         impinput(unit, m);
389*7468Ssam 
390*7468Ssam setup:
391*7468Ssam         /*
392*7468Ssam          * Setup for next message.
393*7468Ssam          */
394*7468Ssam         info = sc->css_ifuba.ifu_r.ifrw_info;
395*7468Ssam         addr->css_iba = (u_short)info;
396*7468Ssam         addr->css_iwc = - (IMPMTU >> 1);
397*7468Ssam         addr->css_icsr =
398*7468Ssam                 IN_HRDY | CSS_IE | IN_WEN | ((info & 0x30000) >> 12) | CSS_GO;
399*7468Ssam }
400