* Copyright (c) 1988 Regents of the University of California.
* 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_dmv.c 7.7 (Berkeley) 10/22/88
* Qbus Sync DDCMP interface - DMV operated in full duplex, point to point mode
* Written by Bob Kridle of Mt Xinu
* starting from if_dmc.c version 6.12 dated 4/23/86
#include "ioctl.h" /* must precede tty.h */
#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 "../vaxuba/ubareg.h"
#include "../vaxuba/ubavar.h"
int dmv_timeout
= 8; /* timeout value */
* Driver information for auto-configuration stuff.
int dmvprobe(), dmvattach(), dmvinit(), dmvioctl();
int dmvoutput(), dmvreset(), dmvtimeout();
struct uba_device
*dmvinfo
[NDMV
];
u_short dmvstd
[] = { 0 };
struct uba_driver dmvdriver
=
{ dmvprobe
, 0, dmvattach
, 0, dmvstd
, "dmv", dmvinfo
};
* Don't really know how many buffers/commands can be queued to a DMV-11.
* Manual doesn't say... Perhaps we can look at a DEC driver some day.
* These numbers ame from DMC/DMR driver.
#define NCMDS (NRCV+NXMT+4) /* size of command queue */
#define printd(f) if (sc->sc_if.if_flags & IFF_DEBUG) \
printf("DMVDEBUG: dmv%d: ", unit), printf(f)
#define printd(f) /* nil */
/* error reporting intervals */
/* number of errors to accept before trying a reset */
u_char qp_mask
; /* Which registers to set up */
struct dmv_command
*qp_next
; /* next command on queue */
#define qp_lowbufaddr qp_
int ubinfo
; /* from uballoc */
short cc
; /* buffer size */
short flags
; /* access control */
#define DBUF_OURS 0 /* buffer is available */
#define DBUF_DMVS 1 /* buffer claimed by somebody */
#define DBUF_XMIT 4 /* transmit buffer */
#define DBUF_RCV 8 /* receive buffer */
* DMV software status per interface.
* Each interface is referenced by a network interface structure,
* sc_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 set of 7 UBA interface structures
* contain 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 ifnet sc_if
; /* network-visible interface */
short sc_oused
; /* output buffers currently in use */
short sc_iused
; /* input buffers given to DMV */
short sc_flag
; /* flags */
short sc_ipl
; /* interrupt priority */
int sc_ubinfo
; /* UBA mapping info for base table */
int sc_errors
[8]; /* error counters */
#define sc_rte sc_errors[0] /* receive threshhold error */
#define sc_xte sc_errors[1] /* xmit threshhold error */
#define sc_ste sc_errors[2] /* select threshhold error */
#define sc_nxm sc_errors[3] /* non-existant memory */
#define sc_modd sc_errors[4] /* modem disconnect */
#define sc_qovf sc_errors[5] /* command/response queue overflow */
#define sc_cxrl sc_errors[6] /* carrier loss */
#define sc_unknown sc_errors[7] /* other errors - look in DMV manual */
struct dmvbufs sc_rbufs
[NRCV
]; /* receive buffer info */
struct dmvbufs sc_xbufs
[NXMT
]; /* transmit buffer info */
struct ifubinfo sc_ifuba
; /* UNIBUS resources */
struct ifrw sc_ifr
[NRCV
]; /* UNIBUS receive buffer maps */
struct ifxmt sc_ifw
[NXMT
]; /* UNIBUS receive buffer maps */
/* command queue stuff */
struct dmv_command sc_cmdbuf
[NCMDS
];
struct dmv_command
*sc_qhead
; /* head of command queue */
struct dmv_command
*sc_qtail
; /* tail of command queue */
struct dmv_command
*sc_qactive
; /* command in progress */
struct dmv_command
*sc_qfreeh
; /* head of list of free cmd buffers */
struct dmv_command
*sc_qfreet
; /* tail of list of free cmd buffers */
/* end command queue stuff */
#define DMV_RESTART 0x01 /* software restart in progress */
#define DMV_ONLINE 0x02 /* device managed to transmit */
#define DMV_RUNNING 0x04 /* device initialized */
/* queue manipulation macros */
#define QUEUE_AT_HEAD(qp, head, tail) \
(qp)->qp_next = (head); \
if ((tail) == (struct dmv_command *) 0) \
#define QUEUE_AT_TAIL(qp, head, tail) \
(tail)->qp_next = (qp); \
(qp)->qp_next = (struct dmv_command *) 0; \
#define DEQUEUE(head, tail) \
(head) = (head)->qp_next;\
if ((head) == (struct dmv_command *) 0)\
register struct dmvdevice
*addr
= (struct dmvdevice
*)reg
;
br
= 0; cvec
= br
; br
= cvec
;
for (i
= 100000; i
&& (addr
->bsel1
& DMV_RUN
) == 0; i
--)
if ((addr
->bsel1
& DMV_RUN
) == 0) {
printf("dmvprobe: can't start device\n" );
if ((addr
->bsel4
!= 033) || (addr
->bsel6
!= 0305))
printf("dmvprobe: device init failed, bsel4=%o, bsel6=%o\n",
addr
->bsel4
, addr
->bsel6
);
addr
->bsel0
= DMV_RQI
|DMV_IEI
|DMV_IEO
;
for (i
= 100000; i
&& (addr
->bsel1
& DMV_RUN
) == 0; i
--)
dmv_softc
[ui
->ui_unit
].sc_ipl
= br
= qbgetpri();
return (sizeof(struct dmvdevice
));
* Interface exists: make available by filling in network interface
* record. System will initialize the interface when it is ready
register struct uba_device
*ui
;
register struct dmv_softc
*sc
= &dmv_softc
[ui
->ui_unit
];
sc
->sc_if
.if_unit
= ui
->ui_unit
;
sc
->sc_if
.if_name
= "dmv";
sc
->sc_if
.if_mtu
= DMVMTU
;
sc
->sc_if
.if_init
= dmvinit
;
sc
->sc_if
.if_output
= dmvoutput
;
sc
->sc_if
.if_ioctl
= dmvioctl
;
sc
->sc_if
.if_reset
= dmvreset
;
sc
->sc_if
.if_watchdog
= dmvtimeout
;
sc
->sc_if
.if_flags
= IFF_POINTOPOINT
;
sc
->sc_ifuba
.iff_flags
= UBA_CANTWAIT
;
* Reset of interface after UNIBUS reset.
* If interface is on specified UBA, reset its state.
register struct uba_device
*ui
;
register struct dmv_softc
*sc
= &dmv_softc
[unit
];
if (unit
>= NDMV
|| (ui
= dmvinfo
[unit
]) == 0 || ui
->ui_alive
== 0 ||
sc
->sc_if
.if_flags
&= ~IFF_RUNNING
;
* Initialization of interface; reinitialize UNIBUS usage.
register struct dmv_softc
*sc
= &dmv_softc
[unit
];
register struct uba_device
*ui
= dmvinfo
[unit
];
register struct dmvdevice
*addr
;
register struct ifnet
*ifp
= &sc
->sc_if
;
register struct ifrw
*ifrw
;
register struct ifxmt
*ifxp
;
register struct dmvbufs
*rp
;
register struct dmv_command
*qp
;
addr
= (struct dmvdevice
*)ui
->ui_addr
;
* Check to see that an address has been set
* (both local and destination for an address family).
for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
)
if (ifa
->ifa_addr
.sa_family
&& ifa
->ifa_dstaddr
.sa_family
)
if (ifa
== (struct ifaddr
*) 0)
if ((addr
->bsel1
&DMV_RUN
) == 0) {
log(LOG_CRIT
, "dmvinit: dmv%d not running\n", unit
);
ifp
->if_flags
&= ~IFF_UP
;
/* initialize UNIBUS resources */
sc
->sc_iused
= sc
->sc_oused
= 0;
if ((ifp
->if_flags
& IFF_RUNNING
) == 0) {
sizeof(struct dmv_header
),
log(LOG_CRIT
, "dmvinit: dmv%d can't allocate uba resources\n", unit
);
ifp
->if_flags
&= ~IFF_UP
;
ifp
->if_flags
|= IFF_RUNNING
;
* Limit packets enqueued until we see if we're on the air.
ifp
->if_snd
.ifq_maxlen
= 3;
/* initialize buffer pool */
for (rp
= &sc
->sc_rbufs
[0]; rp
< &sc
->sc_rbufs
[NRCV
]; rp
++) {
rp
->ubinfo
= UBAI_ADDR(ifrw
->ifrw_info
);
rp
->cc
= DMVMTU
+ sizeof (struct dmv_header
);
rp
->flags
= DBUF_OURS
|DBUF_RCV
;
for (rp
= &sc
->sc_xbufs
[0]; rp
< &sc
->sc_xbufs
[NXMT
]; rp
++) {
rp
->ubinfo
= UBAI_ADDR(ifxp
->ifw_info
);
rp
->flags
= DBUF_OURS
|DBUF_XMIT
;
/* set up command queues */
sc
->sc_qfreeh
= sc
->sc_qfreet
= sc
->sc_qhead
= sc
->sc_qtail
= sc
->sc_qactive
=
/* set up free command buffer list */
for (qp
= &sc
->sc_cmdbuf
[0]; qp
< &sc
->sc_cmdbuf
[NCMDS
]; qp
++) {
QUEUE_AT_HEAD(qp
, sc
->sc_qfreeh
, sc
->sc_qfreet
);
if(sc
->sc_flag
& DMV_RUNNING
)
dmvload( sc
, DMV_CNTRLI
, (QP_TRIB
|QP_SEL6
), 1, 0, DMV_REQHS
,0);
dmvload( sc
, DMV_CNTRLI
, (QP_TRIB
|QP_SEL6
), 1, 0, DMV_ESTTRIB
,0);
dmvload( sc
, DMV_CNTRLI
, (QP_TRIB
|QP_SEL6
), 1, 0, DMV_REQSUS
,0);
sc
->sc_flag
|= (DMV_RESTART
|DMV_RUNNING
);
sc
->sc_flag
&= ~DMV_ONLINE
;
* Start output on interface. Get another datagram
* to send from the interface queue and map it to
* the interface before starting output.
* Must be called at spl 5
register struct dmv_softc
*sc
= &dmv_softc
[unit
];
register struct dmvbufs
*rp
;
* Dequeue up to NXMT requests and map them to the UNIBUS.
* If no more requests, or no dmv buffers available, just return.
for (rp
= &sc
->sc_xbufs
[0]; rp
< &sc
->sc_xbufs
[NXMT
]; rp
++ ) {
/* find an available buffer */
if ((rp
->flags
& DBUF_DMVS
) == 0) {
IF_DEQUEUE(&sc
->sc_if
.if_snd
, m
);
rp
->flags
|= (DBUF_DMVS
);
* Have request mapped to UNIBUS for transmission
rp
->cc
= if_ubaput(&sc
->sc_ifuba
, &sc
->sc_ifw
[n
], m
);
sc
->sc_if
.if_timer
= dmv_timeout
;
QP_TRIB
|QP_SEL4
|QP_SEL6
|QP_SEL10
,
* Utility routine to load the DMV device registers.
dmvload(sc
, cmd
, mask
, tributary
, sel4
, sel6
, sel10
)
register struct dmv_softc
*sc
;
u_char cmd
, tributary
, mask
;
u_short sel4
, sel6
, sel10
;
register struct dmvdevice
*addr
;
register struct dmv_command
*qp
;
printd(("dmvload: cmd=%x mask=%x trib=%x sel4=%x sel6=%x sel10=%x\n",
addr
= (struct dmvdevice
*)dmvinfo
[unit
]->ui_addr
;
/* grab a command buffer from the free list */
if ((qp
= sc
->sc_qfreeh
) == (struct dmv_command
*)0)
panic("dmv command queue overflow");
DEQUEUE(sc
->sc_qfreeh
, sc
->sc_qfreet
);
/* fill in requested info */
qp
->qp_tributary
= tributary
;
if (sc
->sc_qactive
) { /* command in progress */
if (cmd
== DMV_BACCR
) { /* supply read buffers first */
QUEUE_AT_HEAD(qp
, sc
->sc_qhead
, sc
->sc_qtail
);
QUEUE_AT_TAIL(qp
, sc
->sc_qhead
, sc
->sc_qtail
);
} else { /* command port free */
addr
->bsel0
= (DMV_RQI
|DMV_IEI
|DMV_IEO
);
* DMV interface input interrupt.
* Ready to accept another command,
* pull one off the command queue.
register struct dmv_softc
*sc
;
register struct dmvdevice
*addr
;
register struct dmv_command
*qp
;
addr
= (struct dmvdevice
*)dmvinfo
[unit
]->ui_addr
;
if ((qp
= sc
->sc_qactive
) == (struct dmv_command
*) 0) {
log(LOG_WARNING
, "dmvrint: dmv%d no command\n", unit
);
while (addr
->bsel2
&DMV_RDI
) {
addr
->wsel4
= qp
->qp_sel4
;
addr
->wsel6
= qp
->qp_sel6
;
if(qp
->qp_mask
&QP_SEL10
) {
addr
->wsel10
= qp
->qp_sel10
;
addr
->wsel2
= qp
->qp_cmd
|(qp
->qp_tributary
<< 8);
addr
->bsel2
= qp
->qp_cmd
;
QUEUE_AT_HEAD(qp
, sc
->sc_qfreeh
, sc
->sc_qfreet
);
if ((sc
->sc_qactive
= sc
->sc_qhead
) == (struct dmv_command
*)0)
DEQUEUE(sc
->sc_qhead
, sc
->sc_qtail
);
if(addr
->bsel2
&DMV_RDI
) {
/* clear RQI prior to last command per DMV manual */
addr
->bsel2
= DMV_CNTRLI
;
else /* RDO set or DMV still holding CSR */
addr
->bsel0
= (DMV_RQI
|DMV_IEI
|DMV_IEO
);
* DMV interface output interrupt.
* A transfer may have completed, check for errors.
* If it was a read, notify appropriate protocol.
* If it was a write, pull the next one off the queue.
register struct dmv_softc
*sc
;
register struct ifnet
*ifp
;
struct uba_device
*ui
= dmvinfo
[unit
];
int sel2
, sel3
, sel4
, sel6
, sel10
, pkaddr
, len
, s
;
register struct ifrw
*ifrw
;
register struct dmvbufs
*rp
;
register struct ifxmt
*ifxp
;
addr
= (struct dmvdevice
*)ui
->ui_addr
;
while (addr
->bsel2
& DMV_RDO
) {
sel4
= addr
->wsel4
; /* release port */
pkaddr
= sel4
| ((sel6
& 0x3f) << 16);
printd(("dmvxint: sel2=%x sel4=%x sel6=%x sel10=%x pkaddr=%x\n",
if((sc
->sc_flag
& DMV_RUNNING
)==0) {
log(LOG_WARNING
, "dmvxint: dmv%d xint while down\n", unit
);
* Pass packet to type specific
* higher-level input routine.
/* find location in dmvuba struct */
for (rp
= &sc
->sc_rbufs
[0]; rp
< &sc
->sc_rbufs
[NRCV
]; rp
++) {
if (rp
>= &sc
->sc_rbufs
[NRCV
])
if ((rp
->flags
& DBUF_DMVS
) == 0)
log(LOG_WARNING
, "dmvxint: dmv%d done unalloc rbuf\n", unit
);
len
= (sel10
&0x3fff) - sizeof (struct dmv_header
);
if (len
< 0 || len
> DMVMTU
) {
log(LOG_ERR
, "dmvxint: dmv%d bad rcv pkt addr 0x%x len 0x%x\n",
* 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.
dh
= (struct dmv_header
*)ifrw
->ifrw_addr
;
dh
->dmv_type
= ntohs((u_short
)dh
->dmv_type
);
#define dmvdataaddr(dh, off, type) ((type)(((caddr_t)((dh)+1)+(off))))
if (dh
->dmv_type
>= DMV_TRAILER
&&
dh
->dmv_type
< DMV_TRAILER
+DMV_NTRAILER
) {
off
= (dh
->dmv_type
- DMV_TRAILER
) * 512;
dh
->dmv_type
= ntohs(*dmvdataaddr(dh
, off
, u_short
*));
resid
= ntohs(*(dmvdataaddr(dh
, off
+2, u_short
*)));
* Pull packet off interface. Off is nonzero if
* packet has trailing header; dmv_get 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_ubaget(&sc
->sc_ifuba
, ifrw
, len
, off
, ifp
);
ifp
= *(mtod(m
, struct ifnet
**));
m
->m_off
+= 2 * sizeof (u_short
);
m
->m_len
-= 2 * sizeof (u_short
);
*(mtod(m
, struct ifnet
**)) = ifp
;
rp
->ubinfo
= UBAI_ADDR(ifrw
->ifrw_info
);
QP_SEL4
|QP_SEL6
|QP_SEL10
,
* A write has completed, start another
* transfer if there is more data to send.
/* find associated dmvbuf structure */
for (rp
= &sc
->sc_xbufs
[0]; rp
< &sc
->sc_xbufs
[NXMT
]; rp
++) {
if (rp
>= &sc
->sc_xbufs
[NXMT
]) {
log(LOG_ERR
, "dmv%d: bad packet address 0x%x\n",
if ((rp
->flags
& DBUF_DMVS
) == 0)
log(LOG_ERR
, "dmvxint: dmv%d unallocated packet 0x%x\n",
(void)m_freem(ifxp
->ifw_xtofree
);
sc
->sc_if
.if_timer
= dmv_timeout
;
if ((sc
->sc_flag
& DMV_ONLINE
) == 0) {
* Open the queue to the usual value.
sc
->sc_flag
|= DMV_ONLINE
;
ifp
->if_snd
.ifq_maxlen
= ifqmaxlen
;
/* ACCUMULATE STATISTICS */
if(sc
->sc_flag
& DMV_RESTART
) {
sc
->sc_flag
&= ~DMV_RESTART
;
"dmv%d: far end on-line\n", unit
);
"dmv%d: far end restart\n", unit
);
if ((sc
->sc_rte
++ % DMV_RPRTE
) == 0)
"dmv%d: receive threshold error\n",
if ((sc
->sc_xte
++ % DMV_RPTTE
) == 0)
"dmv%d: transmit threshold error\n",
if ((sc
->sc_ste
++ % DMV_RPSTE
) == 0)
"dmv%d: select threshold error\n",
if ((sc
->sc_nxm
++ % DMV_RPNXM
) == 0)
"dmv%d: nonexistent memory error\n",
if ((sc
->sc_modd
++ % DMV_RPMODD
) == 0) {
"dmv%d: modem disconnected error\n",
if ((sc
->sc_cxrl
++ % DMV_RPCXRL
) == 0)
"dmv%d: carrier loss error\n",
"dmv%d: response queue overflow\n",
"dmv%d: unknown error %o\n",
if ((sc
->sc_unknown
++ % DMV_RPUNKNOWN
) == 0)
"dmv%d: buffer disp for halted trib %o\n",
"dmv%d: buffer return complete sel3=%x\n",
"dmv%d: info resp sel3=%x sel4=%x sel6=%x\n",
log(LOG_WARNING
, "dmv%d: bad control %o\n",
register struct dmv_softc
*sc
;
register struct dmvbufs
*rp
;
/* queue first NRCV buffers for DMV to fill */
for (rp
= &sc
->sc_rbufs
[0]; rp
< &sc
->sc_rbufs
[NRCV
]; rp
++) {
QP_TRIB
|QP_SEL4
|QP_SEL6
|QP_SEL10
,
* Encapsulate a packet of type family for the dmv.
* 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 mbuf
*m
= m0
;
register struct dmv_header
*dh
;
if ((ifp
->if_flags
& IFF_UP
) == 0) {
switch (dst
->sa_family
) {
off
= ntohs((u_short
)mtod(m
, struct ip
*)->ip_len
) - m
->m_len
;
if ((ifp
->if_flags
& IFF_NOTRAILERS
) == 0)
if (off
> 0 && (off
& 0x1ff) == 0 &&
m
->m_off
>= MMINOFF
+ 2 * sizeof (u_short
)) {
type
= DMV_TRAILER
+ (off
>>9);
m
->m_off
-= 2 * sizeof (u_short
);
m
->m_len
+= 2 * sizeof (u_short
);
*mtod(m
, u_short
*) = htons((u_short
)DMV_IPTYPE
);
*(mtod(m
, u_short
*) + 1) = htons((u_short
)m
->m_len
);
dh
= (struct dmv_header
*)dst
->sa_data
;
log(LOG_ERR
, "dmvoutput, dmv%d can't handle af%d\n",
ifp
->if_unit
, dst
->sa_family
);
* Packet to be sent as a trailer; move first packet
* (control information) to end of chain.
* Add local network header
* (there is space for a uba on a vax to step on)
if (m
->m_off
> MMAXOFF
||
MMINOFF
+ sizeof(struct dmv_header
) > m
->m_off
) {
m
= m_get(M_DONTWAIT
, MT_HEADER
);
m
->m_len
= sizeof (struct dmv_header
);
m
->m_off
-= sizeof (struct dmv_header
);
m
->m_len
+= sizeof (struct dmv_header
);
dh
= mtod(m
, struct dmv_header
*);
dh
->dmv_type
= htons((u_short
)type
);
* Queue message on interface, and start output if interface
if (IF_QFULL(&ifp
->if_snd
)) {
IF_ENQUEUE(&ifp
->if_snd
, m
);
* Process an ioctl request.
register struct ifnet
*ifp
;
int s
= splimp(), error
= 0;
register struct dmv_softc
*sc
= &dmv_softc
[ifp
->if_unit
];
if ((ifp
->if_flags
& IFF_RUNNING
) == 0)
if ((ifp
->if_flags
& IFF_RUNNING
) == 0)
if ((ifp
->if_flags
& IFF_UP
) == 0 &&
sc
->sc_flag
& DMV_RUNNING
)
else if (ifp
->if_flags
& IFF_UP
&&
(sc
->sc_flag
& DMV_RUNNING
) == 0)
dmvrestart(ifp
->if_unit
);
* Restart after a fatal error.
* Clear device and reinitialize.
register struct dmvdevice
*addr
;
addr
= (struct dmvdevice
*)(dmvinfo
[unit
]->ui_addr
);
* Let the DMV finish the MCLR.
for (i
= 100000; i
&& (addr
->bsel1
& DMV_RUN
) == 0; i
--)
if ((addr
->bsel1
& DMV_RUN
) == 0) {
log(LOG_ERR
, "dmvrestart: can't start device\n" );
if ((addr
->bsel4
!= 033) || (addr
->bsel6
!= 0305))
log(LOG_ERR
, "dmv%d: device init failed, bsel4=%o, bsel6=%o\n",
unit
, addr
->bsel4
, addr
->bsel6
);
dmv_softc
[unit
].sc_if
.if_collisions
++; /* why not? */
* Reset a device and mark down.
* Flush output queue and drop queue limit.
struct dmv_softc
*sc
= &dmv_softc
[unit
];
register struct ifxmt
*ifxp
;
((struct dmvdevice
*)(dmvinfo
[unit
]->ui_addr
))->bsel1
= DMV_MCLR
;
sc
->sc_flag
&= ~(DMV_RUNNING
| DMV_ONLINE
);
for (ifxp
= sc
->sc_ifw
; ifxp
< &sc
->sc_ifw
[NXMT
]; ifxp
++) {
(void) m_freem(ifxp
->ifw_xtofree
);
if_qflush(&sc
->sc_if
.if_snd
);
* Limit packets enqueued until we're back on the air.
sc
->sc_if
.if_snd
.ifq_maxlen
= 3;
* Watchdog timeout to see that transmitted packets don't
* lose interrupts. The device has to be online.
register struct dmv_softc
*sc
;
if (sc
->sc_flag
& DMV_ONLINE
) {
addr
= (struct dmvdevice
*)(dmvinfo
[unit
]->ui_addr
);
log(LOG_ERR
, "dmv%d: output timeout, bsel0=%b bsel2=%b\n",
unit
, addr
->bsel0
& 0xff, DMV0BITS
,
addr
->bsel2
& 0xff, DMV2BITS
);