xref: /original-bsd/sys/vax/if/if_dp.c (revision 86ed09e7)
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.3 (Berkeley) 09/12/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 "socketvar.h"
37 #include "syslog.h"
38 #include "vmmac.h"
39 #include "errno.h"
40 #include "time.h"
41 #include "kernel.h"
42 
43 #include "../net/if.h"
44 #include "../net/netisr.h"
45 #include "../net/route.h"
46 
47 #include "../vax/cpu.h"
48 #include "../vax/mtpr.h"
49 
50 #define	dzdevice dpdevice
51 #include "../vaxuba/pdma.h"
52 #include "../vaxuba/ubavar.h"
53 
54 #include "../netccitt/x25.h"
55 #include "../netccitt/pk.h"
56 #include "../netccitt/pk_var.h"
57 
58 #include "if_dpreg.h"
59 
60 /*
61  * Driver information for auto-configuration stuff.
62  */
63 int	dpprobe(), dpattach(), dpinit(), dpioctl(), dprint(), dpxint();
64 int	dpoutput(), dpreset(), dptimeout(), dpstart(), x25_ifoutput(), dptestoutput();
65 
66 struct	uba_device *dpinfo[NDP];
67 
68 u_short	dpstd[] = { 0 };
69 struct	uba_driver dpdriver =
70 	{ dpprobe, 0, dpattach, 0, dpstd, "dp", dpinfo };
71 
72 /*
73  * debug info
74  */
75 struct	dpstat {
76 	long	start;
77 	long	nohdr;
78 	long	init;
79 	long	rint;
80 	long	xint;
81 	long	reset;
82 	long	ioctl;
83 	long	down;
84 	long	mchange;
85 	long	timeout;
86 } dpstat;
87 /*
88  * Pdma structures for fast interrupts.
89  */
90 struct	pdma dppdma[2*NDP];
91 
92 /* error reporting intervals */
93 #define DPI_RPNBFS	50
94 #define DPI_RPDSC	1
95 #define DPI_RPTMO	10
96 #define DPI_RPDCK	10
97 
98 
99 /*
100  * DP software status per interface.
101  *
102  * Each interface is referenced by a network interface structure,
103  * dp_if, which the routing code uses to locate the interface.
104  * This structure contains the output queue for the interface, its address, ...
105  */
106 struct dp_softc {
107 	struct	ifnet dp_if;		/* network-visible interface */
108 	int	dp_ipl;
109 	short	dp_iused;		/* input buffers given to DP */
110 	short	dp_flags;		/* flags */
111 #define DPF_RUNNING	0x01		/* device initialized */
112 #define DPF_ONLINE	0x02		/* device running (had a RDYO) */
113 #define DPF_RESTART	0x04		/* software restart in progress */
114 #define DPF_FLUSH	0x08		/* had a ROVR, flush ipkt when done */
115 	short	dp_ostate;		/* restarting, etc. */
116 	short	dp_istate;		/* not sure this is necessary */
117 #define DPS_IDLE	0
118 #define DPS_RESTART	1
119 #define DPS_ACTIVE	2
120 #define DPS_XEM		3		/* transmitting CRC, etc. */
121 	int	dp_errors[4];		/* non-fatal error counters */
122 #define dp_datck dp_errors[0]
123 #define dp_timeo dp_errors[1]
124 #define dp_nobuf dp_errors[2]
125 #define dp_disc  dp_errors[3]
126 	struct timeval	dp_xt;			/* start of last transmission */
127 	char	dp_obuf[DP_MTU+8];
128 	char	dp_ibuf[DP_MTU+8];
129 } dp_softc[NDP];
130 
131 dpprobe(reg, ui)
132 	caddr_t reg;
133 	struct	uba_device *ui;
134 {
135 	register int br, cvec;
136 	register struct dpdevice *addr = (struct dpdevice *)reg;
137 	register int i;
138 
139 #ifdef lint
140 	br = 0; cvec = br; br = cvec;
141 	dprint(0); dpxint(0);
142 #endif
143 	(void) spl6();
144 	addr->dpclr = DP_CLR;
145 	addr->dpclr = DP_XIE|DP_XE;
146 	DELAY(100000);
147 	dp_softc[ui->ui_unit].dp_ipl = br = qbgetpri();
148 	addr->dpclr = 0;
149 	if (cvec && cvec != 0x200){
150 		cvec -= 4;
151 	}
152 	return (1);
153 }
154 
155 /*
156  * Interface exists: make available by filling in network interface
157  * record.  System will initialize the interface when it is ready
158  * to accept packets.
159  */
160 dpattach(ui)
161 	register struct uba_device *ui;
162 {
163 	register struct dp_softc *dp = &dp_softc[ui->ui_unit];
164 
165 	dp->dp_if.if_unit = ui->ui_unit;
166 	dp->dp_if.if_name = "dp";
167 	dp->dp_if.if_mtu = DP_MTU;
168 	dp->dp_if.if_init = dpinit;
169 	dp->dp_if.if_output = x25_ifoutput;
170 	dp->dp_if.if_start = dpstart;
171 	dp->dp_if.if_ioctl = dpioctl;
172 	dp->dp_if.if_reset = dpreset;
173 	dp->dp_if.if_watchdog = dptimeout;
174 	dp->dp_if.if_flags = 0;
175 	if_attach(&dp->dp_if);
176 }
177 
178 /*
179  * Reset of interface after UNIBUS reset.
180  * If interface is on specified UBA, reset its state.
181  */
182 dpreset(unit, uban)
183 	int unit, uban;
184 {
185 	register struct uba_device *ui;
186 	register struct dp_softc *dp = &dp_softc[unit];
187 	register struct dpdevice *addr;
188 
189 	dpstat.reset++;
190 	if (unit >= NDP || (ui = dpinfo[unit]) == 0 || ui->ui_alive == 0 ||
191 	    ui->ui_ubanum != uban)
192 		return;
193 	printf(" dp%d", unit);
194 	dp->dp_flags = 0;
195 	dp->dp_if.if_flags &= ~IFF_RUNNING;
196 	addr = (struct dpdevice *)ui->ui_addr;
197 	addr->dpclr = DP_CLR;
198 	DELAY(1000);
199 	addr->dpsar = 0;
200 	addr->dprcsr = 0;
201 	dpinit(unit);
202 }
203 
204 /*
205  * Initialization of interface.
206  */
207 dpinit(unit)
208 	int unit;
209 {
210 	register struct dp_softc *dp = &dp_softc[unit];
211 	register struct uba_device *ui = dpinfo[unit];
212 	register struct dpdevice *addr;
213 	register struct ifaddr *ifa;
214 	register struct pdma *pdp = &dppdma[unit*2];
215 	int base, s;
216 
217 	dpstat.init++;
218 	/*
219 	 * Check to see that an address has been set.
220 	 */
221 	for (ifa = dp->dp_if.if_addrlist; ifa; ifa = ifa->ifa_next)
222 		if (ifa->ifa_addr->sa_family != AF_LINK)
223 			break;
224 	if (ifa == (struct ifaddr *) 0)
225 		return;
226 
227 	addr = (struct dpdevice *)ui->ui_addr;
228 	s = splimp();
229 	dp->dp_iused = 0;
230 	dp->dp_istate = dp->dp_ostate = DPS_IDLE;
231 	dp->dp_if.if_flags |= IFF_RUNNING;
232 	dp->dp_if.if_flags &= ~IFF_OACTIVE;
233 
234 	pdp->p_addr = addr;
235 	pdp->p_fcn = dpxint;
236 	pdp->p_mem = pdp->p_end = dp->dp_obuf;
237 	pdp++;
238 	pdp->p_addr = addr;
239 	pdp->p_fcn = dprint;
240 	/* force initial interrupt to come to dprint */
241 	pdp->p_mem = pdp->p_end = dp->dp_ibuf + DP_MTU + 8;
242 
243 	addr->dpclr = DP_CLR;
244 	DELAY(1000);
245 	addr->dpclr = 0;
246 	DELAY(1000);
247 	/* DP_ATA = 0, DP_CHRM = 0,
248 			    CRC = CCIIT, initially all ones, 2nd addr = 0 */
249 	addr->dpsar = 0;
250 	/* enable receive interrupt */
251 	addr->dprcsr = DP_RIE | DP_MIE | DP_RE | DP_DTR | DP_RTS;
252 	dpstart(&dp->dp_if);
253 	splx(s);
254 }
255 
256 int dpMessy = 0;
257 /*
258  * Start output on interface.  Get another datagram
259  * to send from the interface queue and map it to
260  * the interface before starting output.
261  *
262  */
263 dpstart(ifp)
264 	struct ifnet *ifp;
265 {
266 	int s, unit = ifp->if_unit, error = 0, len;
267 	register struct dp_softc *dp = &dp_softc[unit];
268 	register struct dpdevice *addr =
269 				(struct dpdevice *)(dpinfo[unit]->ui_addr);
270 	register struct mbuf *m;
271 	register char *cp;
272 	char *cplim;
273 
274 	/*
275 	 * If already doing output, go away and depend on transmit
276 	 * complete or error.
277 	 */
278 	dpstat.start++;
279 	if (dp->dp_if.if_flags & IFF_OACTIVE)
280 		goto out;
281 	IF_DEQUEUE(&dp->dp_if.if_snd, m);
282 	if (m == 0)
283 		goto out;
284 	dp->dp_if.if_collisions++;
285 	if (m->m_flags & M_PKTHDR)
286 		len = m->m_pkthdr.len;
287 	else {
288 		struct mbuf *m0 = m;
289 		for (len = 0; m; m = m->m_next)
290 			len += m->m_len;
291 		m = m0;
292 		dpstat.nohdr++;
293 	}
294 	if (len == 0)
295 		goto out;
296 	if (len > DP_MTU) {
297 		error = EINVAL;
298 		goto out;
299 	}
300 	cp = dp->dp_obuf;
301 	dppdma[2*unit].p_mem = cp + 1;
302 	while (m) {
303 		struct mbuf *n;
304 		bcopy(mtod(m, caddr_t), (caddr_t)cp, m->m_len);
305 		cp += m->m_len;
306 		MFREE(m, n); m = n;
307 	}
308 	dppdma[2*unit].p_end = cp;
309 	if (dpMessy)
310 		printf("dp: len %d, start %x, end %x, first %x, next %x",
311 			len, dp->dp_obuf, cp, *(int *)dp->dp_obuf,
312 			1[(int *)dp->dp_obuf]);
313 	dp->dp_if.if_flags |= IFF_OACTIVE;
314 	dp->dp_ostate = DPS_ACTIVE;
315 	dp->dp_if.if_collisions--;
316 dp->dp_xt = time;
317 	addr->dpclr = DP_XE | DP_XIE;
318 	addr->dptdsr = DP_XSM | (0xff & dp->dp_obuf[0]);
319 out:
320 	return (error);
321 }
322 /*
323  * Receive done or error interrupt
324  */
325 dprint(unit, pdma, addr)
326 register struct pdma *pdma;
327 register struct dpdevice *addr;
328 {
329 	register struct dp_softc *dp = &dp_softc[unit];
330 	short rdsr = addr->dprdsr, rcsr;
331 
332 	dpstat.rint++;
333 	splx(dp->dp_ipl);
334 	if (rdsr & DP_RSM) { /* Received Start of Message */
335 		dp->dp_ibuf[0] = rdsr & DP_RBUF;
336 		pdma->p_mem = dp->dp_ibuf + 1;
337 		dp->dp_flags &= ~DPF_FLUSH;
338 		return;
339 	}
340 	if (rdsr & DP_REM) { /* Received End of Message */
341 		if (rdsr & DP_REC || dp->dp_flags & DPF_FLUSH) {
342 			dp->dp_if.if_ierrors++;
343 		} else
344 			dpinput(&dp->dp_if,
345 				pdma->p_mem - dp->dp_ibuf, dp->dp_ibuf);
346 		pdma->p_mem = pdma->p_end;
347 		dp->dp_flags &= ~ DPF_FLUSH;
348 		return;
349 	}
350 	if (rdsr & DP_ROVR) {
351 		dp->dp_flags |= DPF_FLUSH;
352 		return;
353 	}
354 	rcsr = pdma->p_arg;
355 	if (rcsr & DP_MSC) {
356 		dpstat.mchange++;
357 		if (0 == (rcsr & DP_DSR)) {
358 			log(LOG_DEBUG, "dp%d: lost modem\n", unit);
359 			dpdown(unit);
360 		}
361 		return;
362 	}
363 	dp->dp_flags |= DPF_FLUSH;
364 	if (pdma->p_mem != pdma->p_end)
365 		log("dp%d: unexplained receiver interrupt\n", unit);
366 }
367 struct timeval dp_xt;
368 
369 /*
370  * Transmit complete or error interrupt
371  */
372 dpxint(unit, pdma, addr)
373 register struct pdma *pdma;
374 register struct dpdevice *addr;
375 {
376 	register struct dp_softc *dp = &dp_softc[unit];
377 	int s;
378 
379 	splx(dp->dp_ipl);
380 	dpstat.xint++;
381 	if (addr->dptdsr & DP_XERR) {
382 		log("if_dp%d: data late\n", unit);
383 	restart:
384 		pdma->p_mem = dp->dp_obuf;
385 		addr->dptdsr = DP_XSM;
386 		dp->dp_if.if_oerrors++;
387 		return;
388 	}
389 	switch (dp->dp_ostate) {
390 
391 	case DPS_ACTIVE:
392 		if (pdma->p_mem != pdma->p_end) {
393 			log("if_dp%d: misc error in dpxint\n", unit);
394 			goto restart;
395 		}
396 		addr->dptdsr = DP_XEM;
397 		dp->dp_ostate = DPS_XEM;
398 		break;
399 
400 	case DPS_XEM:
401 		dp->dp_if.if_opackets++;
402 		dp->dp_if.if_flags &= ~IFF_OACTIVE;
403 s = splclock();
404 dp_xt = time;
405 timevalsub(&dp_xt, &dp->dp_xt);
406 splx(s);
407 		if (dp->dp_if.if_snd.ifq_len)
408 			dpstart(&dp->dp_if);
409 		else {
410 			addr->dpclr = 0;
411 			dp->dp_ostate = DPS_IDLE;
412 		}
413 		break;
414 
415 	default:
416 		log("if_dp%d: impossible state in dpxint\n");
417 	}
418 }
419 /*
420  * Routine to copy from device buffer into mbufs.
421  *
422  * Warning: This makes the fairly safe assumption that
423  * mbufs have even lengths.
424  */
425 struct mbuf *
426 dpget(rxbuf, totlen, off, ifp)
427 	caddr_t rxbuf;
428 	int totlen, off;
429 	struct ifnet *ifp;
430 {
431 	register caddr_t cp;
432 	register struct mbuf *m;
433 	struct mbuf *top = 0, **mp = ⊤
434 	int len;
435 	caddr_t packet_end;
436 
437 	cp = rxbuf;
438 	packet_end = cp + totlen;
439 	if (off) {
440 		off += 2 * sizeof(u_short);
441 		totlen -= 2 *sizeof(u_short);
442 		cp = rxbuf + off;
443 	}
444 
445 	MGETHDR(m, M_DONTWAIT, MT_DATA);
446 	if (m == 0)
447 		return (0);
448 	m->m_pkthdr.rcvif = ifp;
449 	m->m_pkthdr.len = totlen;
450 	m->m_len = MHLEN;
451 
452 	while (totlen > 0) {
453 		if (top) {
454 			MGET(m, M_DONTWAIT, MT_DATA);
455 			if (m == 0) {
456 				m_freem(top);
457 				return (0);
458 			}
459 			m->m_len = MLEN;
460 		}
461 		len = min(totlen, (packet_end - cp));
462 		if (len >= MINCLSIZE) {
463 			MCLGET(m, M_DONTWAIT);
464 			if (m->m_flags & M_EXT)
465 				m->m_len = len = min(len, MCLBYTES);
466 			else
467 				len = m->m_len;
468 		} else {
469 			/*
470 			 * Place initial small packet/header at end of mbuf.
471 			 */
472 			if (len < m->m_len) {
473 				if (top == 0 && len + max_linkhdr <= m->m_len)
474 					m->m_data += max_linkhdr;
475 				m->m_len = len;
476 			} else
477 				len = m->m_len;
478 		}
479 		bcopy(cp, mtod(m, caddr_t), (u_int)len);
480 		*mp = m;
481 		mp = &m->m_next;
482 		totlen -= len;
483 		cp += len;
484 		if (cp == packet_end)
485 			cp = rxbuf;
486 	}
487 	return (top);
488 }
489 
490 dpinput(ifp, len, buffer)
491 register struct ifnet *ifp;
492 caddr_t buffer;
493 {
494 	register struct ifqueue *inq;
495 	register struct mbuf *m;
496 	extern struct ifqueue hdintrq, ipintrq;
497 	int netisr;
498 
499 	ifp->if_ipackets++;
500     {
501 	register struct ifaddr *ifa = ifp->if_addrlist;
502 	register u_char *cp = (u_char *)buffer;
503 
504 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
505 		if (ifa->ifa_addr->sa_family != AF_LINK)
506 			break;
507 	if (cp[0] == 0xff && cp[1] == 0x3) {
508 		/* This is a UI HDLC Packet, so we'll assume PPP
509 		   protocol.  for now, IP only. */
510 		buffer += 4;
511 		len -= 4;
512 		inq = &ipintrq;
513 		netisr = NETISR_IP;
514 	} else {
515 		inq = &hdintrq;
516 		netisr = NETISR_CCITT;
517 	}
518     }
519 	if (len <= 0)
520 		return;
521 
522 	m = dpget(buffer, len , 0, ifp);
523 	if (m == 0)
524 		return;
525 
526 	if(IF_QFULL(inq)) {
527 		IF_DROP(inq);
528 		m_freem(m);
529 	} else {
530 		IF_ENQUEUE(inq, m);
531 		schednetisr(netisr);
532 	}
533 }
534 
535 /*
536  * Process an ioctl request.
537  */
538 dpioctl(ifp, cmd, data)
539 	register struct ifnet *ifp;
540 	int cmd;
541 	caddr_t data;
542 {
543 	register struct ifaddr *ifa = (struct ifaddr *)data;
544 	int s = splimp(), error = 0;
545 	struct dp_softc *dp = &dp_softc[ifp->if_unit];
546 
547 	dpstat.ioctl++;
548 	switch (cmd) {
549 
550 	case SIOCSIFADDR:
551 		ifp->if_flags |= IFF_UP;
552 		switch (ifa->ifa_addr->sa_family) {
553 		case AF_INET:
554 			ifp->if_output = dptestoutput;
555 		default:
556 			dpinit(ifp->if_unit);
557 			break;
558 		}
559 		break;
560 #ifdef CCITT
561 	case SIOCSIFCONF_X25:
562 		ifp->if_flags |= IFF_UP;
563 		ifp->if_output = x25_ifoutput;
564 		error = hd_ctlinput(PRC_IFUP, ifa->ifa_addr);
565 		if (error == 0)
566 			dpinit(ifp->if_unit);
567 		break;
568 #endif
569 
570 	case SIOCSIFFLAGS:
571 		if ((ifp->if_flags & IFF_UP) == 0 &&
572 		    (ifp->if_flags & IFF_RUNNING))
573 			dpdown(ifp->if_unit);
574 		else if (ifp->if_flags & IFF_UP &&
575 		    (ifp->if_flags & IFF_RUNNING) == 0)
576 			dpinit(ifp->if_unit);
577 		break;
578 
579 
580 	default:
581 		error = EINVAL;
582 	}
583 	splx(s);
584 	return (error);
585 }
586 /*
587  * Reset a device and mark down.
588  * Flush output queue and drop queue limit.
589  */
590 dpdown(unit)
591 	int unit;
592 {
593 	register struct dp_softc *dp = &dp_softc[unit];
594 
595 	dpstat.down++;
596 	if_qflush(&dp->dp_if.if_snd);
597 	dpreset(unit);
598 }
599 
600 /*
601  * Watchdog timeout to see that transmitted packets don't
602  * lose interrupts.  The device has to be online (the first
603  * transmission may block until the other side comes up).
604  */
605 dptimeout(unit)
606 	int unit;
607 {
608 	register struct dp_softc *dp;
609 
610 	/* currently not armed */
611 	dpstat.timeout++;
612 	dp = &dp_softc[unit];
613 	if (dp->dp_if.if_flags & IFF_OACTIVE) {
614 		dpstart(&dp->dp_if);
615 	}
616 }
617 /*
618  * For debugging loopback activity.
619  */
620 static char pppheader[4] = { -1, 3, 0, 0x21 };
621 int dp_louts;
622 
623 dptestoutput(ifp, m, dst, rt)
624 register struct ifnet *ifp;
625 register struct mbuf *m;
626 struct sockaddr *dst;
627 struct rtentry *rt;
628 {
629 	/*
630 	 * Queue message on interface, and start output if interface
631 	 * not yet active.
632 	 */
633 	int s = splimp(), error = 0;
634 	dp_louts++;
635 	M_PREPEND(m, sizeof pppheader, M_DONTWAIT);
636 	if (m == 0) {
637 		splx(s);
638 		return ENOBUFS;
639 	}
640 	bcopy(pppheader, mtod(m, caddr_t), sizeof pppheader);
641 	if (IF_QFULL(&ifp->if_snd)) {
642 		IF_DROP(&ifp->if_snd);
643 	    /* printf("%s%d: HDLC says OK to send but queue full, may hang\n",
644 			ifp->if_name, ifp->if_unit);*/
645 		m_freem(m);
646 		error = ENOBUFS;
647 	} else {
648 		IF_ENQUEUE(&ifp->if_snd, m);
649 		if ((ifp->if_flags & IFF_OACTIVE) == 0)
650 			(*ifp->if_start)(ifp);
651 	}
652 	splx(s);
653 	return (error);
654 }
655 
656 #endif
657