|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution is only permitted until one year after the first shipment
6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
7: * binary forms are permitted provided that: (1) source distributions retain
8: * this entire copyright notice and comment, and (2) distributions including
9: * binaries display the following acknowledgement: This product includes
10: * software developed by the University of California, Berkeley and its
11: * contributors'' in the documentation or other materials provided with the
12: * distribution and in all advertising materials mentioning features or use
13: * of this software. Neither the name of the University nor the names of
14: * its contributors may be used to endorse or promote products derived from
15: * this software without specific prior written permission.
16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19: *
20: * @(#)if_acc.c 7.7 (Berkeley) 6/28/90
21: */
22:
23: #include "acc.h"
24: #if NACC > 0
25:
26: /*
27: * ACC LH/DH ARPAnet IMP interface driver.
28: */
29: #include "machine/pte.h"
30:
31: #include "param.h"
32: #include "systm.h"
33: #include "mbuf.h"
34: #include "buf.h"
35: #include "protosw.h"
36: #include "socket.h"
37: #include "vmmac.h"
38:
39: #include "../net/if.h"
40: #include "../netimp/if_imp.h"
41:
42: #include "../vax/cpu.h"
43: #include "../vax/mtpr.h"
44: #include "if_accreg.h"
45: #include "if_uba.h"
46: #include "../vaxuba/ubareg.h"
47: #include "../vaxuba/ubavar.h"
48:
49: int accprobe(), accattach(), accrint(), accxint();
50: struct uba_device *accinfo[NACC];
51: u_short accstd[] = { 0 };
52: struct uba_driver accdriver =
53: { accprobe, 0, accattach, 0, accstd, "acc", accinfo };
54:
55: int accinit(), accoutput(), accdown(), accreset();
56:
57: /*
58: * "Lower half" of IMP interface driver.
59: *
60: * Each IMP interface is handled by a common module which handles
61: * the IMP-host protocol and a hardware driver which manages the
62: * hardware specific details of talking with the IMP.
63: *
64: * The hardware portion of the IMP driver handles DMA and related
65: * management of UNIBUS resources. The IMP protocol module interprets
66: * contents of these messages and "controls" the actions of the
67: * hardware module during IMP resets, but not, for instance, during
68: * UNIBUS resets.
69: *
70: * The two modules are coupled at "attach time", and ever after,
71: * through the imp interface structure. Higher level protocols,
72: * e.g. IP, interact with the IMP driver, rather than the ACC.
73: */
74: struct acc_softc {
75: struct imp_softc *acc_imp; /* data structure shared with IMP */
76: struct ifuba acc_ifuba; /* UNIBUS resources */
77: struct mbuf *acc_iq; /* input reassembly queue */
78: short acc_olen; /* size of last message sent */
79: char acc_flush; /* flush remainder of message */
80: } acc_softc[NACC];
81:
82: /*
83: * Reset the IMP and cause a transmitter interrupt by
84: * performing a null DMA.
85: */
86: accprobe(reg)
87: caddr_t reg;
88: {
89: register int br, cvec; /* r11, r10 value-result */
90: register struct accdevice *addr = (struct accdevice *)reg;
91:
92: #ifdef lint
93: br = 0; cvec = br; br = cvec;
94: accrint(0); accxint(0);
95: #endif
96: addr->icsr = ACC_RESET; DELAY(5000);
97: addr->ocsr = ACC_RESET; DELAY(5000);
98: addr->ocsr = OUT_BBACK; DELAY(5000);
99: addr->owc = 0;
100: addr->ocsr = ACC_IE | ACC_GO; DELAY(5000);
101: addr->ocsr = 0;
102: if (cvec && cvec != 0x200) /* transmit -> receive */
103: cvec -= 4;
104: return (1);
105: }
106:
107: /*
108: * Call the IMP module to allow it to set up its internal
109: * state, then tie the two modules together by setting up
110: * the back pointers to common data structures.
111: */
112: accattach(ui)
113: register struct uba_device *ui;
114: {
115: register struct acc_softc *sc = &acc_softc[ui->ui_unit];
116: register struct impcb *ip;
117:
118: if ((sc->acc_imp = impattach(ui->ui_driver->ud_dname, ui->ui_unit,
119: accreset)) == 0)
120: return;
121: ip = &sc->acc_imp->imp_cb;
122: ip->ic_init = accinit;
123: ip->ic_output = accoutput;
124: ip->ic_down = accdown;
125: sc->acc_ifuba.ifu_flags = UBA_CANTWAIT;
126: #ifdef notdef
127: sc->acc_ifuba.ifu_flags |= UBA_NEEDBDP;
128: #endif
129: }
130:
131: /*
132: * Reset interface after UNIBUS reset.
133: * If interface is on specified uba, reset its state.
134: */
135: accreset(unit, uban)
136: int unit, uban;
137: {
138: register struct uba_device *ui;
139: struct acc_softc *sc;
140:
141: if (unit >= NACC || (ui = accinfo[unit]) == 0 || ui->ui_alive == 0 ||
142: ui->ui_ubanum != uban)
143: return;
144: printf(" acc%d", unit);
145: sc = &acc_softc[unit];
146: sc->acc_imp->imp_if.if_flags &= ~IFF_RUNNING;
147: accoflush(unit);
148: /* must go through IMP to allow it to set state */
149: (*sc->acc_imp->imp_if.if_init)(sc->acc_imp->imp_if.if_unit);
150: }
151:
152: /*
153: * Initialize interface: clear recorded pending operations,
154: * and retrieve, and initialize UNIBUS resources. Note
155: * return value is used by IMP init routine to mark IMP
156: * unavailable for outgoing traffic.
157: */
158: accinit(unit)
159: int unit;
160: {
161: register struct acc_softc *sc;
162: register struct uba_device *ui;
163: register struct accdevice *addr;
164: int info;
165:
166: if (unit >= NACC || (ui = accinfo[unit]) == 0 || ui->ui_alive == 0) {
167: printf("acc%d: not alive\n", unit);
168: return (0);
169: }
170: sc = &acc_softc[unit];
171: /*
172: * Header length is 0 since we have to passs
173: * the IMP leader up to the protocol interpretation
174: * routines. If we had the header length as
175: * sizeof(struct imp_leader), then the if_ routines
176: * would asssume we handle it on input and output.
177: */
178: if ((sc->acc_imp->imp_if.if_flags & IFF_RUNNING) == 0 &&
179: if_ubainit(&sc->acc_ifuba, ui->ui_ubanum, 0,
180: (int)btoc(IMP_RCVBUF)) == 0) {
181: printf("acc%d: can't initialize\n", unit);
182: sc->acc_imp->imp_if.if_flags &= ~(IFF_UP | IFF_RUNNING);
183: return (0);
184: }
185: sc->acc_imp->imp_if.if_flags |= IFF_RUNNING;
186: addr = (struct accdevice *)ui->ui_addr;
187:
188: /*
189: * Reset the imp interface;
190: * the delays are pure guesswork.
191: */
192: addr->ocsr = ACC_RESET; DELAY(5000);
193: addr->ocsr = OUT_BBACK; DELAY(5000); /* reset host master ready */
194: addr->ocsr = 0;
195: if (accinputreset(addr, unit) == 0) {
196: ui->ui_alive = 0;
197: return (0);
198: }
199:
200: /*
201: * Put up a read. We can't restart any outstanding writes
202: * until we're back in synch with the IMP (i.e. we've flushed
203: * the NOOPs it throws at us).
204: * Note: IMP_RCVBUF includes the leader.
205: */
206: info = sc->acc_ifuba.ifu_r.ifrw_info;
207: addr->iba = (u_short)info;
208: addr->iwc = -((IMP_RCVBUF) >> 1);
209: #ifdef LOOPBACK
210: addr->ocsr |= OUT_BBACK;
211: #endif
212: addr->icsr =
213: IN_MRDY | ACC_IE | IN_WEN | ((info & 0x30000) >> 12) | ACC_GO;
214: return (1);
215: }
216:
217: accinputreset(addr, unit)
218: register struct accdevice *addr;
219: register int unit;
220: {
221: register int i;
222:
223: addr->icsr = ACC_RESET; DELAY(5000);
224: addr->icsr = IN_MRDY | IN_WEN; /* close the relay */
225: DELAY(10000);
226: /* YECH!!! */
227: for (i = 0; i < 500; i++) {
228: if ((addr->icsr & IN_HRDY) ||
229: (addr->icsr & (IN_RMR | IN_IMPBSY)) == 0)
230: return (1);
231: addr->icsr = IN_MRDY | IN_WEN; DELAY(10000);
232: /* keep turning IN_RMR off */
233: }
234: printf("acc%d: imp doesn't respond, icsr=%b\n", unit,
235: addr->icsr, ACC_INBITS);
236: return (0);
237: }
238:
239: /*
240: * Drop the host ready line to mark host down.
241: */
242: accdown(unit)
243: int unit;
244: {
245: register struct accdevice *addr;
246:
247: addr = (struct accdevice *)(accinfo[unit]->ui_addr);
248: addr->ocsr = ACC_RESET;
249: DELAY(5000);
250: addr->ocsr = OUT_BBACK; /* reset host master ready */
251: accoflush(unit);
252: return (1);
253: }
254:
255: accoflush(unit)
256: int unit;
257: {
258: register struct acc_softc *sc = &acc_softc[unit];
259:
260: sc->acc_imp->imp_cb.ic_oactive = 0;
261: if (sc->acc_ifuba.ifu_xtofree) {
262: m_freem(sc->acc_ifuba.ifu_xtofree);
263: sc->acc_ifuba.ifu_xtofree = 0;
264: }
265: }
266:
267: /*
268: * Start output on an interface.
269: */
270: accoutput(unit, m)
271: int unit;
272: struct mbuf *m;
273: {
274: int info;
275: register struct acc_softc *sc = &acc_softc[unit];
276: register struct accdevice *addr;
277: u_short cmd;
278:
279: sc->acc_olen = if_wubaput(&sc->acc_ifuba, m);
280: /*
281: * Have request mapped to UNIBUS for
282: * transmission; start the output.
283: */
284: if (sc->acc_ifuba.ifu_flags & UBA_NEEDBDP)
285: UBAPURGE(sc->acc_ifuba.ifu_uba, sc->acc_ifuba.ifu_w.ifrw_bdp);
286: addr = (struct accdevice *)accinfo[unit]->ui_addr;
287: info = sc->acc_ifuba.ifu_w.ifrw_info;
288: addr->oba = (u_short)info;
289: addr->owc = -((sc->acc_olen + 1) >> 1);
290: cmd = ACC_IE | OUT_ENLB | ((info & 0x30000) >> 12) | ACC_GO;
291: #ifdef LOOPBACK
292: cmd |= OUT_BBACK;
293: #endif
294: addr->ocsr = cmd;
295: sc->acc_imp->imp_cb.ic_oactive = 1;
296: }
297:
298: /*
299: * Output interrupt handler.
300: */
301: accxint(unit)
302: int unit;
303: {
304: register struct acc_softc *sc = &acc_softc[unit];
305: register struct accdevice *addr;
306:
307: addr = (struct accdevice *)accinfo[unit]->ui_addr;
308: if (sc->acc_imp->imp_cb.ic_oactive == 0) {
309: printf("acc%d: stray xmit interrupt, csr=%b\n", unit,
310: addr->ocsr, ACC_OUTBITS);
311: return;
312: }
313: sc->acc_imp->imp_if.if_opackets++;
314: sc->acc_imp->imp_cb.ic_oactive = 0;
315: if (addr->ocsr & ACC_ERR) {
316: printf("acc%d: output error, ocsr=%b, icsr=%b\n", unit,
317: addr->ocsr, ACC_OUTBITS, addr->icsr, ACC_INBITS);
318: sc->acc_imp->imp_if.if_oerrors++;
319: }
320: if (sc->acc_ifuba.ifu_xtofree) {
321: m_freem(sc->acc_ifuba.ifu_xtofree);
322: sc->acc_ifuba.ifu_xtofree = 0;
323: }
324: impstart(sc->acc_imp);
325: }
326:
327: /*
328: * Input interrupt handler
329: */
330: accrint(unit)
331: int unit;
332: {
333: register struct acc_softc *sc = &acc_softc[unit];
334: register struct accdevice *addr;
335: struct mbuf *m;
336: int len, info;
337:
338: addr = (struct accdevice *)accinfo[unit]->ui_addr;
339: sc->acc_imp->imp_if.if_ipackets++;
340:
341: /*
342: * Purge BDP; flush message if error indicated.
343: */
344: if (sc->acc_ifuba.ifu_flags & UBA_NEEDBDP)
345: UBAPURGE(sc->acc_ifuba.ifu_uba, sc->acc_ifuba.ifu_r.ifrw_bdp);
346: if (addr->icsr & ACC_ERR) {
347: printf("acc%d: input error, csr=%b\n", unit,
348: addr->icsr, ACC_INBITS);
349: sc->acc_imp->imp_if.if_ierrors++;
350: sc->acc_flush = 1;
351: }
352:
353: if (sc->acc_flush) {
354: if (addr->icsr & IN_EOM)
355: sc->acc_flush = 0;
356: goto setup;
357: }
358: len = IMP_RCVBUF + (addr->iwc << 1);
359: if (len < 0 || len > IMP_RCVBUF) {
360: printf("acc%d: bad length=%d\n", unit, len);
361: sc->acc_imp->imp_if.if_ierrors++;
362: goto setup;
363: }
364:
365: /*
366: * The offset parameter is always 0 since using
367: * trailers on the ARPAnet is insane.
368: */
369: m = if_rubaget(&sc->acc_ifuba, len, 0, &sc->acc_imp->imp_if);
370: if (m == 0)
371: goto setup;
372: if ((addr->icsr & IN_EOM) == 0) {
373: if (sc->acc_iq)
374: m_cat(sc->acc_iq, m);
375: else
376: sc->acc_iq = m;
377: goto setup;
378: }
379: if (sc->acc_iq) {
380: m_cat(sc->acc_iq, m);
381: m = sc->acc_iq;
382: sc->acc_iq = 0;
383: }
384: impinput(unit, m);
385:
386: setup:
387: /*
388: * Setup for next message.
389: */
390: info = sc->acc_ifuba.ifu_r.ifrw_info;
391: addr->iba = (u_short)info;
392: addr->iwc = -((IMP_RCVBUF)>> 1);
393: addr->icsr =
394: IN_MRDY | ACC_IE | IN_WEN | ((info & 0x30000) >> 12) | ACC_GO;
395: }
396: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.