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