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