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