xref: /csrg-svn/sys/vax/if/if_pcl.c (revision 24792)
123300Smckusick /*
223300Smckusick  * Copyright (c) 1982 Regents of the University of California.
323300Smckusick  * All rights reserved.  The Berkeley software License Agreement
423300Smckusick  * specifies the terms and conditions for redistribution.
523300Smckusick  *
6*24792Skarels  *	@(#)if_pcl.c	6.5 (Berkeley) 09/16/85
723300Smckusick  */
811816Ssam 
911816Ssam #include "pcl.h"
1011816Ssam #if NPCL > 0
1111816Ssam /*
1211816Ssam  * DEC CSS PCL-11B Parallel Communications Interface
1311816Ssam  *
1413800Ssam  * Written by Mike Muuss and Jeff Schwab.
1511816Ssam  */
1611816Ssam #include "../machine/pte.h"
1711816Ssam 
1817116Sbloom #include "param.h"
1917116Sbloom #include "systm.h"
2017116Sbloom #include "mbuf.h"
2117116Sbloom #include "buf.h"
2217116Sbloom #include "protosw.h"
2317116Sbloom #include "socket.h"
2417116Sbloom #include "vmmac.h"
2517116Sbloom #include "ioctl.h"
2617116Sbloom #include "errno.h"
2711816Ssam 
2811816Ssam #include "../net/if.h"
2911816Ssam #include "../net/netisr.h"
3011816Ssam #include "../net/route.h"
31*24792Skarels 
32*24792Skarels #ifdef	BBNNET
33*24792Skarels #define	INET
34*24792Skarels #endif
3511816Ssam #include "../netinet/in.h"
3611816Ssam #include "../netinet/in_systm.h"
3711816Ssam #include "../netinet/ip.h"
3811816Ssam 
3911816Ssam #include "../vax/cpu.h"
4011816Ssam #include "../vax/mtpr.h"
4117116Sbloom #include "if_pclreg.h"
4217116Sbloom #include "if_uba.h"
4311816Ssam #include "../vaxuba/ubareg.h"
4411816Ssam #include "../vaxuba/ubavar.h"
4511816Ssam 
4611816Ssam /* The MTU has been carefully selected to prevent fragmentation <-> ArpaNet */
4713800Ssam #define	PCLMTU		(1006)	/* Max transmission unit (bytes) */
4813800Ssam #define	PCLMAXTDM	7	/* Max unit number on TDM bus */
4911816Ssam 
5011816Ssam int	pclprobe(), pclattach(), pclrint(), pclxint();
5113064Ssam int	pclinit(), pclioctl(), pcloutput(), pclreset();
5211816Ssam 
5311816Ssam struct	uba_device	*pclinfo[NPCL];
5411816Ssam u_short pclstd[] = { 0 };
5511816Ssam #define	PCLUNIT(x)	minor(x)
5611816Ssam struct	uba_driver pcldriver =
5711816Ssam 	{ pclprobe, 0, pclattach, 0, pclstd, "pcl", pclinfo };
5811816Ssam 
5911816Ssam /*
6011816Ssam  * PCL software status per interface.
6111816Ssam  *
6211816Ssam  * Each interface is referenced by a network interface structure,
6311816Ssam  * sc_if, which the routing code uses to locate the interface.
6411816Ssam  * This structure contains the output queue for the interface, its address, ...
6511816Ssam  * We also have, for each interface, a UBA interface structure, which
6611816Ssam  * contains information about the UNIBUS resources held by the interface:
6711816Ssam  * map registers, buffered data paths, etc.  Information is cached in this
6811816Ssam  * structure for use by the if_uba.c routines in running the interface
6911816Ssam  * efficiently.
7011816Ssam  */
7111816Ssam struct	pcl_softc {
7211816Ssam 	struct	ifnet sc_if;		/* network-visible interface */
7311816Ssam 	struct	ifuba sc_ifuba;		/* UNIBUS resources */
7411816Ssam 	short	sc_oactive;		/* is output active? */
7511816Ssam 	short	sc_olen;		/* length of last output */
7611816Ssam 	short	sc_lastdest;		/* previous destination */
7711816Ssam 	short	sc_odest;		/* current xmit destination */
7813800Ssam 	short	sc_bdest;		/* buffer's stated destination */
7911816Ssam 	short	sc_pattern;		/* identification pattern */
8011816Ssam } pcl_softc[NPCL];
8111816Ssam 
8211816Ssam /*
8311816Ssam  * Structure of "local header", which only goes between
8411816Ssam  * pcloutput and pclstart.
8511816Ssam  */
8611816Ssam struct pcl_header {
8711816Ssam 	short	pcl_dest;		/* Destination PCL station */
8811816Ssam };
8911816Ssam 
9011816Ssam /*
9111816Ssam  * Do non-DMA output of 1 word to determine presence of interface,
9211816Ssam  * and to find the interupt vector.  1 word messages are a special
9311816Ssam  * case in the receiver routine, and will be discarded.
9411816Ssam  */
9511816Ssam pclprobe(reg)
9611816Ssam 	caddr_t reg;
9711816Ssam {
9811816Ssam 	register int br, cvec;		/* r11, r10 value-result */
9911816Ssam 	register struct pcldevice *addr = (struct pcldevice *)reg;
10011816Ssam 
10111816Ssam #ifdef lint
10211816Ssam 	br = 0; cvec = br; br = cvec;
10311816Ssam 	pclrint(0); pclxint(0);
10411816Ssam #endif
10511816Ssam 	addr->pcl_rcr = PCL_RCINIT;
10611816Ssam 	addr->pcl_tcr = PCL_TXINIT;
10711816Ssam 	addr->pcl_tsba = 0xFFFE;
10811816Ssam 	/* going for 01777776 */
10911816Ssam 	addr->pcl_tsbc = -4;		/* really short */
11011816Ssam 	addr->pcl_tcr =
11111816Ssam 	 ((1 & 0xF) << 8) | PCL_TXNPR | PCL_SNDWD | PCL_STTXM | PCL_IE | 0x0030;
11211816Ssam 	DELAY(100000);
11311816Ssam 	addr->pcl_tcr = PCL_TXINIT;
11411816Ssam 	return (sizeof (struct pcldevice));
11511816Ssam }
11611816Ssam 
11711816Ssam /*
11811816Ssam  * Interface exists: make available by filling in network interface
11911816Ssam  * record.  System will initialize the interface when it is ready
12011816Ssam  * to accept packets.
12111816Ssam  */
12211816Ssam pclattach(ui)
12311816Ssam 	struct uba_device *ui;
12411816Ssam {
12511816Ssam 	register struct pcl_softc *sc = &pcl_softc[ui->ui_unit];
12611816Ssam 
12711816Ssam 	sc->sc_if.if_unit = ui->ui_unit;
12811816Ssam 	sc->sc_if.if_name = "pcl";
12911816Ssam 	sc->sc_if.if_mtu = PCLMTU;
13011816Ssam 	sc->sc_if.if_init = pclinit;
13111816Ssam 	sc->sc_if.if_output = pcloutput;
13213064Ssam 	sc->sc_if.if_ioctl = pclioctl;
13311816Ssam 	sc->sc_if.if_reset = pclreset;
13421774Skarels 	sc->sc_if.if_flags = IFF_BROADCAST;
13511816Ssam 	sc->sc_ifuba.ifu_flags = UBA_NEEDBDP;
13611816Ssam 	if_attach(&sc->sc_if);
13711816Ssam }
13811816Ssam 
13911816Ssam /*
14011816Ssam  * Reset of interface after UNIBUS reset.
14111816Ssam  * If interface is on specified uba, reset its state.
14211816Ssam  */
14311816Ssam pclreset(unit, uban)
14411816Ssam 	int unit, uban;
14511816Ssam {
14611816Ssam 	register struct uba_device *ui;
14711816Ssam 
14811816Ssam 	if (unit >= NPCL || (ui = pclinfo[unit]) == 0 || ui->ui_alive == 0 ||
14911816Ssam 	    ui->ui_ubanum != uban)
15011816Ssam 		return;
15111816Ssam 	printf(" pcl%d", unit);
15211816Ssam 	pclinit(unit);
15311816Ssam }
15411816Ssam 
15511816Ssam /*
15611816Ssam  * Initialization of interface; clear recorded pending
15711816Ssam  * operations, and reinitialize UNIBUS usage.
15811816Ssam  */
15911816Ssam pclinit(unit)
16011816Ssam 	int unit;
16111816Ssam {
16211816Ssam 	register struct pcl_softc *sc = &pcl_softc[unit];
16311816Ssam 	register struct uba_device *ui = pclinfo[unit];
16411816Ssam 	register struct pcldevice *addr;
16511816Ssam 	int s;
16611816Ssam 
16721774Skarels 	if (sc->sc_if.if_addrlist == (struct ifaddr *)0)
16813064Ssam 		return;
16911816Ssam 	if (if_ubainit(&sc->sc_ifuba, ui->ui_ubanum, 0,
17011816Ssam 	    (int)btoc(PCLMTU)) == 0) {
17111816Ssam 		printf("pcl%d: can't init\n", unit);
17221774Skarels 		sc->sc_if.if_flags &= ~(IFF_UP | IFF_RUNNING);
17311816Ssam 		return;
17411816Ssam 	}
17521774Skarels 	sc->sc_if.if_flags |= IFF_RUNNING;
17611816Ssam 	addr = (struct pcldevice *)ui->ui_addr;
17711816Ssam 	addr->pcl_rcr = PCL_RCINIT;
17811816Ssam 	addr->pcl_tcr = PCL_TXINIT;
17911816Ssam 
18011816Ssam 	/*
18111816Ssam 	 * Hang a receive and start any
18211816Ssam 	 * pending writes by faking a transmit complete.
18311816Ssam 	 */
18411816Ssam 	s = splimp();
18511816Ssam 	addr->pcl_rdba = (short) sc->sc_ifuba.ifu_r.ifrw_info;
18611816Ssam 	addr->pcl_rdbc = -PCLMTU;
18711816Ssam 	addr->pcl_rcr = (((int)(sc->sc_ifuba.ifu_r.ifrw_info>>12))&0x0030) |
18811816Ssam 		PCL_RCNPR | PCL_RCVWD | PCL_RCVDAT | PCL_IE;
18911816Ssam 	sc->sc_oactive = 0;
19011816Ssam 	pclstart(unit);
19111816Ssam 	splx(s);
19211816Ssam }
19311816Ssam 
19411816Ssam /*
19511816Ssam  * PCL output routine.
19611816Ssam  */
19711816Ssam pcloutput(ifp, m, dst)
19811816Ssam 	struct ifnet *ifp;
19911816Ssam 	struct mbuf *m;
20011816Ssam 	struct sockaddr *dst;
20111816Ssam {
20213089Ssam 	int dest, s, error;
20311816Ssam 	struct pcl_header *pclp;
20411816Ssam 	struct mbuf *m2;
20511816Ssam 
20611816Ssam 	switch (dst->sa_family) {
20711816Ssam 
20811816Ssam #ifdef INET
20911816Ssam 	case AF_INET:
21021774Skarels 		if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr))
21121774Skarels 			dest = 0;
21221774Skarels 		else
21321774Skarels 			dest = in_lnaof(((struct sockaddr_in *)dst)->sin_addr);
21413800Ssam 		if (dest > PCLMAXTDM) {
21513800Ssam 			error = EHOSTUNREACH;
21613800Ssam 			goto bad;
21713800Ssam 		}
21811816Ssam 		break;
21911816Ssam #endif
22011816Ssam 	default:
22111816Ssam 		printf("pcl%d: can't handle af%d\n", ifp->if_unit,
22211816Ssam 			dst->sa_family);
22311816Ssam 		error = EAFNOSUPPORT;
22411816Ssam 		goto bad;
22511816Ssam 	}
22611816Ssam 
22711816Ssam 	/*
22811816Ssam 	 * Add pseudo local net header.
22911816Ssam 	 * Actually, it does not get transmitted, but merely stripped
23011816Ssam 	 * off and used by the START routine to route the packet.
23111816Ssam 	 * If no space in first mbuf, allocate another.
23211816Ssam 	 */
23311816Ssam 	if (m->m_off > MMAXOFF ||
23411816Ssam 	    MMINOFF + sizeof (struct pcl_header) > m->m_off) {
23511816Ssam 		m2 = m_get(M_DONTWAIT, MT_HEADER);
23611816Ssam 		if (m2 == 0) {
23711816Ssam 			error = ENOBUFS;
23811816Ssam 			goto bad;
23911816Ssam 		}
24011816Ssam 		m2->m_next = m;
24111816Ssam 		m2->m_off = MMINOFF;
24211816Ssam 		m2->m_len = sizeof (struct pcl_header);
24311816Ssam 		m = m2;
24411816Ssam 	} else {
24511816Ssam 		m->m_off -= sizeof (struct pcl_header);
24611816Ssam 		m->m_len += sizeof (struct pcl_header);
24711816Ssam 	}
24811816Ssam 	pclp = mtod(m, struct pcl_header *);
24911816Ssam 	pclp->pcl_dest = dest;
25011816Ssam 
25111816Ssam 	/*
25211816Ssam 	 * Queue message on interface, and start output if interface
25311816Ssam 	 * not yet active.
25411816Ssam 	 */
25511816Ssam 	s = splimp();
25611816Ssam 	if (IF_QFULL(&ifp->if_snd)) {
25711816Ssam 		IF_DROP(&ifp->if_snd);
25811816Ssam 		error = ENOBUFS;
25911816Ssam 		goto qfull;
26011816Ssam 	}
26111816Ssam 	IF_ENQUEUE(&ifp->if_snd, m);
26211816Ssam 	if (pcl_softc[ifp->if_unit].sc_oactive == 0)
26311816Ssam 		pclstart(ifp->if_unit);
26411816Ssam 	splx(s);
26511816Ssam 	return (0);
26611816Ssam qfull:
26711816Ssam 	splx(s);
26811816Ssam bad:
26911816Ssam 	m_freem(m);
27011816Ssam 	return (error);
27111816Ssam }
27211816Ssam 
27311816Ssam /*
27411816Ssam  * Start or restart output on interface.
27511816Ssam  * If interface is already active, then this is a retransmit.
27611816Ssam  * If interface is not already active, get another datagram
27711816Ssam  * to send off of the interface queue, and map it to the interface
27811816Ssam  * before starting the output.
27911816Ssam  */
28011816Ssam pclstart(dev)
28111816Ssam 	dev_t dev;
28211816Ssam {
28311816Ssam         int unit = PCLUNIT(dev);
28411816Ssam 	struct uba_device *ui = pclinfo[unit];
28511816Ssam 	register struct pcl_softc *sc = &pcl_softc[unit];
28611816Ssam 	register struct pcldevice *addr;
28711816Ssam 	struct mbuf *m;
28811816Ssam 
28911816Ssam 	if (sc->sc_oactive)
29011816Ssam 		goto restart;
29111816Ssam 
29211816Ssam 	/*
29311816Ssam 	 * Not already active: dequeue another request
29411816Ssam 	 * and map it to the UNIBUS.  If no more requests,
29511816Ssam 	 * just return.
29611816Ssam 	 */
29711816Ssam 	IF_DEQUEUE(&sc->sc_if.if_snd, m);
29811816Ssam 	if (m == 0) {
29911816Ssam 		sc->sc_oactive = 0;
30011816Ssam 		return;
30111816Ssam 	}
30211816Ssam 
30311816Ssam 	/*
30411816Ssam 	 * Pull destination node out of pseudo-local net header.
30511816Ssam 	 * remove it from outbound data.
30611816Ssam 	 * Note that if_wubaput calls m_bcopy, which is prepared for
30711816Ssam 	 * m_len to be 0 in the first mbuf in the chain.
30811816Ssam 	 */
30913800Ssam 	sc->sc_bdest = mtod(m, struct pcl_header *)->pcl_dest;
31013800Ssam 	sc->sc_odest = sc->sc_bdest? sc->sc_bdest: 1;
31111816Ssam 	m->m_off += sizeof (struct pcl_header);
31211816Ssam 	m->m_len -= sizeof (struct pcl_header);
31311816Ssam 
31411816Ssam 	/* Map out to the DMA area */
31511816Ssam 	sc->sc_olen = if_wubaput(&sc->sc_ifuba, m);
31611816Ssam 
31711816Ssam restart:
31811816Ssam 	/*
31911816Ssam 	 * Have request mapped to UNIBUS for transmission.
32013800Ssam 	 * Purge any stale data from this BDP, and start the output.
32111816Ssam 	 */
32211816Ssam 	if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP)
32311816Ssam 		UBAPURGE(sc->sc_ifuba.ifu_uba, sc->sc_ifuba.ifu_w.ifrw_bdp);
32411816Ssam 	addr = (struct pcldevice *)ui->ui_addr;
32511816Ssam 	addr->pcl_tcr = PCL_TXINIT;
32611816Ssam 	addr->pcl_tsba = (int)sc->sc_ifuba.ifu_w.ifrw_info;
32711816Ssam 	addr->pcl_tsbc = -sc->sc_olen;
32811816Ssam 
32911816Ssam 	/*
33011816Ssam 	 * RIB (retry if busy) is used on the second and subsequent packets
33111816Ssam 	 * to a single host, because TCP often wants to transmit multiple
33211816Ssam 	 * buffers in a row,
33311816Ssam 	 * and if they are all going to the same place, the second and
33411816Ssam 	 * subsequent ones may be lost due to receiver not ready again yet.
33511816Ssam 	 * This can cause serious problems, because the TCP will resend the
33611816Ssam 	 * whole window, which just repeats the problem.  The result is that
33711816Ssam 	 * a perfectly good link appears not to work unless we take steps here.
33811816Ssam 	 */
33911816Ssam 	addr->pcl_tcr = (((int)(sc->sc_ifuba.ifu_w.ifrw_info>>12))&0x0030) |
34011816Ssam 		((sc->sc_odest & 0xF)<<8) |
34111816Ssam 		PCL_TXNPR | PCL_SNDWD | PCL_STTXM | PCL_IE |
34211816Ssam 		(sc->sc_odest == sc->sc_lastdest ? PCL_RIB : 0);
34311816Ssam 	sc->sc_lastdest = sc->sc_odest;
34411816Ssam 	sc->sc_oactive = 1;
34511816Ssam }
34611816Ssam 
34711816Ssam /*
34811816Ssam  * PCL transmitter interrupt.
34911816Ssam  * Start another output if more data to send.
35011816Ssam  */
35111816Ssam pclxint(unit)
35211816Ssam 	int unit;
35311816Ssam {
35411816Ssam 	register struct uba_device *ui = pclinfo[unit];
35511816Ssam 	register struct pcl_softc *sc = &pcl_softc[unit];
35611816Ssam 	register struct pcldevice *addr = (struct pcldevice *)ui->ui_addr;
35711816Ssam 
35811816Ssam 	if (sc->sc_oactive == 0) {
35911816Ssam 		printf ("pcl%d: stray interrupt\n", unit);
36011816Ssam 		return;
36111816Ssam 	}
36211816Ssam 	if (addr->pcl_tsr & PCL_ERR) {
36311816Ssam 		sc->sc_lastdest = 0;		/* don't bother with RIB */
36411816Ssam 		if (addr->pcl_tsr & PCL_MSTDWN) {
36511816Ssam 			addr->pcl_tmmr = PCL_MASTER|PCL_AUTOADDR;
36611816Ssam 			pclstart(unit);	/* Retry */
36711816Ssam 			printf("pcl%d: master\n", unit );
36811816Ssam 			return;
36911816Ssam 		}
37013800Ssam #ifndef PCL_TESTING
37113800Ssam 		if ((addr->pcl_tsr & (PCL_ERR|PCL_RESPB)) == (PCL_ERR|0))  {
37213800Ssam 			;	/* Receiver Offline -- not exactly an error */
37313800Ssam 		}  else  {
37413800Ssam #else
37513800Ssam 		{
37613800Ssam #endif
37711816Ssam 			/* Log as an error */
37811816Ssam 			printf("pcl%d: send error, tcr=%b tsr=%b\n",
37911816Ssam 				unit, addr->pcl_tcr, PCL_TCSRBITS,
38011816Ssam 				addr->pcl_tsr, PCL_TERRBITS);
38111816Ssam 			sc->sc_if.if_oerrors++;
38211816Ssam 		}
38311816Ssam 	} else
38411816Ssam 		sc->sc_if.if_opackets++;
38513800Ssam 	if (sc->sc_bdest == 0 && sc->sc_odest < PCLMAXTDM) {
38613800Ssam 		sc->sc_odest++;		/* do next host (broadcast) */
38713800Ssam 	} else {
38813800Ssam 		sc->sc_oactive = 0;
38913800Ssam 		if (sc->sc_ifuba.ifu_xtofree) {
39013800Ssam 			m_freem(sc->sc_ifuba.ifu_xtofree);
39113800Ssam 			sc->sc_ifuba.ifu_xtofree = 0;
39213800Ssam 		}
39311816Ssam 	}
39411816Ssam 	pclstart(unit);
39511816Ssam }
39611816Ssam 
39711816Ssam /*
39811816Ssam  * PCL interface receiver interrupt.
39911816Ssam  * If input error just drop packet.
40011816Ssam  */
40111816Ssam pclrint(unit)
40211816Ssam 	int unit;
40311816Ssam {
40411816Ssam 	register struct pcl_softc *sc = &pcl_softc[unit];
40511816Ssam 	struct pcldevice *addr = (struct pcldevice *)pclinfo[unit]->ui_addr;
40611816Ssam     	struct mbuf *m;
40713089Ssam 	int len;
40811816Ssam 	register struct ifqueue *inq;
40911816Ssam 
41011816Ssam 	sc->sc_if.if_ipackets++;
41111816Ssam 	/*
41211816Ssam 	 * Purge BDP; drop if input error indicated.
41311816Ssam 	 */
41411816Ssam 	if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP)
41511816Ssam 		UBAPURGE(sc->sc_ifuba.ifu_uba, sc->sc_ifuba.ifu_r.ifrw_bdp);
41611816Ssam 	if (addr->pcl_rsr & PCL_ERR) {
41711816Ssam 		printf("pcl%d: rcv error, rcr=%b rsr=%b\n",
41811816Ssam 			unit, addr->pcl_rcr, PCL_RCSRBITS,
41911816Ssam 			addr->pcl_rsr, PCL_RERRBITS);
42011816Ssam 		sc->sc_if.if_ierrors++;
42111816Ssam 		goto setup;
42211816Ssam 	}
42311816Ssam 	len = PCLMTU + addr->pcl_rdbc;
42411816Ssam 	if (len <= 0 || len > PCLMTU) {
42511816Ssam 		printf("pcl%d: bad len=%d.\n", unit, len);
42611816Ssam 		sc->sc_if.if_ierrors++;
42711816Ssam 		goto setup;
42811816Ssam 	}
42911816Ssam 
43011816Ssam 	/* Really short packets will be part of the startup sequence */
43111816Ssam 	if (len <= 4) {
43211816Ssam 		/* Later, do comming-up processing here */
43311816Ssam 		goto setup;	/* drop packet */
43411816Ssam 	}
43511816Ssam 
43611816Ssam 	/*
43711816Ssam 	 * Pull packet off interface.
43811816Ssam 	 */
439*24792Skarels 	m = if_rubaget(&sc->sc_ifuba, len, 0, &sc->sc_if);
44011816Ssam 	if (m == 0)
44111816Ssam 		goto setup;
44211816Ssam 
44311816Ssam 	schednetisr(NETISR_IP);
44411816Ssam 	inq = &ipintrq;
44511816Ssam 
44611816Ssam 	if (IF_QFULL(inq)) {
44711816Ssam 		IF_DROP(inq);
44811816Ssam 		m_freem(m);
44911816Ssam 	} else
45011816Ssam 		IF_ENQUEUE(inq, m);
45111816Ssam setup:
45211816Ssam 	/*
45311816Ssam 	 * Reset for next packet.
45411816Ssam 	 */
45511816Ssam 	addr->pcl_rcr = PCL_RCINIT;
45611816Ssam 	addr->pcl_rdba = (int)sc->sc_ifuba.ifu_r.ifrw_info;
45711816Ssam 	addr->pcl_rdbc = -PCLMTU;
45811816Ssam 	addr->pcl_rcr = (((int)(sc->sc_ifuba.ifu_w.ifrw_info>>12))&0x0030) |
45911816Ssam 		PCL_RCNPR | PCL_RCVWD | PCL_RCVDAT | PCL_IE;
46011816Ssam }
46113064Ssam 
46213064Ssam /*
46313064Ssam  * Process an ioctl request.
46413064Ssam  */
46513064Ssam pclioctl(ifp, cmd, data)
46613064Ssam 	register struct ifnet *ifp;
46713064Ssam 	int cmd;
46813064Ssam 	caddr_t data;
46913064Ssam {
47013064Ssam 	int s = splimp(), error = 0;
47113064Ssam 
47213064Ssam 	switch (cmd) {
47313064Ssam 
47413064Ssam 	case SIOCSIFADDR:
475*24792Skarels 		ifp->if_flags |= IFF_UP;
47621774Skarels 		if ((ifp->if_flags & IFF_RUNNING) == 0)
47713064Ssam 			pclinit(ifp->if_unit);
47813064Ssam 		break;
47913064Ssam 
48013064Ssam 	default:
48113064Ssam 		error = EINVAL;
48213064Ssam 	}
48313064Ssam 	splx(s);
48413064Ssam 	return (error);
48513064Ssam }
48611816Ssam #endif
487