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