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