* Copyright (c) 1990 Regents of the University of California.
* %sccs.include.redist.c%
* @(#)if_dp.c 7.3 (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"
#define dzdevice dpdevice
#include "../vaxuba/pdma.h"
#include "../vaxuba/ubavar.h"
#include "../netccitt/x25.h"
#include "../netccitt/pk.h"
#include "../netccitt/pk_var.h"
* Driver information for auto-configuration stuff.
int dpprobe(), dpattach(), dpinit(), dpioctl(), dprint(), dpxint();
int dpoutput(), dpreset(), dptimeout(), dpstart(), x25_ifoutput(), dptestoutput();
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 */
#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 */
short dp_ostate
; /* restarting, etc. */
short dp_istate
; /* not sure this is necessary */
#define DPS_XEM 3 /* transmitting CRC, etc. */
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]
struct timeval dp_xt
; /* start of last transmission */
register struct dpdevice
*addr
= (struct dpdevice
*)reg
;
br
= 0; cvec
= br
; br
= cvec
;
addr
->dpclr
= DP_XIE
|DP_XE
;
dp_softc
[ui
->ui_unit
].dp_ipl
= br
= qbgetpri();
if (cvec
&& cvec
!= 0x200){
* 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
];
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
;
* 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 ifaddr
*ifa
;
register struct pdma
*pdp
= &dppdma
[unit
*2];
* Check to see that an address has been set.
for (ifa
= dp
->dp_if
.if_addrlist
; ifa
; ifa
= ifa
->ifa_next
)
if (ifa
->ifa_addr
->sa_family
!= AF_LINK
)
if (ifa
== (struct ifaddr
*) 0)
addr
= (struct dpdevice
*)ui
->ui_addr
;
dp
->dp_istate
= dp
->dp_ostate
= DPS_IDLE
;
dp
->dp_if
.if_flags
|= IFF_RUNNING
;
dp
->dp_if
.if_flags
&= ~IFF_OACTIVE
;
pdp
->p_mem
= pdp
->p_end
= dp
->dp_obuf
;
/* force initial interrupt to come to dprint */
pdp
->p_mem
= pdp
->p_end
= dp
->dp_ibuf
+ DP_MTU
+ 8;
/* DP_ATA = 0, DP_CHRM = 0,
CRC = CCIIT, initially all ones, 2nd addr = 0 */
/* enable receive interrupt */
addr
->dprcsr
= DP_RIE
| DP_MIE
| DP_RE
| DP_DTR
| DP_RTS
;
* 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
, error
= 0, len
;
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
);
dp
->dp_if
.if_collisions
++;
if (m
->m_flags
& M_PKTHDR
)
for (len
= 0; m
; m
= m
->m_next
)
dppdma
[2*unit
].p_mem
= cp
+ 1;
bcopy(mtod(m
, caddr_t
), (caddr_t
)cp
, m
->m_len
);
dppdma
[2*unit
].p_end
= cp
;
printf("dp: len %d, start %x, end %x, first %x, next %x",
len
, dp
->dp_obuf
, cp
, *(int *)dp
->dp_obuf
,
dp
->dp_if
.if_flags
|= IFF_OACTIVE
;
dp
->dp_ostate
= DPS_ACTIVE
;
dp
->dp_if
.if_collisions
--;
addr
->dpclr
= DP_XE
| DP_XIE
;
addr
->dptdsr
= DP_XSM
| (0xff & dp
->dp_obuf
[0]);
* 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
, rcsr
;
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_ibuf
);
pdma
->p_mem
= pdma
->p_end
;
dp
->dp_flags
&= ~ DPF_FLUSH
;
dp
->dp_flags
|= DPF_FLUSH
;
if (0 == (rcsr
& DP_DSR
)) {
log(LOG_DEBUG
, "dp%d: lost modem\n", unit
);
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", unit
);
dp
->dp_if
.if_flags
&= ~IFF_OACTIVE
;
timevalsub(&dp_xt
, &dp
->dp_xt
);
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
);
dpinput(ifp
, len
, buffer
)
register struct ifnet
*ifp
;
register struct ifqueue
*inq
;
extern struct ifqueue hdintrq
, ipintrq
;
register struct ifaddr
*ifa
= ifp
->if_addrlist
;
register u_char
*cp
= (u_char
*)buffer
;
for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
)
if (ifa
->ifa_addr
->sa_family
!= AF_LINK
)
if (cp
[0] == 0xff && cp
[1] == 0x3) {
/* This is a UI HDLC Packet, so we'll assume PPP
protocol. for now, IP only. */
m
= dpget(buffer
, len
, 0, ifp
);
* 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
) {
ifp
->if_output
= dptestoutput
;
ifp
->if_output
= x25_ifoutput
;
error
= hd_ctlinput(PRC_IFUP
, ifa
->ifa_addr
);
if ((ifp
->if_flags
& IFF_UP
) == 0 &&
(ifp
->if_flags
& IFF_RUNNING
))
else if (ifp
->if_flags
& IFF_UP
&&
(ifp
->if_flags
& IFF_RUNNING
) == 0)
* Reset a device and mark down.
* Flush output queue and drop queue limit.
register struct dp_softc
*dp
= &dp_softc
[unit
];
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
;
/* currently not armed */
if (dp
->dp_if
.if_flags
& IFF_OACTIVE
) {
* For debugging loopback activity.
static char pppheader
[4] = { -1, 3, 0, 0x21 };
dptestoutput(ifp
, m
, dst
, rt
)
register struct ifnet
*ifp
;
* Queue message on interface, and start output if interface
int s
= splimp(), error
= 0;
M_PREPEND(m
, sizeof pppheader
, M_DONTWAIT
);
bcopy(pppheader
, mtod(m
, caddr_t
), sizeof pppheader
);
if (IF_QFULL(&ifp
->if_snd
)) {
/* printf("%s%d: HDLC says OK to send but queue full, may hang\n",
ifp->if_name, ifp->if_unit);*/
IF_ENQUEUE(&ifp
->if_snd
, m
);
if ((ifp
->if_flags
& IFF_OACTIVE
) == 0)