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