merge 4.1b with 4.1c
[unix-history] / usr / src / sys / vax / if / if_dmc.c
CommitLineData
4fce3bf9 1/* if_dmc.c 4.21 82/11/13 */
63665984
BJ
2
3#include "dmc.h"
4#if NDMC > 0
5#define printd if(dmcdebug)printf
6int dmcdebug = 1;
7/*
8 * DMC11 device driver, internet version
9 *
10 * TODO
11 * allow more than one outstanding read or write.
12 */
13
14#include "../h/param.h"
15#include "../h/systm.h"
16#include "../h/mbuf.h"
17#include "../h/pte.h"
18#include "../h/buf.h"
19#include "../h/tty.h"
20#include "../h/protosw.h"
21#include "../h/socket.h"
63665984 22#include "../h/vmmac.h"
a9687d27
BJ
23#include <errno.h>
24
25#include "../net/if.h"
4fce3bf9 26#include "../net/netisr.h"
a9687d27 27#include "../net/route.h"
d2cc167c
BJ
28#include "../netinet/in.h"
29#include "../netinet/in_systm.h"
a9687d27
BJ
30
31#include "../vax/cpu.h"
32#include "../vax/mtpr.h"
d2cc167c
BJ
33#include "../vaxif/if_uba.h"
34#include "../vaxif/if_dmc.h"
a9687d27
BJ
35#include "../vaxuba/ubareg.h"
36#include "../vaxuba/ubavar.h"
63665984
BJ
37
38/*
39 * Driver information for auto-configuration stuff.
40 */
41int dmcprobe(), dmcattach(), dmcinit(), dmcoutput(), dmcreset();
42struct uba_device *dmcinfo[NDMC];
43u_short dmcstd[] = { 0 };
44struct uba_driver dmcdriver =
45 { dmcprobe, 0, dmcattach, 0, dmcstd, "dmc", dmcinfo };
46
ee787340 47#define DMC_AF 0xff /* 8 bits of address type in ui_flags */
6187f8f4 48#define DMC_NET 0xffffff00 /* 24 bits of net number in ui_flags */
63665984
BJ
49
50/*
51 * DMC software status per interface.
52 *
53 * Each interface is referenced by a network interface structure,
54 * sc_if, which the routing code uses to locate the interface.
55 * This structure contains the output queue for the interface, its address, ...
56 * We also have, for each interface, a UBA interface structure, which
57 * contains information about the UNIBUS resources held by the interface:
58 * map registers, buffered data paths, etc. Information is cached in this
59 * structure for use by the if_uba.c routines in running the interface
60 * efficiently.
61 */
62struct dmc_softc {
63 struct ifnet sc_if; /* network-visible interface */
64 struct ifuba sc_ifuba; /* UNIBUS resources */
65 short sc_flag; /* flags */
66 short sc_oactive; /* output active */
67 int sc_ubinfo; /* UBA mapping info for base table */
68 struct clist sc_que; /* command queue */
69} dmc_softc[NDMC];
70
71/* flags */
72#define DMCRUN 01
73#define DMCBMAPPED 02 /* base table mapped */
74
75struct dmc_base {
76 short d_base[128]; /* DMC base table */
77} dmc_base[NDMC];
78
79#define loword(x) ((short *)&x)[0]
80#define hiword(x) ((short *)&x)[1]
81
82dmcprobe(reg)
83 caddr_t reg;
84{
85 register int br, cvec;
86 register struct dmcdevice *addr = (struct dmcdevice *)reg;
87 register int i;
88
89#ifdef lint
90 br = 0; cvec = br; br = cvec;
91 dmcrint(0); dmcxint(0);
92#endif
93 addr->bsel1 = DMC_MCLR;
94 for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
95 ;
96 if ((addr->bsel1 & DMC_RUN) == 0)
ee787340 97 return (0);
63665984
BJ
98 addr->bsel1 &= ~DMC_MCLR;
99 addr->bsel0 = DMC_RQI|DMC_IEI;
100 DELAY(100000);
101 addr->bsel1 = DMC_MCLR;
102 for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
103 ;
7d6f1cd5
SL
104#ifdef ECHACK
105 br = 0x16;
106#endif
ee787340 107 return (1);
63665984
BJ
108}
109
110/*
111 * Interface exists: make available by filling in network interface
112 * record. System will initialize the interface when it is ready
113 * to accept packets.
114 */
115dmcattach(ui)
116 register struct uba_device *ui;
117{
118 register struct dmc_softc *sc = &dmc_softc[ui->ui_unit];
ee787340 119 register struct sockaddr_in *sin;
63665984
BJ
120
121 sc->sc_if.if_unit = ui->ui_unit;
122 sc->sc_if.if_name = "dmc";
123 sc->sc_if.if_mtu = DMCMTU;
124 sc->sc_if.if_net = (ui->ui_flags & DMC_NET) >> 8;
125 sc->sc_if.if_host[0] = 17; /* random number */
ee787340 126 sin = (struct sockaddr_in *)&sc->sc_if.if_addr;
bfa2d860 127 sin->sin_family = AF_INET;
ee787340 128 sin->sin_addr = if_makeaddr(sc->sc_if.if_net, sc->sc_if.if_host[0]);
63665984
BJ
129 sc->sc_if.if_init = dmcinit;
130 sc->sc_if.if_output = dmcoutput;
51595ca2 131 sc->sc_if.if_reset = dmcreset;
bfa2d860
SL
132 /* DON'T KNOW IF THIS WILL WORK WITH A BDP AT HIGH SPEEDS */
133 sc->sc_ifuba.ifu_flags = UBA_NEEDBDP | UBA_CANTWAIT;
63665984
BJ
134 if_attach(&sc->sc_if);
135}
136
137/*
138 * Reset of interface after UNIBUS reset.
139 * If interface is on specified UBA, reset it's state.
140 */
141dmcreset(unit, uban)
142 int unit, uban;
143{
144 register struct uba_device *ui;
145
146 if (unit >= NDMC || (ui = dmcinfo[unit]) == 0 || ui->ui_alive == 0 ||
147 ui->ui_ubanum != uban)
148 return;
149 printf(" dmc%d", unit);
150 dmcinit(unit);
151}
152
153/*
154 * Initialization of interface; reinitialize UNIBUS usage.
155 */
156dmcinit(unit)
157 int unit;
158{
159 register struct dmc_softc *sc = &dmc_softc[unit];
160 register struct uba_device *ui = dmcinfo[unit];
161 register struct dmcdevice *addr;
162 int base;
163
164 printd("dmcinit\n");
165 if ((sc->sc_flag&DMCBMAPPED) == 0) {
166 sc->sc_ubinfo = uballoc(ui->ui_ubanum,
167 (caddr_t)&dmc_base[unit], sizeof (struct dmc_base), 0);
168 sc->sc_flag |= DMCBMAPPED;
169 }
170 if (if_ubainit(&sc->sc_ifuba, ui->ui_ubanum, 0,
b3a74b5e 171 (int)btoc(DMCMTU)) == 0) {
63665984 172 printf("dmc%d: can't initialize\n", unit);
ee787340 173 sc->sc_if.if_flags &= ~IFF_UP;
63665984
BJ
174 return;
175 }
176 addr = (struct dmcdevice *)ui->ui_addr;
177 addr->bsel2 |= DMC_IEO;
178 base = sc->sc_ubinfo & 0x3ffff;
179 printd(" base 0x%x\n", base);
180 dmcload(sc, DMC_BASEI, base, (base>>2)&DMC_XMEM);
181 dmcload(sc, DMC_CNTLI, 0, 0);
182 base = sc->sc_ifuba.ifu_r.ifrw_info & 0x3ffff;
183 dmcload(sc, DMC_READ, base, ((base>>2)&DMC_XMEM)|DMCMTU);
184 printd(" first read queued, addr 0x%x\n", base);
ee787340 185 sc->sc_if.if_flags |= IFF_UP;
f6311fb6
SL
186 /* set up routing table entry */
187 if ((sc->sc_if.if_flags & IFF_ROUTE) == 0) {
a13c006d 188 rtinit(&sc->sc_if.if_addr, &sc->sc_if.if_addr, RTF_HOST|RTF_UP);
f6311fb6
SL
189 sc->sc_if.if_flags |= IFF_ROUTE;
190 }
63665984
BJ
191}
192
193/*
194 * Start output on interface. Get another datagram
195 * to send from the interface queue and map it to
196 * the interface before starting output.
197 */
198dmcstart(dev)
199 dev_t dev;
200{
201 int unit = minor(dev);
202 struct uba_device *ui = dmcinfo[unit];
203 register struct dmc_softc *sc = &dmc_softc[unit];
204 int addr, len;
205 struct mbuf *m;
206
207 printd("dmcstart\n");
208 /*
209 * Dequeue a request and map it to the UNIBUS.
210 * If no more requests, just return.
211 */
212 IF_DEQUEUE(&sc->sc_if.if_snd, m);
213 if (m == 0)
214 return;
215 len = if_wubaput(&sc->sc_ifuba, m);
216
217 /*
218 * Have request mapped to UNIBUS for transmission.
219 * Purge any stale data from this BDP and start the output.
220 */
bfa2d860 221 if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP)
791be395 222 UBAPURGE(sc->sc_ifuba.ifu_uba, sc->sc_ifuba.ifu_w.ifrw_bdp);
63665984
BJ
223 addr = sc->sc_ifuba.ifu_w.ifrw_info & 0x3ffff;
224 printd(" len %d, addr 0x%x, ", len, addr);
225 printd("mr 0x%x\n", sc->sc_ifuba.ifu_w.ifrw_mr[0]);
226 dmcload(sc, DMC_WRITE, addr, (len&DMC_CCOUNT)|((addr>>2)&DMC_XMEM));
227 sc->sc_oactive = 1;
228}
229
230/*
231 * Utility routine to load the DMC device registers.
232 */
233dmcload(sc, type, w0, w1)
234 register struct dmc_softc *sc;
235 int type, w0, w1;
236{
237 register struct dmcdevice *addr;
238 register int unit, sps, n;
239
240 printd("dmcload: 0x%x 0x%x 0x%x\n", type, w0, w1);
241 unit = sc - dmc_softc;
242 addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
243 sps = spl5();
244 if ((n = sc->sc_que.c_cc) == 0)
245 addr->bsel0 = type | DMC_RQI;
246 else
668cc26d
SL
247 (void) putc(type | DMC_RQI, &sc->sc_que);
248 (void) putw(w0, &sc->sc_que);
249 (void) putw(w1, &sc->sc_que);
63665984
BJ
250 if (n == 0)
251 dmcrint(unit);
252 splx(sps);
253}
254
255/*
256 * DMC interface receiver interrupt.
257 * Ready to accept another command,
258 * pull one off the command queue.
259 */
260dmcrint(unit)
261 int unit;
262{
263 register struct dmc_softc *sc;
264 register struct dmcdevice *addr;
265 register int n;
63665984
BJ
266
267 addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
268 sc = &dmc_softc[unit];
269 while (addr->bsel0&DMC_RDYI) {
63665984
BJ
270 addr->sel4 = getw(&sc->sc_que);
271 addr->sel6 = getw(&sc->sc_que);
63665984 272 addr->bsel0 &= ~(DMC_IEI|DMC_RQI);
63665984
BJ
273 while (addr->bsel0&DMC_RDYI)
274 ;
275 if (sc->sc_que.c_cc == 0)
276 return;
277 addr->bsel0 = getc(&sc->sc_que);
278 n = RDYSCAN;
279 while (n-- && (addr->bsel0&DMC_RDYI) == 0)
280 ;
281 }
282 if (sc->sc_que.c_cc)
283 addr->bsel0 |= DMC_IEI;
284}
285
286/*
287 * DMC interface transmitter interrupt.
288 * A transfer has completed, check for errors.
289 * If it was a read, notify appropriate protocol.
290 * If it was a write, pull the next one off the queue.
291 */
292dmcxint(unit)
293 int unit;
294{
295 register struct dmc_softc *sc;
296 struct uba_device *ui = dmcinfo[unit];
297 struct dmcdevice *addr;
298 struct mbuf *m;
299 register struct ifqueue *inq;
300 int arg, cmd, len;
301
302 addr = (struct dmcdevice *)ui->ui_addr;
303 arg = addr->sel6;
304 cmd = addr->bsel2&7;
305 addr->bsel2 &= ~DMC_RDYO;
306 sc = &dmc_softc[unit];
307 printd("dmcxint\n");
308 switch (cmd) {
309
310 case DMC_OUR:
311 /*
312 * A read has completed. Purge input buffered
313 * data path. Pass packet to type specific
314 * higher-level input routine.
315 */
316 sc->sc_if.if_ipackets++;
bfa2d860 317 if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP)
791be395
BJ
318 UBAPURGE(sc->sc_ifuba.ifu_uba,
319 sc->sc_ifuba.ifu_r.ifrw_bdp);
63665984
BJ
320 len = arg & DMC_CCOUNT;
321 printd(" read done, len %d\n", len);
ee787340 322 switch (ui->ui_flags & DMC_AF) {
63665984 323#ifdef INET
ee787340 324 case AF_INET:
9c8692e9 325 schednetisr(NETISR_IP);
63665984
BJ
326 inq = &ipintrq;
327 break;
328#endif
329
330 default:
ee787340
SL
331 printf("dmc%d: unknown address type %d\n", unit,
332 ui->ui_flags & DMC_AF);
63665984
BJ
333 goto setup;
334 }
335 m = if_rubaget(&sc->sc_ifuba, len, 0);
336 if (m == 0)
337 goto setup;
1e977657
BJ
338 if (IF_QFULL(inq)) {
339 IF_DROP(inq);
4fce3bf9 340 m_freem(m);
1e977657
BJ
341 } else
342 IF_ENQUEUE(inq, m);
63665984
BJ
343
344setup:
345 arg = sc->sc_ifuba.ifu_r.ifrw_info & 0x3ffff;
346 dmcload(sc, DMC_READ, arg, ((arg >> 2) & DMC_XMEM) | DMCMTU);
347 return;
348
349 case DMC_OUX:
350 /*
351 * A write has completed, start another
352 * transfer if there is more data to send.
353 */
354 if (sc->sc_oactive == 0)
355 return; /* SHOULD IT BE A FATAL ERROR? */
356 printd(" write done\n");
357 sc->sc_if.if_opackets++;
358 sc->sc_oactive = 0;
359 if (sc->sc_ifuba.ifu_xtofree) {
4fce3bf9 360 m_freem(sc->sc_ifuba.ifu_xtofree);
63665984
BJ
361 sc->sc_ifuba.ifu_xtofree = 0;
362 }
363 if (sc->sc_if.if_snd.ifq_head == 0)
364 return;
365 dmcstart(unit);
366 return;
367
368 case DMC_CNTLO:
369 arg &= DMC_CNTMASK;
370 if (arg&DMC_FATAL) {
371 addr->bsel1 = DMC_MCLR;
372 sc->sc_flag &= ~DMCRUN;
373 /*** DO SOMETHING TO RESTART DEVICE ***/
374 printf("DMC FATAL ERROR 0%o\n", arg);
375 } else {
376 /* ACCUMULATE STATISTICS */
377 printf("DMC SOFT ERROR 0%o\n", arg);
378 }
379 return;
380
381 default:
382 printf("dmc%d: bad control %o\n", unit, cmd);
383 }
384}
385
386/*
387 * DMC output routine.
388 * Just send the data, header was supplied by
389 * upper level protocol routines.
390 */
ee787340 391dmcoutput(ifp, m, dst)
63665984
BJ
392 register struct ifnet *ifp;
393 register struct mbuf *m;
ee787340 394 struct sockaddr *dst;
63665984
BJ
395{
396 struct uba_device *ui = dmcinfo[ifp->if_unit];
397 int s;
398
399 printd("dmcoutput\n");
ee787340 400 if (dst->sa_family != (ui->ui_flags & DMC_AF)) {
4fce3bf9
SL
401 printf("dmc%d: af%d not supported\n", ifp->if_unit,
402 dst->sa_family);
ee787340 403 m_freem(m);
8a2f82db 404 return (EAFNOSUPPORT);
63665984
BJ
405 }
406 s = splimp();
1e977657
BJ
407 if (IF_QFULL(&ifp->if_snd)) {
408 IF_DROP(&ifp->if_snd);
ee787340 409 m_freem(m);
1e977657 410 splx(s);
8a2f82db 411 return (ENOBUFS);
1e977657 412 }
63665984
BJ
413 IF_ENQUEUE(&ifp->if_snd, m);
414 if (dmc_softc[ifp->if_unit].sc_oactive == 0)
415 dmcstart(ifp->if_unit);
416 splx(s);
8a2f82db 417 return (0);
63665984 418}