xref: /original-bsd/sys/vax/if/if_dp.c (revision 6ab384a1)
1 /*
2  * Copyright (c) 1990 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)if_dp.c	7.1 (Berkeley) 08/30/90
8  */
9 
10 #include "dp.h"
11 #if NDP > 0
12 
13 /*
14  * DPV-11 device driver, X.25 version
15  *
16  * Derived from dmc-11 driver:
17  *
18  *	Bill Nesheim
19  *	Cornell University
20  *
21  *	Lou Salkind
22  *	New York University
23  */
24 
25 /* #define DEBUG	/* for base table dump on fatal error */
26 
27 #include "machine/pte.h"
28 
29 #include "param.h"
30 #include "systm.h"
31 #include "mbuf.h"
32 #include "buf.h"
33 #include "ioctl.h"		/* must precede tty.h */
34 #include "protosw.h"
35 #include "socket.h"
36 #include "syslog.h"
37 #include "vmmac.h"
38 #include "errno.h"
39 #include "time.h"
40 #include "kernel.h"
41 
42 #include "../net/if.h"
43 #include "../net/netisr.h"
44 #include "../net/route.h"
45 
46 #include "../vax/cpu.h"
47 #include "../vax/mtpr.h"
48 #include "../vaxuba/pdma.h"
49 
50 #include "if_dpreg.h"
51 
52 /*
53  * Driver information for auto-configuration stuff.
54  */
55 int	dpprobe(), dpattach(), dpinit(), dpioctl(), dprint(), dpxint();
56 int	dpoutput(), dpreset(), dptimeout(), x25_ifoutput();
57 
58 struct	uba_device *dpinfo[NDP];
59 
60 u_short	dpstd[] = { 0 };
61 struct	uba_driver dpdriver =
62 	{ dpprobe, 0, dpattach, 0, dpstd, "dp", dpinfo };
63 
64 /*
65  * Pdma structures for fast interrupts.
66  */
67 struct	pdma dppdma[2*NDP];
68 
69 /* error reporting intervals */
70 #define DPI_RPNBFS	50
71 #define DPI_RPDSC	1
72 #define DPI_RPTMO	10
73 #define DPI_RPDCK	10
74 
75 
76 /*
77  * DP software status per interface.
78  *
79  * Each interface is referenced by a network interface structure,
80  * dp_if, which the routing code uses to locate the interface.
81  * This structure contains the output queue for the interface, its address, ...
82  */
83 struct dp_softc {
84 	struct	ifnet dp_if;		/* network-visible interface */
85 	short	dp_iused;		/* input buffers given to DP */
86 	short	dp_flags;		/* flags */
87 	short	dp_ostate;		/* restarting, etc. */
88 	short	dp_istate;		/* not sure this is necessary */
89 #define DPS_IDLE	0
90 #define DPS_RESTART	1
91 #define DPS_ACTIVE	2
92 #define DPS_XEM		3		/* transmitting CRC, etc. */
93 /* flags */
94 #define DPF_RUNNING	0x01		/* device initialized */
95 #define DPF_ONLINE	0x02		/* device running (had a RDYO) */
96 #define DPF_RESTART	0x04		/* software restart in progress */
97 #define DPF_FLUSH	0x08		/* had a ROVR, flush ipkt when done */
98 	int	dp_errors[4];		/* non-fatal error counters */
99 #define dp_datck dp_errors[0]
100 #define dp_timeo dp_errors[1]
101 #define dp_nobuf dp_errors[2]
102 #define dp_disc  dp_errors[3]
103 	char	dp_obuf[DP_MTU+8];
104 	char	dp_rbuf[DP_MTU+8];
105 } dp_softc[NDP];
106 
107 dpprobe(reg, ui)
108 	caddr_t reg;
109 	struct	uba_device *ui;
110 {
111 	register int br, cvec;
112 	register struct dpdevice *addr = (struct dpdevice *)reg;
113 	register int i;
114 
115 #ifdef lint
116 	br = 0; cvec = br; br = cvec;
117 	dprint(0); dpxint(0);
118 #endif
119 	addr->dpclr = DP_CLR;
120 	addr->dpclr = DP_XIE|DP_XE;
121 	DELAY(100000);
122 	addr->dpclr = 0;
123 	return (1);
124 }
125 
126 /*
127  * Interface exists: make available by filling in network interface
128  * record.  System will initialize the interface when it is ready
129  * to accept packets.
130  */
131 dpattach(ui)
132 	register struct uba_device *ui;
133 {
134 	register struct dp_softc *dp = &dp_softc[ui->ui_unit];
135 	register struct pdma *pdp = &dppdma[ui->ui_unit*2];
136 
137 	dp->dp_if.if_unit = ui->ui_unit;
138 	dp->dp_if.if_name = "dp";
139 	dp->dp_if.if_mtu = DP_MTU;
140 	dp->dp_if.if_init = dpinit;
141 	dp->dp_if.if_output = x25_ifoutput;
142 	dp->dp_if.if_start = dpstart;
143 	dp->dp_if.if_ioctl = dpioctl;
144 	dp->dp_if.if_reset = dpreset;
145 	dp->dp_if.if_watchdog = dptimeout;
146 	dp->dp_if.if_flags = IFF_POINTOPOINT;
147 
148 
149 	pdp->p_addr = (struct dzdevice *)ui->ui_addr;
150 	pdp->p_arg = (int)dp;
151 	pdp->p_fcn = dpxint;
152 	pdp->p_mem = pdp->p_end = dp->dp_obuf;
153 	pdp++;
154 	pdp->p_addr = (struct dzdevice *)ui->ui_addr;
155 	pdp->p_arg = (int)dp;
156 	pdp->p_fcn = dprint;
157 	pdp->p_mem = pdp->p_end = dp->dp_rbuf;
158 
159 	if_attach(&dp->dp_if);
160 }
161 
162 /*
163  * Reset of interface after UNIBUS reset.
164  * If interface is on specified UBA, reset its state.
165  */
166 dpreset(unit, uban)
167 	int unit, uban;
168 {
169 	register struct uba_device *ui;
170 	register struct dp_softc *dp = &dp_softc[unit];
171 	register struct dpdevice *addr;
172 
173 	if (unit >= NDP || (ui = dpinfo[unit]) == 0 || ui->ui_alive == 0 ||
174 	    ui->ui_ubanum != uban)
175 		return;
176 	printf(" dp%d", unit);
177 	dp->dp_flag = 0;
178 	dp->dp_if.if_flags &= ~IFF_RUNNING;
179 	addr = ui->ui_addr;
180 	addr->dpclr = DP_CLR;
181 	addr->dpsar = 0;
182 	addr->dprcsr = 0;
183 	dpinit(unit);
184 }
185 
186 /*
187  * Initialization of interface.
188  */
189 dpinit(unit)
190 	int unit;
191 {
192 	register struct dp_softc *dp = &dp_softc[unit];
193 	register struct uba_device *ui = dpinfo[unit];
194 	register struct dpdevice *addr;
195 	register struct ifnet *ifp = &dp->dp_if;
196 	struct ifaddr *ifa;
197 	int base;
198 	int s;
199 
200 	addr = (struct dpdevice *)ui->ui_addr;
201 
202 	/*
203 	 * Check to see that an address has been set.
204 	 */
205 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
206 		if (ifa->ifa_addr->sa_family != AF_LINK)
207 			break;
208 	if (ifa == (struct ifaddr *) 0)
209 		return;
210 
211 	s = spl5();
212 	dp->dp_iused = 0;
213 	dp->dp_istate = dp->dp_ostate = DPS_IDLE;
214 	dppdma[2*unit+1].p_end =
215 		dppdma[2*unit+1].p_mem = = dp->dp_rbuf;
216 	/* enable receive interrupt; CTS comming up will trigger it also */
217 	addr->dpsar = DP_CHRM | 0x7E; /* 7E is the flag character */
218 	addr->dpclr = 0;
219 	addr->dprcsr = DP_RIE | DP_DTR | DP_RE;
220 	splx(s);
221 }
222 
223 /*
224  * Start output on interface.  Get another datagram
225  * to send from the interface queue and map it to
226  * the interface before starting output.
227  *
228  */
229 dpstart(ifp)
230 	struct ifnet *ifp;
231 {
232 	int s, unit = ifp->if_unit;
233 	register struct dp_softc *dp = &dp_softc[unit];
234 	register struct dpdevice *addr = dpinfo[unit].ui_addr;
235 	register struct mbuf *m;
236 	register char *cp;
237 	char *cplim;
238 
239 	/*
240 	 * If already doing output, go away and depend on transmit
241 	 * complete or error.
242 	 */
243 	s = splimp();
244 	if (dp->dp_if.if_flags & IFF_OACTIVE) {
245 		splx(s);
246 		return (0);
247 	}
248 	IF_DEQUEUE(&dp->dp_if.if_snd, m);
249 	if (m == 0)
250 		return (0);
251 	if ((m->m_flags | M_PKTHDR) == 0 || m->m_pkthdr.len > DP_MTU)
252 		return (EINVAL);
253 	s = spl5();
254 	dppdma[2*unit].p_mem = cp = dp->dp_obuf;
255 	while (m) {
256 		struct mbuf *n;
257 		bcopy(mtod(m, caddr_t), (caddr_t)cp, m->m_len);
258 		cp += m->m_len;
259 		MFREE(m, n); m = n;
260 	}
261 	if (cp == dp->dp_obuf)
262 		return (0);
263 	dppdma[2*unit].p_end = cp;
264 	addr->dpclr = DP_XE | DP_XIE;
265 	addr->dptdsr = DP_XSM;
266 	dp->dp_if.if_flags |= IFF_OACTIVE;
267 	dp->dp_ostate = DPS_ACTIVE;
268 	splx(s);
269 	return (0);
270 }
271 /*
272  * Receive done or error interrupt
273  */
274 dprint(unit, pdma, addr)
275 register struct pdma *pdma;
276 register struct dpdevice *addr;
277 {
278 	register struct dpsoftc *dp = &dpsoftc[unit];
279 	unsigned short dprdsr = addr->dprdsr;
280 
281 	if (dprdsr & DP_ROVR) {
282 		dp->dp_flags |= DPF_FLUSH;
283 		return;
284 	}
285 	if (dprdsr & DP_RSM) { /* Received Start of Message */
286 		dp->dp_ibuf[0] = dprdsr & DP_RBUF;
287 		pdma->p_mem = dp->dp_ibuf + 1;
288 		dpflags &= ~DPF_FLUSH;
289 		return;
290 	}
291 	if (dprdsr & DP_REM) { /* Received End of Message */
292 		if (dprdsr & DP_REC || dp->dp_flags & DPF_FLUSH) {
293 			dp->dp_if.if_errors++;
294 			pdma->p_mem = dp->dp_ibuf;
295 			dp->dp_flags &= ~ DPF_FLUSH;
296 			return;
297 		}
298 		dpinput(dp, pdma->p_mem - dp->dp_ibuf, dp->dp_ibuf);
299 		return;
300 	}
301 	dp->dp_flags |= DPF_FLUSH;
302 	if (pdma->p_mem != pdma->p_end)
303 		log(dp%d: unexplained receiver interrupt\n");
304 }
305 
306 /*
307  * Transmit complete or error interrupt
308  */
309 dpxint(unit, pdma, addr)
310 register struct pdma *pdma;
311 register struct dpdevice *addr;
312 {
313 	register struct dpsoftc *dp = &dpsoftc[unit];
314 
315 	if (addr->dptdsr & DP_XERR) {
316 		log("if_dp%d: data late\n", unit);
317 	restart:
318 		pdma->p_mem = dp->dp_obuf;
319 		addr->dptdsr = DP_XSM;
320 		return;
321 	}
322 	switch (dp->dp_ostate) {
323 
324 	case DPS_ACTIVE:
325 		if (pdma->p_mem != pdma->p_end) {
326 			log("if_dp%d: misc error in dpxint\n");
327 			goto restart;
328 		}
329 		addr->dptdsr = DP_XEM;
330 		dp->dp_ostate = DPS_XEM;
331 		break;
332 
333 	case DPS_XEM:
334 		dp->dp_if.if_flags &= ~IFF_OACTIVE;
335 		if (dp->dp_if.if_snd.ifq_len)
336 			dpstart(&dp->dp_if);
337 		else {
338 			addr->dpclr = 0;
339 			dp->dp_ostate = DPS_IDLE;
340 		}
341 		break;
342 
343 	default:
344 		log("if_dp%d: impossible state in dpxint\n");
345 	}
346 }
347 /*
348  * Routine to copy from device buffer into mbufs.
349  *
350  * Warning: This makes the fairly safe assumption that
351  * mbufs have even lengths.
352  */
353 struct mbuf *
354 dpget(rxbuf, totlen, off, ifp)
355 	caddr_t rxbuf;
356 	int totlen, off;
357 	struct ifnet *ifp;
358 {
359 	register caddr_t cp;
360 	register struct mbuf *m;
361 	struct mbuf *top = 0, **mp = ⊤
362 	int len;
363 	caddr_t packet_end;
364 
365 	cp = rxbuf;
366 	packet_end = cp + totlen;
367 	if (off) {
368 		off += 2 * sizeof(u_short);
369 		totlen -= 2 *sizeof(u_short);
370 		cp = rxbuf + off;
371 	}
372 
373 	MGETHDR(m, M_DONTWAIT, MT_DATA);
374 	if (m == 0)
375 		return (0);
376 	m->m_pkthdr.rcvif = ifp;
377 	m->m_pkthdr.len = totlen;
378 	m->m_len = MHLEN;
379 
380 	while (totlen > 0) {
381 		if (top) {
382 			MGET(m, M_DONTWAIT, MT_DATA);
383 			if (m == 0) {
384 				m_freem(top);
385 				return (0);
386 			}
387 			m->m_len = MLEN;
388 		}
389 		len = min(totlen, (packet_end - cp));
390 		if (len >= MINCLSIZE) {
391 			MCLGET(m, M_DONTWAIT);
392 			if (m->m_flags & M_EXT)
393 				m->m_len = len = min(len, MCLBYTES);
394 			else
395 				len = m->m_len;
396 		} else {
397 			/*
398 			 * Place initial small packet/header at end of mbuf.
399 			 */
400 			if (len < m->m_len) {
401 				if (top == 0 && len + max_linkhdr <= m->m_len)
402 					m->m_data += max_linkhdr;
403 				m->m_len = len;
404 			} else
405 				len = m->m_len;
406 		}
407 		bcopy(cp, mtod(m, caddr_t), (u_int)len);
408 		*mp = m;
409 		mp = &m->m_next;
410 		totlen -= len;
411 		cp += len;
412 		if (cp == packet_end)
413 			cp = rxbuf;
414 	}
415 	return (top);
416 }
417 
418 dpinput(dp, len, buffer)
419 register struct dpsoftc *dp;
420 caddr_t buffer;
421 {
422 	register struct ifnet *ifp = &dp->dp_if;
423 	register struct ifqueue *inq;
424 	register struct mbuf *m;
425 	extern struct ifqueue hdintrq;
426 
427 	if(len <= 0 || ifp->if_addrlist == 0)
428 		return;
429 
430 	m = dpget(buffer, len , 0, ifp);
431 	if (m == 0)
432 		return;
433 	ifp->if_ipackets++;
434 
435 	/* Only AF_CCITT makes sense at this point */
436 	inq = &hdintrq;
437 
438 	if(IF_QFULL(inq)) {
439 		IF_DROP(inq);
440 		m_freem(m);
441 	} else {
442 		IF_ENQUEUE(inq, m);
443 		schednetisr(NETISR_HD);
444 	}
445 }
446 
447 /*
448  * Process an ioctl request.
449  */
450 dpioctl(ifp, cmd, data)
451 	register struct ifnet *ifp;
452 	int cmd;
453 	caddr_t data;
454 {
455 	register struct ifaddr *ifa = (struct ifaddr *)data;
456 	int s = splimp(), error = 0;
457 
458 	switch (cmd) {
459 
460 	case SIOCSIFADDR:
461 		ifp->if_flags |= IFF_UP;
462 		switch (ifa->ifa_addr->sa_family) {
463 #ifdef CCITT
464 		case AF_CCITT:
465 			error = hd_ctlinput (PRC_IFUP, (caddr_t)&ifa->ifa_addr);
466 			if (error == 0)
467 				dpinit(ifp->if_unit);
468 			break;
469 #endif
470 		case SIOCSIFFLAGS:
471 			if ((ifp->if_flags & IFF_UP) == 0 &&
472 			    (dp->dp_flags & DPF_RUNNING))
473 				dpdown(ifp->if_unit);
474 			else if (ifp->if_flags & IFF_UP &&
475 			    (dp->dp_flags & DPF_RUNNING) == 0)
476 				dpinit(ifp->if_unit);
477 			break;
478 
479 		default:
480 			dpinit(ifp->if_unit);
481 			break;
482 		}
483 		break;
484 
485 	/* case SIOCSIFFLAGS: ... */
486 
487 	default:
488 		error = EINVAL;
489 	}
490 	splx(s);
491 	return (error);
492 }
493 /*
494  * Reset a device and mark down.
495  * Flush output queue and drop queue limit.
496  */
497 dpdown(unit)
498 	int unit;
499 {
500 	register struct dp_softc *dp = &dp_softc[unit];
501 	register struct ifxmt *ifxp;
502 
503 	dp->dp_flags &= ~(DP_RUNNING | DP_ONLINE);
504 	addr->dpclr = DP_CLR;
505 	addr->dpclr = 0;
506 
507 	if_qflush(&dp->dp_if.if_snd);
508 }
509 
510 /*
511  * Watchdog timeout to see that transmitted packets don't
512  * lose interrupts.  The device has to be online (the first
513  * transmission may block until the other side comes up).
514  */
515 dptimeout(unit)
516 	int unit;
517 {
518 	register struct dp_softc *dp;
519 	struct dpdevice *addr;
520 
521 	dp = &dp_softc[unit];
522 	if (dp->dp_flags & DP_ONLINE) {
523 		addr = (struct dpdevice *)(dpinfo[unit]->ui_addr);
524 		dpstart(unit);
525 	}
526 }
527 #endif
528