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