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