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