xref: /csrg-svn/sys/vax/if/if_css.c (revision 34273)
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.4 (Berkeley) 05/14/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         register 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->ui_driver->ud_dname, ui->ui_unit,
138 	    cssreset)) == 0)
139                 return;
140 	ip = &sc->css_imp->imp_cb;
141         ip->ic_init = cssinit;
142         ip->ic_output = cssoutput;
143         ip->ic_down = cssdown;
144 	sc->css_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEED16;
145 #ifdef notdef
146 	sc->css_ifuba.ifu_flags |= UBA_NEEDBDP;
147 #endif
148 }
149 
150 /*
151  * Reset interface after UNIBUS reset.
152  * If interface is on specified uba, reset its state.
153  */
154 cssreset(unit, uban)
155         int unit, uban;
156 {
157         register struct uba_device *ui;
158         register struct css_softc *sc;
159 
160         if (unit >= NCSS || (ui = cssinfo[unit]) == 0 || ui->ui_alive == 0 ||
161             ui->ui_ubanum != uban)
162                 return;
163         printf(" css%d", unit);
164         sc = &css_softc[unit];
165 	sc->css_imp->imp_if.if_flags &= ~IFF_RUNNING;
166 	cssoflush(unit);
167         /* must go through IMP to allow it to set state */
168         (*sc->css_imp->imp_if.if_init)(sc->css_imp->imp_if.if_unit);
169 }
170 
171 /*
172  * Initialize interface: clear recorded pending operations,
173  * and retrieve, and reinitialize UNIBUS resources.
174  */
175 cssinit(unit)
176         int unit;
177 {
178         register struct css_softc *sc;
179         register struct uba_device *ui;
180         register struct cssdevice *addr;
181         int x, info;
182 
183 	if (unit >= NCSS || (ui = cssinfo[unit]) == 0 || ui->ui_alive == 0) {
184 		printf("css%d: not alive\n", unit);
185 		return(0);
186 	}
187 	sc = &css_softc[unit];
188 
189 	/*
190 	 * Header length is 0 to if_ubainit since we have to pass
191 	 * the IMP leader up to the protocol interpretaion
192 	 * routines.  If we had the deader length as
193 	 * sizeof(struct imp_leader), then the if_ routines
194 	 * would assume we handle it on input and output.
195 	 */
196 
197         if ((sc->css_imp->imp_if.if_flags & IFF_RUNNING) == 0 &&
198 	    if_ubainit(&sc->css_ifuba, ui->ui_ubanum, 0,
199 	    (int)btoc(IMP_RCVBUF)) == 0) {
200                 printf("css%d: can't initialize\n", unit);
201 		ui->ui_alive = 0;
202 		sc->css_imp->imp_if.if_flags &= ~(IFF_UP | IFF_RUNNING);
203 		return(0);
204         }
205 	sc->css_imp->imp_if.if_flags |= IFF_RUNNING;
206         addr = (struct cssdevice *)ui->ui_addr;
207 
208         /* reset the imp interface. */
209         x = spl5();
210         addr->css_icsr = CSS_CLR;
211         addr->css_ocsr = CSS_CLR;
212 	DELAY(100);
213 	addr->css_icsr = 0;
214 	addr->css_ocsr = 0;
215         addr->css_icsr = IN_HRDY;       /* close the relay */
216 	DELAY(5000);
217         splx(x);
218 
219         /*
220 	 * This may hang if the imp isn't really there.
221 	 * Will test and verify safe operation.
222 	 */
223 
224 	x = 500;
225 	while (x-- > 0) {
226 		if ((addr->css_icsr & (IN_HRDY|IN_IMPNR)) == IN_HRDY)
227 			break;
228                 addr->css_icsr = IN_HRDY;	/* close the relay */
229                 DELAY(5000);
230         }
231 
232 	if (x <= 0) {
233 		printf("css%d: imp doesn't respond, icsr=%b\n", unit,
234 			CSS_INBITS, addr->css_icsr);
235 		goto down;
236 	}
237 
238         /*
239          * Put up a read.  We can't restart any outstanding writes
240          * until we're back in synch with the IMP (i.e. we've flushed
241          * the NOOPs it throws at us).
242 	 * Note: IMP_RCVBUF includes the leader.
243          */
244 
245         x = spl5();
246         info = sc->css_ifuba.ifu_r.ifrw_info;
247         addr->css_iba = (u_short)info;
248         addr->css_iwc = -(IMP_RCVBUF >> 1);
249         addr->css_icsr =
250                 IN_HRDY | CSS_IE | IN_WEN | ((info & 0x30000) >> 12) | CSS_GO;
251         splx(x);
252 	return(1);
253 
254 down:
255 	ui->ui_alive = 0;
256 	return(0);
257 }
258 
259 /*
260  * Drop the host ready line to mark host down.
261  * UNTESTED.
262  */
263 cssdown(unit)
264 	int unit;
265 {
266         register struct cssdevice *addr;
267 
268 	addr = (struct cssdevice *)(cssinfo[unit]->ui_addr);
269         /* reset the imp interface. */
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 	cssoflush(unit);
276 	return (1);
277 }
278 
279 cssoflush(unit)
280 	int unit;
281 {
282 	register struct acc_softc *sc = &acc_softc[unit];
283 
284 	sc->acc_imp->imp_cb.ic_oactive = 0;
285 	if (sc->acc_ifuba.ifu_xtofree) {
286 		m_freem(sc->acc_ifuba.ifu_xtofree);
287 		sc->acc_ifuba.ifu_xtofree = 0;
288 	}
289 }
290 
291 /*
292  * Start output on an interface.
293  */
294 cssoutput(unit, m)
295         int unit;
296         struct mbuf *m;
297 {
298         int info;
299         struct uba_device *ui = cssinfo[unit];
300         register struct css_softc *sc = &css_softc[unit];
301         register struct cssdevice *addr;
302 
303         sc->css_olen = if_wubaput(&sc->css_ifuba, m);
304         /*
305          * Have request mapped to UNIBUS for transmission.
306          * Purge any stale data from the BDP, and start the output.
307          */
308 	if (sc->css_ifuba.ifu_flags & UBA_NEEDBDP)
309 		UBAPURGE(sc->css_ifuba.ifu_uba, sc->css_ifuba.ifu_w.ifrw_bdp);
310         addr = (struct cssdevice *)ui->ui_addr;
311         info = sc->css_ifuba.ifu_w.ifrw_info;
312         addr->css_oba = (u_short)info;
313         addr->css_owc = -((sc->css_olen + 1) >> 1);
314         addr->css_ocsr =
315 	    (u_short)(CSS_IE | OUT_ENLB | ((info & 0x30000) >> 12) | CSS_GO);
316         sc->css_imp->imp_cb.ic_oactive = 1;
317 }
318 
319 /*
320  * Output interrupt handler.
321  */
322 cssxint(unit)
323 {
324         register struct uba_device *ui = cssinfo[unit];
325         register struct css_softc *sc = &css_softc[unit];
326         register struct cssdevice *addr;
327 
328         addr = (struct cssdevice *)ui->ui_addr;
329         if (sc->css_imp->imp_cb.ic_oactive == 0) {
330                 printf("css%d: stray output interrupt csr=%b\n",
331 			unit, addr->css_ocsr, CSS_OUTBITS);
332                 return;
333         }
334         sc->css_imp->imp_if.if_opackets++;
335         sc->css_imp->imp_cb.ic_oactive = 0;
336         if (addr->css_ocsr & CSS_ERR){
337                 sc->css_imp->imp_if.if_oerrors++;
338                 printf("css%d: output error, ocsr=%b icsr=%b\n", unit,
339                         addr->css_ocsr, CSS_OUTBITS,
340 			addr->css_icsr, CSS_INBITS);
341 	}
342 	if (sc->css_ifuba.ifu_xtofree) {
343 		m_freem(sc->css_ifuba.ifu_xtofree);
344 		sc->css_ifuba.ifu_xtofree = 0;
345 	}
346 	impstart(sc->css_imp);
347 }
348 
349 /*
350  * Input interrupt handler
351  */
352 cssrint(unit)
353 {
354         register struct css_softc *sc = &css_softc[unit];
355         register struct cssdevice *addr;
356         struct mbuf *m;
357         int len, info;
358 
359         sc->css_imp->imp_if.if_ipackets++;
360 
361         /*
362          * Purge BDP; flush message if error indicated.
363          */
364 
365         addr = (struct cssdevice *)cssinfo[unit]->ui_addr;
366 	if (sc->css_ifuba.ifu_flags & UBA_NEEDBDP)
367 		UBAPURGE(sc->css_ifuba.ifu_uba, sc->css_ifuba.ifu_r.ifrw_bdp);
368         if (addr->css_icsr & CSS_ERR) {
369                 printf("css%d: recv error, csr=%b\n", unit,
370                     addr->css_icsr, CSS_INBITS);
371                 sc->css_imp->imp_if.if_ierrors++;
372                 sc->css_flush = 1;
373         }
374 
375         if (sc->css_flush) {
376                 if (addr->css_icsr & IN_EOM)
377                         sc->css_flush = 0;
378                 goto setup;
379         }
380 
381         len = IMP_RCVBUF + (addr->css_iwc << 1);
382 	if (len < 0 || len > IMP_RCVBUF) {
383 		printf("css%d: bad length=%d\n", len);
384 		sc->css_imp->imp_if.if_ierrors++;
385 		goto setup;
386 	}
387 
388         /*
389          * The offset parameter is always 0 since using
390          * trailers on the ARPAnet is insane.
391          */
392         m = if_rubaget(&sc->css_ifuba, len, 0, &sc->css_imp->imp_if);
393         if (m == 0)
394                 goto setup;
395         if ((addr->css_icsr & IN_EOM) == 0) {
396 		if (sc->css_iq)
397 			m_cat(sc->css_iq, m);
398 		else
399 			sc->css_iq = m;
400 		goto setup;
401 	}
402 	if (sc->css_iq) {
403 		m_cat(sc->css_iq, m);
404 		m = sc->css_iq;
405 		sc->css_iq = 0;
406         }
407         impinput(unit, m);
408 
409 setup:
410         /*
411          * Setup for next message.
412          */
413         info = sc->css_ifuba.ifu_r.ifrw_info;
414         addr->css_iba = (u_short)info;
415         addr->css_iwc = - (IMP_RCVBUF >> 1);
416         addr->css_icsr =
417                 IN_HRDY | CSS_IE | IN_WEN | ((info & 0x30000) >> 12) | CSS_GO;
418 }
419 #endif
420