xref: /csrg-svn/sys/vax/if/if_pcl.c (revision 45801)
123300Smckusick /*
229369Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
335325Sbostic  * All rights reserved.
423300Smckusick  *
544562Sbostic  * %sccs.include.redist.c%
635325Sbostic  *
7*45801Sbostic  *	@(#)if_pcl.c	7.6 (Berkeley) 12/16/90
823300Smckusick  */
911816Ssam 
1011816Ssam #include "pcl.h"
1111816Ssam #if NPCL > 0
1211816Ssam /*
1311816Ssam  * DEC CSS PCL-11B Parallel Communications Interface
1411816Ssam  *
1513800Ssam  * Written by Mike Muuss and Jeff Schwab.
1611816Ssam  */
17*45801Sbostic #include "../include/pte.h"
1811816Ssam 
19*45801Sbostic #include "sys/param.h"
20*45801Sbostic #include "sys/systm.h"
21*45801Sbostic #include "sys/mbuf.h"
22*45801Sbostic #include "sys/buf.h"
23*45801Sbostic #include "sys/protosw.h"
24*45801Sbostic #include "sys/socket.h"
25*45801Sbostic #include "sys/vmmac.h"
26*45801Sbostic #include "sys/ioctl.h"
27*45801Sbostic #include "sys/errno.h"
2811816Ssam 
29*45801Sbostic #include "net/if.h"
30*45801Sbostic #include "net/netisr.h"
31*45801Sbostic #include "net/route.h"
3224792Skarels 
3328952Skarels #ifdef INET
34*45801Sbostic #include "netinet/in.h"
35*45801Sbostic #include "netinet/in_systm.h"
36*45801Sbostic #include "netinet/in_var.h"
37*45801Sbostic #include "netinet/ip.h"
3828952Skarels #endif
3911816Ssam 
40*45801Sbostic #include "../include/cpu.h"
41*45801Sbostic #include "../include/mtpr.h"
4217116Sbloom #include "if_pclreg.h"
4317116Sbloom #include "if_uba.h"
44*45801Sbostic #include "../uba/ubareg.h"
45*45801Sbostic #include "../uba/ubavar.h"
4611816Ssam 
4711816Ssam /* The MTU has been carefully selected to prevent fragmentation <-> ArpaNet */
4813800Ssam #define	PCLMTU		(1006)	/* Max transmission unit (bytes) */
4913800Ssam #define	PCLMAXTDM	7	/* Max unit number on TDM bus */
5011816Ssam 
5111816Ssam int	pclprobe(), pclattach(), pclrint(), pclxint();
5213064Ssam int	pclinit(), pclioctl(), pcloutput(), pclreset();
5311816Ssam 
5411816Ssam struct	uba_device	*pclinfo[NPCL];
5511816Ssam u_short pclstd[] = { 0 };
5611816Ssam #define	PCLUNIT(x)	minor(x)
5711816Ssam struct	uba_driver pcldriver =
5811816Ssam 	{ pclprobe, 0, pclattach, 0, pclstd, "pcl", pclinfo };
5911816Ssam 
6011816Ssam /*
6111816Ssam  * PCL software status per interface.
6211816Ssam  *
6311816Ssam  * Each interface is referenced by a network interface structure,
6411816Ssam  * sc_if, which the routing code uses to locate the interface.
6511816Ssam  * This structure contains the output queue for the interface, its address, ...
6611816Ssam  * We also have, for each interface, a UBA interface structure, which
6711816Ssam  * contains information about the UNIBUS resources held by the interface:
6811816Ssam  * map registers, buffered data paths, etc.  Information is cached in this
6911816Ssam  * structure for use by the if_uba.c routines in running the interface
7011816Ssam  * efficiently.
7111816Ssam  */
7211816Ssam struct	pcl_softc {
7311816Ssam 	struct	ifnet sc_if;		/* network-visible interface */
7411816Ssam 	struct	ifuba sc_ifuba;		/* UNIBUS resources */
7511816Ssam 	short	sc_oactive;		/* is output active? */
7611816Ssam 	short	sc_olen;		/* length of last output */
7711816Ssam 	short	sc_lastdest;		/* previous destination */
7811816Ssam 	short	sc_odest;		/* current xmit destination */
7913800Ssam 	short	sc_bdest;		/* buffer's stated destination */
8011816Ssam 	short	sc_pattern;		/* identification pattern */
8111816Ssam } pcl_softc[NPCL];
8211816Ssam 
8311816Ssam /*
8411816Ssam  * Structure of "local header", which only goes between
8511816Ssam  * pcloutput and pclstart.
8611816Ssam  */
8711816Ssam struct pcl_header {
8811816Ssam 	short	pcl_dest;		/* Destination PCL station */
8911816Ssam };
9011816Ssam 
9111816Ssam /*
9211816Ssam  * Do non-DMA output of 1 word to determine presence of interface,
9311816Ssam  * and to find the interupt vector.  1 word messages are a special
9411816Ssam  * case in the receiver routine, and will be discarded.
9511816Ssam  */
pclprobe(reg)9611816Ssam pclprobe(reg)
9711816Ssam 	caddr_t reg;
9811816Ssam {
9911816Ssam 	register int br, cvec;		/* r11, r10 value-result */
10011816Ssam 	register struct pcldevice *addr = (struct pcldevice *)reg;
10111816Ssam 
10211816Ssam #ifdef lint
10311816Ssam 	br = 0; cvec = br; br = cvec;
10411816Ssam 	pclrint(0); pclxint(0);
10511816Ssam #endif
10611816Ssam 	addr->pcl_rcr = PCL_RCINIT;
10711816Ssam 	addr->pcl_tcr = PCL_TXINIT;
10811816Ssam 	addr->pcl_tsba = 0xFFFE;
10911816Ssam 	/* going for 01777776 */
11011816Ssam 	addr->pcl_tsbc = -4;		/* really short */
11111816Ssam 	addr->pcl_tcr =
11211816Ssam 	 ((1 & 0xF) << 8) | PCL_TXNPR | PCL_SNDWD | PCL_STTXM | PCL_IE | 0x0030;
11311816Ssam 	DELAY(100000);
11411816Ssam 	addr->pcl_tcr = PCL_TXINIT;
11511816Ssam 	return (sizeof (struct pcldevice));
11611816Ssam }
11711816Ssam 
11811816Ssam /*
11911816Ssam  * Interface exists: make available by filling in network interface
12011816Ssam  * record.  System will initialize the interface when it is ready
12111816Ssam  * to accept packets.
12211816Ssam  */
12311816Ssam pclattach(ui)
12411816Ssam 	struct uba_device *ui;
12511816Ssam {
12611816Ssam 	register struct pcl_softc *sc = &pcl_softc[ui->ui_unit];
12711816Ssam 
12811816Ssam 	sc->sc_if.if_unit = ui->ui_unit;
12911816Ssam 	sc->sc_if.if_name = "pcl";
13011816Ssam 	sc->sc_if.if_mtu = PCLMTU;
13111816Ssam 	sc->sc_if.if_init = pclinit;
13211816Ssam 	sc->sc_if.if_output = pcloutput;
13313064Ssam 	sc->sc_if.if_ioctl = pclioctl;
13411816Ssam 	sc->sc_if.if_reset = pclreset;
13521774Skarels 	sc->sc_if.if_flags = IFF_BROADCAST;
13611816Ssam 	sc->sc_ifuba.ifu_flags = UBA_NEEDBDP;
13711816Ssam 	if_attach(&sc->sc_if);
13811816Ssam }
13911816Ssam 
14011816Ssam /*
14111816Ssam  * Reset of interface after UNIBUS reset.
14211816Ssam  * If interface is on specified uba, reset its state.
14311816Ssam  */
pclreset(unit,uban)14411816Ssam pclreset(unit, uban)
14511816Ssam 	int unit, uban;
14611816Ssam {
14711816Ssam 	register struct uba_device *ui;
14811816Ssam 
14911816Ssam 	if (unit >= NPCL || (ui = pclinfo[unit]) == 0 || ui->ui_alive == 0 ||
15011816Ssam 	    ui->ui_ubanum != uban)
15111816Ssam 		return;
15211816Ssam 	printf(" pcl%d", unit);
15311816Ssam 	pclinit(unit);
15411816Ssam }
15511816Ssam 
15611816Ssam /*
15711816Ssam  * Initialization of interface; clear recorded pending
15811816Ssam  * operations, and reinitialize UNIBUS usage.
15911816Ssam  */
pclinit(unit)16011816Ssam pclinit(unit)
16111816Ssam 	int unit;
16211816Ssam {
16311816Ssam 	register struct pcl_softc *sc = &pcl_softc[unit];
16411816Ssam 	register struct uba_device *ui = pclinfo[unit];
16511816Ssam 	register struct pcldevice *addr;
16611816Ssam 	int s;
16711816Ssam 
16821774Skarels 	if (sc->sc_if.if_addrlist == (struct ifaddr *)0)
16913064Ssam 		return;
17011816Ssam 	if (if_ubainit(&sc->sc_ifuba, ui->ui_ubanum, 0,
17111816Ssam 	    (int)btoc(PCLMTU)) == 0) {
17211816Ssam 		printf("pcl%d: can't init\n", unit);
17321774Skarels 		sc->sc_if.if_flags &= ~(IFF_UP | IFF_RUNNING);
17411816Ssam 		return;
17511816Ssam 	}
17621774Skarels 	sc->sc_if.if_flags |= IFF_RUNNING;
17711816Ssam 	addr = (struct pcldevice *)ui->ui_addr;
17811816Ssam 	addr->pcl_rcr = PCL_RCINIT;
17911816Ssam 	addr->pcl_tcr = PCL_TXINIT;
18011816Ssam 
18111816Ssam 	/*
18211816Ssam 	 * Hang a receive and start any
18311816Ssam 	 * pending writes by faking a transmit complete.
18411816Ssam 	 */
18511816Ssam 	s = splimp();
18611816Ssam 	addr->pcl_rdba = (short) sc->sc_ifuba.ifu_r.ifrw_info;
18711816Ssam 	addr->pcl_rdbc = -PCLMTU;
18811816Ssam 	addr->pcl_rcr = (((int)(sc->sc_ifuba.ifu_r.ifrw_info>>12))&0x0030) |
18911816Ssam 		PCL_RCNPR | PCL_RCVWD | PCL_RCVDAT | PCL_IE;
19011816Ssam 	sc->sc_oactive = 0;
19111816Ssam 	pclstart(unit);
19211816Ssam 	splx(s);
19311816Ssam }
19411816Ssam 
19511816Ssam /*
19611816Ssam  * PCL output routine.
19711816Ssam  */
19811816Ssam pcloutput(ifp, m, dst)
19911816Ssam 	struct ifnet *ifp;
20011816Ssam 	struct mbuf *m;
20111816Ssam 	struct sockaddr *dst;
20211816Ssam {
20313089Ssam 	int dest, s, error;
20411816Ssam 	struct pcl_header *pclp;
20511816Ssam 	struct mbuf *m2;
20611816Ssam 
20711816Ssam 	switch (dst->sa_family) {
20811816Ssam 
20911816Ssam #ifdef INET
21011816Ssam 	case AF_INET:
21121774Skarels 		if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr))
21221774Skarels 			dest = 0;
21321774Skarels 		else
21421774Skarels 			dest = in_lnaof(((struct sockaddr_in *)dst)->sin_addr);
21513800Ssam 		if (dest > PCLMAXTDM) {
21613800Ssam 			error = EHOSTUNREACH;
21713800Ssam 			goto bad;
21813800Ssam 		}
21911816Ssam 		break;
22011816Ssam #endif
22111816Ssam 	default:
22211816Ssam 		printf("pcl%d: can't handle af%d\n", ifp->if_unit,
22311816Ssam 			dst->sa_family);
22411816Ssam 		error = EAFNOSUPPORT;
22511816Ssam 		goto bad;
22611816Ssam 	}
22711816Ssam 
22811816Ssam 	/*
22911816Ssam 	 * Add pseudo local net header.
23011816Ssam 	 * Actually, it does not get transmitted, but merely stripped
23111816Ssam 	 * off and used by the START routine to route the packet.
23211816Ssam 	 * If no space in first mbuf, allocate another.
23311816Ssam 	 */
23437476Ssklower 	M_PREPEND(m, sizeof(struct pcl_header), M_DONTWAIT);
23537476Ssklower 	if (m == 0) {
23637476Ssklower 		error = ENOBUFS;
23737476Ssklower 		goto bad;
23811816Ssam 	}
23911816Ssam 	pclp = mtod(m, struct pcl_header *);
24011816Ssam 	pclp->pcl_dest = dest;
24111816Ssam 
24211816Ssam 	/*
24311816Ssam 	 * Queue message on interface, and start output if interface
24411816Ssam 	 * not yet active.
24511816Ssam 	 */
24611816Ssam 	s = splimp();
24711816Ssam 	if (IF_QFULL(&ifp->if_snd)) {
24811816Ssam 		IF_DROP(&ifp->if_snd);
24911816Ssam 		error = ENOBUFS;
25011816Ssam 		goto qfull;
25111816Ssam 	}
25211816Ssam 	IF_ENQUEUE(&ifp->if_snd, m);
25311816Ssam 	if (pcl_softc[ifp->if_unit].sc_oactive == 0)
25411816Ssam 		pclstart(ifp->if_unit);
25511816Ssam 	splx(s);
25611816Ssam 	return (0);
25711816Ssam qfull:
25811816Ssam 	splx(s);
25911816Ssam bad:
26011816Ssam 	m_freem(m);
26111816Ssam 	return (error);
26211816Ssam }
26311816Ssam 
26411816Ssam /*
26511816Ssam  * Start or restart output on interface.
26611816Ssam  * If interface is already active, then this is a retransmit.
26711816Ssam  * If interface is not already active, get another datagram
26811816Ssam  * to send off of the interface queue, and map it to the interface
26911816Ssam  * before starting the output.
27011816Ssam  */
pclstart(dev)27111816Ssam pclstart(dev)
27211816Ssam 	dev_t dev;
27311816Ssam {
27411816Ssam         int unit = PCLUNIT(dev);
27511816Ssam 	struct uba_device *ui = pclinfo[unit];
27611816Ssam 	register struct pcl_softc *sc = &pcl_softc[unit];
27711816Ssam 	register struct pcldevice *addr;
27811816Ssam 	struct mbuf *m;
27911816Ssam 
28011816Ssam 	if (sc->sc_oactive)
28111816Ssam 		goto restart;
28211816Ssam 
28311816Ssam 	/*
28411816Ssam 	 * Not already active: dequeue another request
28511816Ssam 	 * and map it to the UNIBUS.  If no more requests,
28611816Ssam 	 * just return.
28711816Ssam 	 */
28811816Ssam 	IF_DEQUEUE(&sc->sc_if.if_snd, m);
28911816Ssam 	if (m == 0) {
29011816Ssam 		sc->sc_oactive = 0;
29111816Ssam 		return;
29211816Ssam 	}
29311816Ssam 
29411816Ssam 	/*
29511816Ssam 	 * Pull destination node out of pseudo-local net header.
29611816Ssam 	 * remove it from outbound data.
29711816Ssam 	 * Note that if_wubaput calls m_bcopy, which is prepared for
29811816Ssam 	 * m_len to be 0 in the first mbuf in the chain.
29911816Ssam 	 */
30013800Ssam 	sc->sc_bdest = mtod(m, struct pcl_header *)->pcl_dest;
30113800Ssam 	sc->sc_odest = sc->sc_bdest? sc->sc_bdest: 1;
30237476Ssklower 	m->m_data += sizeof (struct pcl_header);
30311816Ssam 	m->m_len -= sizeof (struct pcl_header);
30437476Ssklower 	if (m->m_flags & M_PKTHDR)
30537476Ssklower 		m->m_pkthdr.len -= sizeof (struct pcl_header);
30611816Ssam 
30711816Ssam 	/* Map out to the DMA area */
30811816Ssam 	sc->sc_olen = if_wubaput(&sc->sc_ifuba, m);
30911816Ssam 
31011816Ssam restart:
31111816Ssam 	/*
31211816Ssam 	 * Have request mapped to UNIBUS for transmission.
31313800Ssam 	 * Purge any stale data from this BDP, and start the output.
31411816Ssam 	 */
31511816Ssam 	if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP)
31611816Ssam 		UBAPURGE(sc->sc_ifuba.ifu_uba, sc->sc_ifuba.ifu_w.ifrw_bdp);
31711816Ssam 	addr = (struct pcldevice *)ui->ui_addr;
31811816Ssam 	addr->pcl_tcr = PCL_TXINIT;
31911816Ssam 	addr->pcl_tsba = (int)sc->sc_ifuba.ifu_w.ifrw_info;
32011816Ssam 	addr->pcl_tsbc = -sc->sc_olen;
32111816Ssam 
32211816Ssam 	/*
32311816Ssam 	 * RIB (retry if busy) is used on the second and subsequent packets
32411816Ssam 	 * to a single host, because TCP often wants to transmit multiple
32511816Ssam 	 * buffers in a row,
32611816Ssam 	 * and if they are all going to the same place, the second and
32711816Ssam 	 * subsequent ones may be lost due to receiver not ready again yet.
32811816Ssam 	 * This can cause serious problems, because the TCP will resend the
32911816Ssam 	 * whole window, which just repeats the problem.  The result is that
33011816Ssam 	 * a perfectly good link appears not to work unless we take steps here.
33111816Ssam 	 */
33211816Ssam 	addr->pcl_tcr = (((int)(sc->sc_ifuba.ifu_w.ifrw_info>>12))&0x0030) |
33311816Ssam 		((sc->sc_odest & 0xF)<<8) |
33411816Ssam 		PCL_TXNPR | PCL_SNDWD | PCL_STTXM | PCL_IE |
33511816Ssam 		(sc->sc_odest == sc->sc_lastdest ? PCL_RIB : 0);
33611816Ssam 	sc->sc_lastdest = sc->sc_odest;
33711816Ssam 	sc->sc_oactive = 1;
33811816Ssam }
33911816Ssam 
34011816Ssam /*
34111816Ssam  * PCL transmitter interrupt.
34211816Ssam  * Start another output if more data to send.
34311816Ssam  */
pclxint(unit)34411816Ssam pclxint(unit)
34511816Ssam 	int unit;
34611816Ssam {
34711816Ssam 	register struct uba_device *ui = pclinfo[unit];
34811816Ssam 	register struct pcl_softc *sc = &pcl_softc[unit];
34911816Ssam 	register struct pcldevice *addr = (struct pcldevice *)ui->ui_addr;
35011816Ssam 
35111816Ssam 	if (sc->sc_oactive == 0) {
35211816Ssam 		printf ("pcl%d: stray interrupt\n", unit);
35311816Ssam 		return;
35411816Ssam 	}
35511816Ssam 	if (addr->pcl_tsr & PCL_ERR) {
35611816Ssam 		sc->sc_lastdest = 0;		/* don't bother with RIB */
35711816Ssam 		if (addr->pcl_tsr & PCL_MSTDWN) {
35811816Ssam 			addr->pcl_tmmr = PCL_MASTER|PCL_AUTOADDR;
35911816Ssam 			pclstart(unit);	/* Retry */
36011816Ssam 			printf("pcl%d: master\n", unit );
36111816Ssam 			return;
36211816Ssam 		}
36313800Ssam #ifndef PCL_TESTING
36413800Ssam 		if ((addr->pcl_tsr & (PCL_ERR|PCL_RESPB)) == (PCL_ERR|0))  {
36513800Ssam 			;	/* Receiver Offline -- not exactly an error */
36613800Ssam 		}  else  {
36713800Ssam #else
36813800Ssam 		{
36913800Ssam #endif
37011816Ssam 			/* Log as an error */
37111816Ssam 			printf("pcl%d: send error, tcr=%b tsr=%b\n",
37211816Ssam 				unit, addr->pcl_tcr, PCL_TCSRBITS,
37311816Ssam 				addr->pcl_tsr, PCL_TERRBITS);
37411816Ssam 			sc->sc_if.if_oerrors++;
37511816Ssam 		}
37611816Ssam 	} else
37711816Ssam 		sc->sc_if.if_opackets++;
37813800Ssam 	if (sc->sc_bdest == 0 && sc->sc_odest < PCLMAXTDM) {
37913800Ssam 		sc->sc_odest++;		/* do next host (broadcast) */
38013800Ssam 	} else {
38113800Ssam 		sc->sc_oactive = 0;
38213800Ssam 		if (sc->sc_ifuba.ifu_xtofree) {
38313800Ssam 			m_freem(sc->sc_ifuba.ifu_xtofree);
38413800Ssam 			sc->sc_ifuba.ifu_xtofree = 0;
38513800Ssam 		}
38611816Ssam 	}
38711816Ssam 	pclstart(unit);
38811816Ssam }
38911816Ssam 
39011816Ssam /*
39111816Ssam  * PCL interface receiver interrupt.
39211816Ssam  * If input error just drop packet.
39311816Ssam  */
pclrint(unit)39411816Ssam pclrint(unit)
39511816Ssam 	int unit;
39611816Ssam {
39711816Ssam 	register struct pcl_softc *sc = &pcl_softc[unit];
39811816Ssam 	struct pcldevice *addr = (struct pcldevice *)pclinfo[unit]->ui_addr;
39911816Ssam     	struct mbuf *m;
40013089Ssam 	int len;
40111816Ssam 	register struct ifqueue *inq;
40211816Ssam 
40311816Ssam 	sc->sc_if.if_ipackets++;
40411816Ssam 	/*
40511816Ssam 	 * Purge BDP; drop if input error indicated.
40611816Ssam 	 */
40711816Ssam 	if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP)
40811816Ssam 		UBAPURGE(sc->sc_ifuba.ifu_uba, sc->sc_ifuba.ifu_r.ifrw_bdp);
40911816Ssam 	if (addr->pcl_rsr & PCL_ERR) {
41011816Ssam 		printf("pcl%d: rcv error, rcr=%b rsr=%b\n",
41111816Ssam 			unit, addr->pcl_rcr, PCL_RCSRBITS,
41211816Ssam 			addr->pcl_rsr, PCL_RERRBITS);
41311816Ssam 		sc->sc_if.if_ierrors++;
41411816Ssam 		goto setup;
41511816Ssam 	}
41611816Ssam 	len = PCLMTU + addr->pcl_rdbc;
41711816Ssam 	if (len <= 0 || len > PCLMTU) {
41811816Ssam 		printf("pcl%d: bad len=%d.\n", unit, len);
41911816Ssam 		sc->sc_if.if_ierrors++;
42011816Ssam 		goto setup;
42111816Ssam 	}
42211816Ssam 
42311816Ssam 	/* Really short packets will be part of the startup sequence */
42411816Ssam 	if (len <= 4) {
42511816Ssam 		/* Later, do comming-up processing here */
42611816Ssam 		goto setup;	/* drop packet */
42711816Ssam 	}
42811816Ssam 
42911816Ssam 	/*
43011816Ssam 	 * Pull packet off interface.
43111816Ssam 	 */
43224792Skarels 	m = if_rubaget(&sc->sc_ifuba, len, 0, &sc->sc_if);
43311816Ssam 	if (m == 0)
43411816Ssam 		goto setup;
43511816Ssam 
43611816Ssam 	schednetisr(NETISR_IP);
43711816Ssam 	inq = &ipintrq;
43811816Ssam 
43911816Ssam 	if (IF_QFULL(inq)) {
44011816Ssam 		IF_DROP(inq);
44111816Ssam 		m_freem(m);
44211816Ssam 	} else
44311816Ssam 		IF_ENQUEUE(inq, m);
44411816Ssam setup:
44511816Ssam 	/*
44611816Ssam 	 * Reset for next packet.
44711816Ssam 	 */
44811816Ssam 	addr->pcl_rcr = PCL_RCINIT;
44911816Ssam 	addr->pcl_rdba = (int)sc->sc_ifuba.ifu_r.ifrw_info;
45011816Ssam 	addr->pcl_rdbc = -PCLMTU;
45111816Ssam 	addr->pcl_rcr = (((int)(sc->sc_ifuba.ifu_w.ifrw_info>>12))&0x0030) |
45211816Ssam 		PCL_RCNPR | PCL_RCVWD | PCL_RCVDAT | PCL_IE;
45311816Ssam }
45413064Ssam 
45513064Ssam /*
45613064Ssam  * Process an ioctl request.
45713064Ssam  */
45826301Skarels /* ARGSUSED */
pclioctl(ifp,cmd,data)45913064Ssam pclioctl(ifp, cmd, data)
46013064Ssam 	register struct ifnet *ifp;
46113064Ssam 	int cmd;
46213064Ssam 	caddr_t data;
46313064Ssam {
46413064Ssam 	int s = splimp(), error = 0;
46513064Ssam 
46613064Ssam 	switch (cmd) {
46713064Ssam 
46813064Ssam 	case SIOCSIFADDR:
46924792Skarels 		ifp->if_flags |= IFF_UP;
47021774Skarels 		if ((ifp->if_flags & IFF_RUNNING) == 0)
47113064Ssam 			pclinit(ifp->if_unit);
47213064Ssam 		break;
47313064Ssam 
47413064Ssam 	default:
47513064Ssam 		error = EINVAL;
47613064Ssam 	}
47713064Ssam 	splx(s);
47813064Ssam 	return (error);
47913064Ssam }
48011816Ssam #endif
481