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