* Copyright (c) 1982, 1986 Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)if_ex.c 7.4 (Berkeley) 8/4/88
* Excelan EXOS 204 Interface
#include "../net/netisr.h"
#include "../net/route.h"
#include "../netinet/in.h"
#include "../netinet/in_systm.h"
#include "../netinet/in_var.h"
#include "../netinet/ip.h"
#include "../netinet/if_ether.h"
#include "../netns/ns_if.h"
#include "../vaxuba/ubareg.h"
#include "../vaxuba/ubavar.h"
/* #define DEBUG /* check for "impossible" events */
#define NH2X 4 /* a sufficient number is critical */
#define NX2H 4 /* this is pretty arbitrary */
#define EXWATCHINTVL 10 /* call exwatch() every 10 seconds */
int exprobe(), exattach(), excdint();
struct uba_device
*exinfo
[NEX
];
struct uba_driver exdriver
=
{ exprobe
, 0, exattach
, 0, exstd
, "ex", exinfo
};
int exinit(),exoutput(),exioctl(),exreset(),exwatch();
struct ex_msg
*exgetcbuf();
* Ethernet software status per interface.
* Each interface is referenced by a network interface structure,
* xs_if, which the routing code uses to locate the interface.
* This structure contains the output queue for the interface, its address, ...
* We also have, for each interface, a UBA interface structure, which
* contains information about the UNIBUS resources held by the interface:
* map registers, buffered data paths, etc. Information is cached in this
* structure for use by the if_uba.c routines in running the interface
struct arpcom xs_ac
; /* Ethernet common part */
#define xs_if xs_ac.ac_if /* network-visible interface */
#define xs_addr xs_ac.ac_enaddr /* hardware Ethernet address */
struct ifuba xs_ifuba
; /* UNIBUS resources */
int xs_flags
; /* private flags */
#define EX_XPENDING 1 /* xmit rqst pending on EXOS */
#define EX_STATPENDING (1<<1) /* stats rqst pending on EXOS */
#define EX_RUNNING (1<<2) /* board is running */
#define EX_SETADDR (1<<3) /* physaddr has been changed */
struct ex_msg
*xs_h2xnext
; /* host pointer to request queue */
struct ex_msg
*xs_x2hnext
; /* host pointer to reply queue */
int xs_ubaddr
; /* map info for structs below */
#define UNIADDR(x) ((u_long)(x)&0x3FFFF)
#define P_UNIADDR(x) ((u_long)(x)&0x3FFF0)
/* the following structures are always mapped in */
u_short xs_h2xhdr
; /* EXOS's request queue header */
u_short xs_x2hhdr
; /* EXOS's reply queue header */
struct ex_msg xs_h2xent
[NH2X
]; /* request msg buffers */
struct ex_msg xs_x2hent
[NX2H
]; /* reply msg buffers */
struct confmsg xs_cm
; /* configuration message */
struct stat_array xs_xsa
; /* EXOS writes stats here */
#define INCORE_BASE(p) ((caddr_t)((u_long)(&(p)->xs_h2xhdr) & 0xFFFFFFF0))
#define RVAL_OFF(unit, n) \
((caddr_t)(&(ex_softc[unit].n)) - INCORE_BASE(&ex_softc[unit]))
#define LVAL_OFF(unit, n) \
((caddr_t)(ex_softc[unit].n) - INCORE_BASE(&ex_softc[unit]))
#define H2XHDR_OFFSET(unit) RVAL_OFF(unit, xs_h2xhdr)
#define X2HHDR_OFFSET(unit) RVAL_OFF(unit, xs_x2hhdr)
#define H2XENT_OFFSET(unit) LVAL_OFF(unit, xs_h2xent)
#define X2HENT_OFFSET(unit) LVAL_OFF(unit, xs_x2hent)
#define CM_OFFSET(unit) RVAL_OFF(unit, xs_cm)
#define SA_OFFSET(unit) RVAL_OFF(unit, xs_xsa)
#define INCORE_SIZE(unit) RVAL_OFF(unit, xs_end)
int xs_end
; /* place holder */
* The following structure is a kludge to store a cvec value
* between the time exprobe is called, and exconfig.
struct exdevice
*xc_csraddr
;
int ex_ncall
= 0; /* counts calls to exprobe */
register int br
, cvec
; /* r11, r10 value-result */
register struct exdevice
*addr
= (struct exdevice
*)reg
;
* We program the EXOS interrupt vector, like dmf device.
cvec
= (uba_hd
[numuba
].uh_lastiv
-= 4);
ex_cvecs
[ex_ncall
].xc_csraddr
= addr
;
ex_cvecs
[ex_ncall
].xc_cvec
= cvec
;
* Reset EXOS and run self-test (guaranteed to
* complete within 2 seconds).
addr
->xd_porta
= EX_RESET
;
while (((addr
->xd_portb
& EX_TESTOK
) == 0) && --i
)
if ((addr
->xd_portb
& EX_TESTOK
) == 0) {
printf("ex: self-test failed\n");
return (sizeof(struct exdevice
));
* Interface exists: make available by filling in network interface
* record. System will initialize the interface when it is ready
* to accept packets. Board is temporarily configured and issues
* a NET_ADDRS command, only to get the Ethernet address.
register struct ex_softc
*xs
= &ex_softc
[ui
->ui_unit
];
register struct ifnet
*ifp
= &xs
->xs_if
;
register struct exdevice
*addr
= (struct exdevice
*)ui
->ui_addr
;
register struct ex_msg
*bp
;
ifp
->if_unit
= ui
->ui_unit
;
* Temporarily map queues in order to configure EXOS
xs
->xs_ubaddr
= uballoc(ui
->ui_ubanum
, INCORE_BASE(xs
),
exconfig(ui
, 0); /* without interrupts */
if (xs
->xs_cm
.cm_cc
) goto badconf
;
bp
->mb_rqst
= LLNET_ADDRS
;
bp
->mb_na
.na_mask
= READ_OBJ
;
bp
->mb_na
.na_slot
= PHYSSLOT
;
bp
->mb_status
|= MH_EXOS
;
addr
->xd_portb
= EX_NTRUPT
;
while ((bp
->mb_status
& MH_OWNER
) == MH_EXOS
) /* poll for reply */
printf("ex%d: HW %c.%c, NX %c.%c, hardware address %s\n",
ui
->ui_unit
, xs
->xs_cm
.cm_vc
[2], xs
->xs_cm
.cm_vc
[3],
xs
->xs_cm
.cm_vc
[0], xs
->xs_cm
.cm_vc
[1],
ether_sprintf(bp
->mb_na
.na_addrs
));
bcopy((caddr_t
)bp
->mb_na
.na_addrs
, (caddr_t
)xs
->xs_addr
,
ifp
->if_output
= exoutput
;
ifp
->if_flags
= IFF_BROADCAST
;
xs
->xs_ifuba
.ifu_flags
= UBA_CANTWAIT
;
ubarelse(ui
->ui_ubanum
, &xs
->xs_ubaddr
);
* Reset of interface after UNIBUS reset.
* If interface is on specified uba, reset its state.
register struct uba_device
*ui
;
if (unit
>= NEX
|| (ui
= exinfo
[unit
]) == 0 || ui
->ui_alive
== 0 ||
ex_softc
[unit
].xs_if
.if_flags
&= ~IFF_RUNNING
;
ex_softc
[unit
].xs_flags
&= ~EX_RUNNING
;
* Initialization of interface; clear recorded pending
* operations, and reinitialize UNIBUS usage.
* Called at boot time (with interrupts disabled?),
* and at ifconfig time via exioctl, with interrupts disabled.
register struct ex_softc
*xs
= &ex_softc
[unit
];
register struct uba_device
*ui
= exinfo
[unit
];
register struct exdevice
*addr
= (struct exdevice
*)ui
->ui_addr
;
register struct ifnet
*ifp
= &xs
->xs_if
;
register struct ex_msg
*bp
;
/* not yet, if address still unknown */
if (ifp
->if_addrlist
== (struct ifaddr
*)0)
if (xs
->xs_flags
& EX_RUNNING
)
if ((ifp
->if_flags
& IFF_RUNNING
) == 0) {
if (if_ubainit(&xs
->xs_ifuba
, ui
->ui_ubanum
,
sizeof (struct ether_header
),
(int)btoc(EXMAXRBUF
-sizeof(struct ether_header
))) == 0) {
printf("ex%d: can't initialize\n", unit
);
xs
->xs_if
.if_flags
&= ~IFF_UP
;
xs
->xs_ubaddr
= uballoc(ui
->ui_ubanum
, INCORE_BASE(xs
),
exconfig(ui
, 4); /* with vectored interrupts*/
* Put EXOS on the Ethernet, using NET_MODE command
bp
->mb_rqst
= LLNET_MODE
;
bp
->mb_nm
.nm_mask
= WRITE_OBJ
;
bp
->mb_nm
.nm_mode
= MODE_PERF
;
bp
->mb_status
|= MH_EXOS
;
addr
->xd_portb
= EX_NTRUPT
;
while ((bp
->mb_status
& MH_OWNER
) == MH_EXOS
) /* poll for reply */
bp
->mb_length
= MBDATALEN
;
bp
->mb_status
|= MH_EXOS
; /* free up buffer */
addr
->xd_portb
= EX_NTRUPT
; /* tell EXOS about it */
xs
->xs_x2hnext
= xs
->xs_x2hnext
->mb_next
;
ifp
->if_watchdog
= exwatch
;
ifp
->if_timer
= EXWATCHINTVL
;
s
= splimp(); /* are interrupts always disabled here, anyway? */
exhangrcv(unit
); /* hang receive request */
xs
->xs_if
.if_flags
|= IFF_RUNNING
;
xs
->xs_flags
|= EX_RUNNING
;
if (xs
->xs_flags
& EX_SETADDR
)
ex_setaddr((u_char
*)0, unit
);
exstart(unit
); /* start transmits */
* Reset, test, and configure EXOS. This routine assumes
* that message queues, etc. have already been mapped into
* the UBA. It is called by exinit, and should also be
register int unit
= ui
->ui_unit
;
register struct ex_softc
*xs
= &ex_softc
[unit
];
register struct exdevice
*addr
= (struct exdevice
*) ui
->ui_addr
;
register struct confmsg
*cm
= &xs
->xs_cm
;
register struct ex_msg
*bp
;
* Reset EXOS, wait for self-test to complete
addr
->xd_porta
= EX_RESET
;
while ((addr
->xd_portb
& EX_TESTOK
) == 0)
* Set up configuration message.
cm
->cm_opmode
= 0; /* link-level controller mode */
cm
->cm_dfo
= 0x0101; /* enable host data order conversion */
cm
->cm_ham
= 3; /* absolute address mode */
cm
->cm_byteptrn
[0] = 0x01; /* EXOS deduces data order of host */
cm
->cm_byteptrn
[1] = 0x03; /* by looking at this pattern */
cm
->cm_byteptrn
[2] = 0x07;
cm
->cm_byteptrn
[3] = 0x0F;
cm
->cm_wordptrn
[0] = 0x0103;
cm
->cm_wordptrn
[1] = 0x070F;
cm
->cm_lwordptrn
= 0x0103070F;
for (i
=0; i
<20; i
++) cm
->cm_rsrvd
[i
] = 0;
cm
->cm_h2xba
= P_UNIADDR(xs
->xs_ubaddr
);
cm
->cm_h2xhdr
= H2XHDR_OFFSET(unit
);
cm
->cm_h2xtyp
= 0; /* should never wait for rqst buffer */
cm
->cm_x2hba
= cm
->cm_h2xba
;
cm
->cm_x2hhdr
= X2HHDR_OFFSET(unit
);
cm
->cm_x2htyp
= itype
; /* 0 for none, 4 for vectored */
for (i
=0; (addr
!= ex_cvecs
[i
].xc_csraddr
); i
++)
panic("ex: matching csr address not found");
cm
->cm_x2haddr
= ex_cvecs
[i
].xc_cvec
; /* stashed here by exprobe */
* Set up message queues and headers.
* First the request queue.
for (bp
= &xs
->xs_h2xent
[0]; bp
< &xs
->xs_h2xent
[NH2X
]; bp
++) {
bp
->mb_link
= (u_short
)((char *)(bp
+1)-INCORE_BASE(xs
));
bp
->mb_length
= MBDATALEN
;
xs
->xs_h2xent
[NH2X
-1].mb_link
=
(u_short
)H2XENT_OFFSET(unit
);
xs
->xs_h2xent
[NH2X
-1].mb_next
=
/* Now the reply queue. */
for (bp
= &xs
->xs_x2hent
[0]; bp
< &xs
->xs_x2hent
[NX2H
]; bp
++) {
bp
->mb_link
= (u_short
)((char *)(bp
+1)-INCORE_BASE(xs
));
bp
->mb_length
= MBDATALEN
;
xs
->xs_x2hent
[NX2H
-1].mb_link
=
(u_short
)X2HENT_OFFSET(unit
);
xs
->xs_x2hent
[NX2H
-1].mb_next
=
* Write config msg address to EXOS and wait for
* configuration to complete (guaranteed response
shiftreg
= (u_long
)0x0000FFFF;
for (i
= 0; i
< 8; i
++) {
shiftreg
= P_UNIADDR(xs
->xs_ubaddr
) + CM_OFFSET(unit
);
while (addr
->xd_portb
& EX_UNREADY
)
addr
->xd_portb
= (u_char
)(shiftreg
& 0xFF);
for (i
= 1000000; (cm
->cm_cc
== 0xFF) && i
; --i
);
printf("ex%d: configuration failed; cc = %x\n",
* Start or re-start output on interface.
* Get another datagram to send off of the interface queue,
* and map it to the interface before starting the output.
* This routine is called by exinit(), exoutput(), and excdint().
* In all cases, interrupts by EXOS are disabled.
struct uba_device
*ui
= exinfo
[unit
];
register struct ex_softc
*xs
= &ex_softc
[unit
];
register struct exdevice
*addr
= (struct exdevice
*)ui
->ui_addr
;
register struct ex_msg
*bp
;
if (xs
->xs_flags
& EX_XPENDING
)
panic("exstart(): xmit still pending");
IF_DEQUEUE(&xs
->xs_if
.if_snd
, m
);
len
= if_wubaput(&xs
->xs_ifuba
, m
);
if (len
- sizeof(struct ether_header
) < ETHERMIN
)
len
= ETHERMIN
+ sizeof(struct ether_header
);
* Place a transmit request.
bp
->mb_rqst
= LLRTRANSMIT
;
bp
->mb_et
.et_blks
[0].bb_len
= (u_short
)len
;
*(u_long
*)bp
->mb_et
.et_blks
[0].bb_addr
=
UNIADDR(xs
->xs_ifuba
.ifu_w
.ifrw_info
);
xs
->xs_flags
|= EX_XPENDING
;
bp
->mb_status
|= MH_EXOS
;
addr
->xd_portb
= EX_NTRUPT
;
* Command done interrupt.
register struct ex_softc
*xs
= &ex_softc
[unit
];
register struct ex_msg
*bp
= xs
->xs_x2hnext
;
struct uba_device
*ui
= exinfo
[unit
];
struct exdevice
*addr
= (struct exdevice
*)ui
->ui_addr
;
while ((bp
->mb_status
& MH_OWNER
) == MH_HOST
) {
if ((xs
->xs_flags
& EX_XPENDING
) == 0)
panic("exxmit: no xmit pending");
xs
->xs_flags
&= ~EX_XPENDING
;
if (bp
->mb_rply
== LL_OK
) {
} else if (bp
->mb_rply
& LLXM_1RTRY
) {
xs
->xs_if
.if_collisions
++;
} else if (bp
->mb_rply
& LLXM_RTRYS
) {
xs
->xs_if
.if_collisions
+= 2; /* guess */
} else if (bp
->mb_rply
& LLXM_ERROR
) {
log(LOG_ERR
, "ex%d: transmit error=%b\n",
unit
, bp
->mb_rply
, XMIT_BITS
);
if (xs
->xs_ifuba
.ifu_xtofree
) {
m_freem(xs
->xs_ifuba
.ifu_xtofree
);
xs
->xs_ifuba
.ifu_xtofree
= 0;
xs
->xs_if
.if_ierrors
= xs
->xs_xsa
.sa_crc
;
xs
->xs_flags
&= ~EX_STATPENDING
;
panic("ex%d: unknown reply");
bp
->mb_length
= MBDATALEN
;
bp
->mb_status
|= MH_EXOS
; /* free up buffer */
addr
->xd_portb
= EX_NTRUPT
; /* tell EXOS about it */
bp
= xs
->xs_x2hnext
= xs
->xs_x2hnext
->mb_next
;
* Get a request buffer, fill in standard values, advance pointer.
register struct ex_msg
*bp
= xs
->xs_h2xnext
;
if ((bp
->mb_status
& MH_OWNER
) == MH_EXOS
)
panic("exgetcbuf(): EXOS owns message buffer");
bp
->mb_length
= MBDATALEN
;
xs
->xs_h2xnext
= xs
->xs_h2xnext
->mb_next
;
* Process Ethernet receive completion:
* If input error just drop packet.
* Otherwise purge input buffered data path and examine
* packet to determine type. If can't determine length
* from type, then have to drop packet. Otherwise decapsulate
* packet based on type and pass to type-specific higher-level
register struct ex_msg
*bp
;
register struct ex_softc
*xs
= &ex_softc
[unit
];
register struct ether_header
*eh
;
register int len
, off
, resid
;
register struct ifqueue
*inq
;
len
= bp
->mb_er
.er_blks
[0].bb_len
- sizeof(struct ether_header
) - 4;
if (bp
->mb_rply
!= LL_OK
) {
log(LOG_ERR
, "ex%d: receive error=%b\n",
unit
, bp
->mb_rply
, RECV_BITS
);
eh
= (struct ether_header
*)(xs
->xs_ifuba
.ifu_r
.ifrw_addr
);
* Deal with trailer protocol: if type is trailer
* get true type from first 16-bit word past data.
* Remember that type was trailer by setting off.
eh
->ether_type
= ntohs((u_short
)eh
->ether_type
);
#define exdataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
if (eh
->ether_type
>= ETHERTYPE_TRAIL
&&
eh
->ether_type
< ETHERTYPE_TRAIL
+ETHERTYPE_NTRAILER
) {
off
= (eh
->ether_type
- ETHERTYPE_TRAIL
) * 512;
eh
->ether_type
= ntohs(*exdataaddr(eh
, off
, u_short
*));
resid
= ntohs(*(exdataaddr(eh
, off
+2, u_short
*)));
* Pull packet off interface. Off is nonzero if packet
* has trailing header; if_rubaget will then force this header
* information to be at the front, but we still have to drop
* the type and length which are at the front of any trailer data.
m
= if_rubaget(&xs
->xs_ifuba
, len
, off
, &xs
->xs_if
);
ifp
= *(mtod(m
, struct ifnet
**));
m
->m_off
+= 2 * sizeof (u_short
);
m
->m_len
-= 2 * sizeof (u_short
);
*(mtod(m
, struct ifnet
**)) = ifp
;
switch (eh
->ether_type
) {
schednetisr(NETISR_IP
); /* is this necessary */
* Send receive request to EXOS.
* This routine is called by exinit and excdint,
* with interrupts disabled in both cases.
register struct ex_softc
*xs
= &ex_softc
[unit
];
register struct ex_msg
*bp
= exgetcbuf(xs
);
struct exdevice
*addr
= (struct exdevice
*)exinfo
[unit
]->ui_addr
;
bp
->mb_er
.er_blks
[0].bb_len
= EXMAXRBUF
;
*(u_long
*)bp
->mb_er
.er_blks
[0].bb_addr
=
UNIADDR(xs
->xs_ifuba
.ifu_r
.ifrw_info
);
bp
->mb_status
|= MH_EXOS
;
addr
->xd_portb
= EX_NTRUPT
;
* Ethernet output routine.
* Encapsulate a packet of type family for the local net.
* Use trailer local net encapsulation if enough data in first
* packet leaves a multiple of 512 bytes of data in remainder.
register struct ifnet
*ifp
;
register struct mbuf
*m0
;
register struct ex_softc
*xs
= &ex_softc
[ifp
->if_unit
];
register struct mbuf
*m
= m0
;
register struct ether_header
*eh
;
if ((ifp
->if_flags
& (IFF_UP
|IFF_RUNNING
)) != (IFF_UP
|IFF_RUNNING
)) {
switch (dst
->sa_family
) {
idst
= ((struct sockaddr_in
*)dst
)->sin_addr
;
if (!arpresolve(&xs
->xs_ac
, m
, &idst
, edst
, &usetrailers
))
return (0); /* if not yet resolved */
off
= ntohs((u_short
)mtod(m
, struct ip
*)->ip_len
) - m
->m_len
;
if (usetrailers
&& off
> 0 && (off
& 0x1ff) == 0 &&
m
->m_off
>= MMINOFF
+ 2 * sizeof (u_short
)) {
type
= ETHERTYPE_TRAIL
+ (off
>>9);
m
->m_off
-= 2 * sizeof (u_short
);
m
->m_len
+= 2 * sizeof (u_short
);
*mtod(m
, u_short
*) = htons((u_short
)ETHERTYPE_IP
);
*(mtod(m
, u_short
*) + 1) = htons((u_short
)m
->m_len
);
bcopy((caddr_t
)&(((struct sockaddr_ns
*)dst
)->sns_addr
.x_host
),
(caddr_t
)edst
, sizeof (edst
));
eh
= (struct ether_header
*)dst
->sa_data
;
bcopy((caddr_t
)eh
->ether_dhost
, (caddr_t
)edst
, sizeof (edst
));
printf("ex%d: can't handle af%d\n", ifp
->if_unit
,
* Packet to be sent as trailer: move first packet
* (control information) to end of chain.
* Add local net header. If no space in first mbuf,
if (m
->m_off
> MMAXOFF
||
MMINOFF
+ sizeof (struct ether_header
) > m
->m_off
) {
m
= m_get(M_DONTWAIT
, MT_HEADER
);
m
->m_len
= sizeof (struct ether_header
);
m
->m_off
-= sizeof (struct ether_header
);
m
->m_len
+= sizeof (struct ether_header
);
eh
= mtod(m
, struct ether_header
*);
eh
->ether_type
= htons((u_short
)type
);
bcopy((caddr_t
)edst
, (caddr_t
)eh
->ether_dhost
, sizeof (edst
));
bcopy((caddr_t
)xs
->xs_addr
, (caddr_t
)eh
->ether_shost
, 6);
* Queue message on interface, and start output if interface
if (IF_QFULL(&ifp
->if_snd
)) {
IF_ENQUEUE(&ifp
->if_snd
, m
);
* If transmit request not already pending, then
if ((xs
->xs_flags
& EX_XPENDING
) == 0) {
* Watchdog routine - place stats request to EXOS
* (This could be dispensed with, if you don't care
* about the if_ierrors count, or are willing to receive
* bad packets in order to derive it.)
struct uba_device
*ui
= exinfo
[unit
];
struct exdevice
*addr
= (struct exdevice
*)ui
->ui_addr
;
register struct ex_softc
*xs
= &ex_softc
[unit
];
register struct ex_msg
*bp
;
if (xs
->xs_flags
& EX_STATPENDING
) goto exspnd
;
xs
->xs_flags
|= EX_STATPENDING
;
bp
->mb_rqst
= LLNET_STSTCS
;
bp
->mb_ns
.ns_mask
= READ_OBJ
;
bp
->mb_ns
.ns_nobj
= 8; /* read all 8 stats objects */
bp
->mb_ns
.ns_xobj
= 0; /* starting with the 1st one */
bp
->mb_ns
.ns_bufp
= P_UNIADDR(xs
->xs_ubaddr
) + SA_OFFSET(unit
);
bp
->mb_status
|= MH_EXOS
;
addr
->xd_portb
= EX_NTRUPT
;
xs
->xs_if
.if_timer
= EXWATCHINTVL
;
* Process an ioctl request.
register struct ifnet
*ifp
;
register struct ifaddr
*ifa
= (struct ifaddr
*)data
;
register struct ex_softc
*xs
= &ex_softc
[ifp
->if_unit
];
int s
= splimp(), error
= 0;
switch (ifa
->ifa_addr
.sa_family
) {
((struct arpcom
*)ifp
)->ac_ipaddr
=
arpwhohas((struct arpcom
*)ifp
, &IA_SIN(ifa
)->sin_addr
);
register struct ns_addr
*ina
= &(IA_SNS(ifa
)->sns_addr
);
ina
->x_host
= *(union ns_host
*)(xs
->xs_addr
);
ex_setaddr(ina
->x_host
.c_host
,ifp
->if_unit
);
if ((ifp
->if_flags
& IFF_UP
) == 0 &&
xs
->xs_flags
& EX_RUNNING
) {
(exinfo
[ifp
->if_unit
]->ui_addr
))->xd_porta
= EX_RESET
;
xs
->xs_flags
&= ~EX_RUNNING
;
} else if (ifp
->if_flags
& IFF_UP
&&
(xs
->xs_flags
& EX_RUNNING
) == 0)
* set ethernet address for unit
ex_setaddr(physaddr
, unit
)
register struct ex_softc
*xs
= &ex_softc
[unit
];
struct uba_device
*ui
= exinfo
[unit
];
register struct exdevice
*addr
= (struct exdevice
*)ui
->ui_addr
;
register struct ex_msg
*bp
;
xs
->xs_flags
|= EX_SETADDR
;
bcopy((caddr_t
)physaddr
, (caddr_t
)xs
->xs_addr
, 6);
if (! (xs
->xs_flags
& EX_RUNNING
))
bp
->mb_rqst
= LLNET_ADDRS
;
bp
->mb_na
.na_mask
= READ_OBJ
|WRITE_OBJ
;
bp
->mb_na
.na_slot
= PHYSSLOT
;
bcopy((caddr_t
)xs
->xs_addr
, (caddr_t
)bp
->mb_na
.na_addrs
, 6);
bp
->mb_status
|= MH_EXOS
;
addr
->xd_portb
= EX_NTRUPT
;
while ((bp
->mb_status
& MH_OWNER
) == MH_EXOS
) /* poll for reply */
log(LOG_DEBUG
, "ex%d: reset addr %s\n", ui
->ui_unit
,
ether_sprintf(bp
->mb_na
.na_addrs
));
* Now, re-enable reception on phys slot.
bp
->mb_rqst
= LLNET_RECV
;
bp
->mb_nr
.nr_mask
= ENABLE_RCV
|READ_OBJ
|WRITE_OBJ
;
bp
->mb_nr
.nr_slot
= PHYSSLOT
;
bp
->mb_status
|= MH_EXOS
;
addr
->xd_portb
= EX_NTRUPT
;
while ((bp
->mb_status
& MH_OWNER
) == MH_EXOS
) /* poll for reply */