* Copyright (c) 1990 Regents of the University of California.
* %sccs.include.redist.c%
* @(#)if_dp.c 7.2 (Berkeley) %G%
* DPV-11 device driver, X.25 version
* Derived from dmc-11 driver:
/* #define DEBUG /* for base table dump on fatal error */
#include "ioctl.h" /* must precede tty.h */
#include "../net/netisr.h"
#include "../net/route.h"
#include "../vaxuba/pdma.h"
#include "../vaxuba/ubavar.h"
#include "../netcitt/x25.h"
* Driver information for auto-configuration stuff.
int dpprobe(), dpattach(), dpinit(), dpioctl(), dprint(), dpxint();
int dpoutput(), dpreset(), dptimeout(), dpstart(), x25_ifoutput();
struct uba_device
*dpinfo
[NDP
];
struct uba_driver dpdriver
=
{ dpprobe
, 0, dpattach
, 0, dpstd
, "dp", dpinfo
};
* Pdma structures for fast interrupts.
struct pdma dppdma
[2*NDP
];
/* error reporting intervals */
* DP software status per interface.
* Each interface is referenced by a network interface structure,
* dp_if, which the routing code uses to locate the interface.
* This structure contains the output queue for the interface, its address, ...
struct ifnet dp_if
; /* network-visible interface */
short dp_iused
; /* input buffers given to DP */
short dp_flags
; /* flags */
short dp_ostate
; /* restarting, etc. */
short dp_istate
; /* not sure this is necessary */
#define DPS_XEM 3 /* transmitting CRC, etc. */
#define DPF_RUNNING 0x01 /* device initialized */
#define DPF_ONLINE 0x02 /* device running (had a RDYO) */
#define DPF_RESTART 0x04 /* software restart in progress */
#define DPF_FLUSH 0x08 /* had a ROVR, flush ipkt when done */
int dp_errors
[4]; /* non-fatal error counters */
#define dp_datck dp_errors[0]
#define dp_timeo dp_errors[1]
#define dp_nobuf dp_errors[2]
#define dp_disc dp_errors[3]
register struct dpdevice
*addr
= (struct dpdevice
*)reg
;
br
= 0; cvec
= br
; br
= cvec
;
addr
->dpclr
= DP_XIE
|DP_XE
;
* 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 dp_softc
*dp
= &dp_softc
[ui
->ui_unit
];
register struct pdma
*pdp
= &dppdma
[ui
->ui_unit
*2];
dp
->dp_if
.if_unit
= ui
->ui_unit
;
dp
->dp_if
.if_name
= "dp";
dp
->dp_if
.if_mtu
= DP_MTU
;
dp
->dp_if
.if_init
= dpinit
;
dp
->dp_if
.if_output
= x25_ifoutput
;
dp
->dp_if
.if_start
= dpstart
;
dp
->dp_if
.if_ioctl
= dpioctl
;
dp
->dp_if
.if_reset
= dpreset
;
dp
->dp_if
.if_watchdog
= dptimeout
;
dp
->dp_if
.if_flags
= IFF_POINTOPOINT
;
pdp
->p_addr
= (struct dzdevice
*)ui
->ui_addr
;
pdp
->p_mem
= pdp
->p_end
= dp
->dp_obuf
;
pdp
->p_addr
= (struct dzdevice
*)ui
->ui_addr
;
pdp
->p_mem
= pdp
->p_end
= dp
->dp_ibuf
;
* Reset of interface after UNIBUS reset.
* If interface is on specified UBA, reset its state.
register struct uba_device
*ui
;
register struct dp_softc
*dp
= &dp_softc
[unit
];
register struct dpdevice
*addr
;
if (unit
>= NDP
|| (ui
= dpinfo
[unit
]) == 0 || ui
->ui_alive
== 0 ||
dp
->dp_if
.if_flags
&= ~IFF_RUNNING
;
addr
= (struct dpdevice
*)ui
->ui_addr
;
* Initialization of interface.
register struct dp_softc
*dp
= &dp_softc
[unit
];
register struct uba_device
*ui
= dpinfo
[unit
];
register struct dpdevice
*addr
;
register struct ifnet
*ifp
= &dp
->dp_if
;
addr
= (struct dpdevice
*)ui
->ui_addr
;
* Check to see that an address has been set.
for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
)
if (ifa
->ifa_addr
->sa_family
!= AF_LINK
)
if (ifa
== (struct ifaddr
*) 0)
dp
->dp_istate
= dp
->dp_ostate
= DPS_IDLE
;
dppdma
[2*unit
+1].p_mem
= dp
->dp_ibuf
;
/* enable receive interrupt; CTS comming up will trigger it also */
addr
->dpsar
= DP_CHRM
| 0x7E; /* 7E is the flag character */
addr
->dprcsr
= DP_RIE
| DP_DTR
| DP_RE
;
* Start output on interface. Get another datagram
* to send from the interface queue and map it to
* the interface before starting output.
int s
, unit
= ifp
->if_unit
;
register struct dp_softc
*dp
= &dp_softc
[unit
];
register struct dpdevice
*addr
=
(struct dpdevice
*)(dpinfo
[unit
]->ui_addr
);
* If already doing output, go away and depend on transmit
if (dp
->dp_if
.if_flags
& IFF_OACTIVE
) {
IF_DEQUEUE(&dp
->dp_if
.if_snd
, m
);
if ((m
->m_flags
| M_PKTHDR
) == 0 || m
->m_pkthdr
.len
> DP_MTU
)
dppdma
[2*unit
].p_mem
= cp
= dp
->dp_obuf
;
bcopy(mtod(m
, caddr_t
), (caddr_t
)cp
, m
->m_len
);
dppdma
[2*unit
].p_end
= cp
;
addr
->dpclr
= DP_XE
| DP_XIE
;
dp
->dp_if
.if_flags
|= IFF_OACTIVE
;
dp
->dp_ostate
= DPS_ACTIVE
;
* Receive done or error interrupt
register struct pdma
*pdma
;
register struct dpdevice
*addr
;
register struct dp_softc
*dp
= &dp_softc
[unit
];
short rdsr
= addr
->dprdsr
;
dp
->dp_flags
|= DPF_FLUSH
;
if (rdsr
& DP_RSM
) { /* Received Start of Message */
dp
->dp_ibuf
[0] = rdsr
& DP_RBUF
;
pdma
->p_mem
= dp
->dp_ibuf
+ 1;
dp
->dp_flags
&= ~DPF_FLUSH
;
if (rdsr
& DP_REM
) { /* Received End of Message */
if (rdsr
& DP_REC
|| dp
->dp_flags
& DPF_FLUSH
) {
pdma
->p_mem
= dp
->dp_ibuf
;
dp
->dp_flags
&= ~ DPF_FLUSH
;
dpinput(dp
, pdma
->p_mem
- dp
->dp_ibuf
, dp
->dp_ibuf
);
dp
->dp_flags
|= DPF_FLUSH
;
if (pdma
->p_mem
!= pdma
->p_end
)
log("dp%d: unexplained receiver interrupt\n", unit
);
* Transmit complete or error interrupt
register struct pdma
*pdma
;
register struct dpdevice
*addr
;
register struct dp_softc
*dp
= &dp_softc
[unit
];
if (addr
->dptdsr
& DP_XERR
) {
log("if_dp%d: data late\n", unit
);
pdma
->p_mem
= dp
->dp_obuf
;
if (pdma
->p_mem
!= pdma
->p_end
) {
log("if_dp%d: misc error in dpxint\n");
dp
->dp_if
.if_flags
&= ~IFF_OACTIVE
;
if (dp
->dp_if
.if_snd
.ifq_len
)
dp
->dp_ostate
= DPS_IDLE
;
log("if_dp%d: impossible state in dpxint\n");
* Routine to copy from device buffer into mbufs.
* Warning: This makes the fairly safe assumption that
* mbufs have even lengths.
dpget(rxbuf
, totlen
, off
, ifp
)
struct mbuf
*top
= 0, **mp
= &top
;
packet_end
= cp
+ totlen
;
off
+= 2 * sizeof(u_short
);
totlen
-= 2 *sizeof(u_short
);
MGETHDR(m
, M_DONTWAIT
, MT_DATA
);
m
->m_pkthdr
.len
= totlen
;
MGET(m
, M_DONTWAIT
, MT_DATA
);
len
= min(totlen
, (packet_end
- cp
));
m
->m_len
= len
= min(len
, MCLBYTES
);
* Place initial small packet/header at end of mbuf.
if (top
== 0 && len
+ max_linkhdr
<= m
->m_len
)
m
->m_data
+= max_linkhdr
;
bcopy(cp
, mtod(m
, caddr_t
), (u_int
)len
);
register struct dp_softc
*dp
;
register struct ifnet
*ifp
= &dp
->dp_if
;
register struct ifqueue
*inq
;
extern struct ifqueue hdintrq
;
if(len
<= 0 || ifp
->if_addrlist
== 0)
m
= dpget(buffer
, len
, 0, ifp
);
/* Only AF_CCITT makes sense at this point */
schednetisr(NETISR_CCITT
);
* Process an ioctl request.
register struct ifnet
*ifp
;
register struct ifaddr
*ifa
= (struct ifaddr
*)data
;
int s
= splimp(), error
= 0;
struct dp_softc
*dp
= &dp_softc
[ifp
->if_unit
];
switch (ifa
->ifa_addr
->sa_family
) {
error
= hd_ctlinput(PRC_IFUP
, (caddr_t
)&ifa
->ifa_addr
);
if ((ifp
->if_flags
& IFF_UP
) == 0 &&
(dp
->dp_flags
& DPF_RUNNING
))
else if (ifp
->if_flags
& IFF_UP
&&
(dp
->dp_flags
& DPF_RUNNING
) == 0)
/* case SIOCSIFFLAGS: ... */
* Reset a device and mark down.
* Flush output queue and drop queue limit.
register struct dp_softc
*dp
= &dp_softc
[unit
];
register struct ifxmt
*ifxp
;
register struct dpdevice
*addr
= (struct dpdevice
*)dpinfo
[unit
]->ui_addr
;
dp
->dp_flags
&= ~(DPF_RUNNING
| DPF_ONLINE
);
if_qflush(&dp
->dp_if
.if_snd
);
* Watchdog timeout to see that transmitted packets don't
* lose interrupts. The device has to be online (the first
* transmission may block until the other side comes up).
register struct dp_softc
*dp
;
if (dp
->dp_flags
& DPF_ONLINE
) {
addr
= (struct dpdevice
*)(dpinfo
[unit
]->ui_addr
);