/* if_acc.c 4.9 82/03/13 */
* ACC LH/DH ARPAnet IMP interface driver.
#include "../h/protosw.h"
#include "../net/in_systm.h"
#include "../net/if_acc.h"
#include "../net/if_imp.h"
#include "../net/if_uba.h"
int accprobe(), accattach(), accrint(), accxint();
struct uba_device
*accinfo
[NACC
];
u_short accstd
[] = { 0 };
struct uba_driver accdriver
=
{ accprobe
, 0, accattach
, 0, accstd
, "acc", accinfo
};
#define ACCUNIT(x) minor(x)
int accinit(), accstart(), accreset();
* "Lower half" of IMP interface driver.
* Each IMP interface is handled by a common module which handles
* the IMP-host protocol and a hardware driver which manages the
* hardware specific details of talking with the IMP.
* The hardware portion of the IMP driver handles DMA and related
* management of UNIBUS resources. The IMP protocol module interprets
* contents of these messages and "controls" the actions of the
* hardware module during IMP resets, but not, for instance, during
* The two modules are coupled at "attach time", and ever after,
* through the imp interface structure. Higher level protocols,
* e.g. IP, interact with the IMP driver, rather than the ACC.
struct ifnet
*acc_if
; /* pointer to IMP's ifnet struct */
struct impcb
*acc_ic
; /* data structure shared with IMP */
struct ifuba acc_ifuba
; /* UNIBUS resources */
struct mbuf
*acc_iq
; /* input reassembly queue */
short acc_olen
; /* size of last message sent */
char acc_flush
; /* flush remainder of message */
* Reset the IMP and cause a transmitter interrupt by
register int br
, cvec
; /* r11, r10 value-result */
register struct accdevice
*addr
= (struct accdevice
*)reg
;
br
= 0; cvec
= br
; br
= cvec
;
addr
->icsr
= ACC_RESET
; DELAY(5000);
addr
->ocsr
= ACC_RESET
; DELAY(5000);
addr
->ocsr
= OUT_BBACK
; DELAY(5000);
addr
->ocsr
= ACC_IE
| ACC_GO
; DELAY(5000);
if (cvec
&& cvec
!= 0x200) /* transmit -> receive */
* Call the IMP module to allow it to set up its internal
* state, then tie the two modules together by setting up
* the back pointers to common data structures.
register struct acc_softc
*sc
= &acc_softc
[ui
->ui_unit
];
register struct impcb
*ip
;
struct impcb ifimp_impcb
;
if ((ifimp
= (struct ifimpcb
*)impattach(ui
)) == 0)
sc
->acc_if
= &ifimp
->ifimp_if
;
ip
= &ifimp
->ifimp_impcb
;
sc
->acc_ifuba
.ifu_flags
= UBA_NEEDBDP
;
* Reset interface after UNIBUS reset.
* If interface is on specified uba, reset its state.
register struct uba_device
*ui
;
if (unit
>= NACC
|| (ui
= accinfo
[unit
]) == 0 || ui
->ui_alive
== 0 ||
/* must go through IMP to allow it to set state */
(*sc
->acc_if
->if_init
)(unit
);
* Initialize interface: clear recorded pending operations,
* and retrieve, and initialize UNIBUS resources. Note
* return value is used by IMP init routine to mark IMP
* unavailable for outgoing traffic.
register struct acc_softc
*sc
;
register struct uba_device
*ui
;
register struct accdevice
*addr
;
if (unit
>= NACC
|| (ui
= accinfo
[unit
]) == 0 || ui
->ui_alive
== 0) {
printf("acc%d: not alive\n", unit
);
* Header length is 0 since we have to passs
* the IMP leader up to the protocol interpretation
* routines. If we had the header length as
* sizeof(struct imp_leader), then the if_ routines
* would asssume we handle it on input and output.
if (if_ubainit(&sc
->acc_ifuba
, ui
->ui_ubanum
, 0,
(int)btoc(IMP_MTU
)) == 0) {
printf("acc%d: can't initialize\n", unit
);
addr
= (struct accdevice
*)ui
->ui_addr
;
* Reset the imp interface;
* the delays are pure guesswork.
addr
->icsr
= ACC_RESET
; DELAY(5000);
addr
->ocsr
= ACC_RESET
; DELAY(5000);
addr
->ocsr
= OUT_BBACK
; DELAY(1000); /* reset host master ready */
addr
->icsr
= IN_MRDY
| IN_WEN
; /* close the relay */
if ((addr
->icsr
& IN_HRDY
) ||
(addr
->icsr
& (IN_RMR
| IN_IMPBSY
)) == 0)
addr
->icsr
= IN_MRDY
| IN_WEN
;
DELAY(5000); /* keep turning IN_RMR off */
printf("acc%d: imp doesn't respond, icsr=%b\n", unit
,
* Put up a read. We can't restart any outstanding writes
* until we're back in synch with the IMP (i.e. we've flushed
* the NOOPs it throws at us).
* Note: IMP_MTU includes the leader.
info
= sc
->acc_ifuba
.ifu_r
.ifrw_info
;
addr
->iba
= (u_short
)info
;
addr
->iwc
= -(IMP_MTU
>> 1);
IN_MRDY
| ACC_IE
| IN_WEN
| ((info
& 0x30000) >> 12) | ACC_GO
;
* Start output on an interface.
int unit
= ACCUNIT(dev
), info
;
register struct acc_softc
*sc
= &acc_softc
[unit
];
register struct accdevice
*addr
;
if (sc
->acc_ic
->ic_oactive
)
* Not already active, deqeue a request and
* map it onto the UNIBUS. If no more
* requeusts, just return.
IF_DEQUEUE(&sc
->acc_if
->if_snd
, m
);
sc
->acc_ic
->ic_oactive
= 0;
sc
->acc_olen
= if_wubaput(&sc
->acc_ifuba
, m
);
* Have request mapped to UNIBUS for
* transmission; start the output.
if (sc
->acc_ifuba
.ifu_flags
& UBA_NEEDBDP
)
UBAPURGE(sc
->acc_ifuba
.ifu_uba
, sc
->acc_ifuba
.ifu_w
.ifrw_bdp
);
addr
= (struct accdevice
*)accinfo
[unit
]->ui_addr
;
info
= sc
->acc_ifuba
.ifu_w
.ifrw_info
;
addr
->oba
= (u_short
)info
;
addr
->owc
= -((sc
->acc_olen
+ 1) >> 1);
cmd
= ACC_IE
| OUT_ENLB
| ((info
& 0x30000) >> 12) | ACC_GO
;
sc
->acc_ic
->ic_oactive
= 1;
* Output interrupt handler.
register struct acc_softc
*sc
= &acc_softc
[unit
];
register struct accdevice
*addr
;
if (sc
->acc_ic
->ic_oactive
== 0) {
printf("acc%d: stray xmit interrupt\n", unit
);
addr
= (struct accdevice
*)accinfo
[unit
]->ui_addr
;
sc
->acc_if
->if_opackets
++;
sc
->acc_ic
->ic_oactive
= 0;
if (addr
->ocsr
& ACC_ERR
) {
printf("acc%d: output error, csr=%b\n", unit
,
addr
->ocsr
, ACC_OUTBITS
);
sc
->acc_if
->if_oerrors
++;
if (sc
->acc_ifuba
.ifu_xtofree
) {
m_freem(sc
->acc_ifuba
.ifu_xtofree
);
sc
->acc_ifuba
.ifu_xtofree
= 0;
if (sc
->acc_if
->if_snd
.ifq_head
)
* Input interrupt handler
register struct acc_softc
*sc
= &acc_softc
[unit
];
register struct accdevice
*addr
;
sc
->acc_if
->if_ipackets
++;
* Purge BDP; flush message if error indicated.
if (sc
->acc_ifuba
.ifu_flags
& UBA_NEEDBDP
)
UBAPURGE(sc
->acc_ifuba
.ifu_uba
, sc
->acc_ifuba
.ifu_r
.ifrw_bdp
);
addr
= (struct accdevice
*)accinfo
[unit
]->ui_addr
;
if (addr
->icsr
& ACC_ERR
) {
printf("acc%d: input error, csr=%b\n", unit
,
sc
->acc_if
->if_ierrors
++;
len
= IMP_MTU
+ (addr
->iwc
<< 1);
if (len
< 0 || len
> IMP_MTU
) {
printf("acc%d: bad length=%d\n", len
);
sc
->acc_if
->if_ierrors
++;
* The last parameter is always 0 since using
* trailers on the ARPAnet is insane.
m
= if_rubaget(&sc
->acc_ifuba
, len
, 0);
if ((addr
->icsr
& IN_EOM
) == 0) {
* Setup for next message.
info
= sc
->acc_ifuba
.ifu_r
.ifrw_info
;
addr
->iba
= (u_short
)info
;
addr
->iwc
= -(IMP_MTU
>> 1);
IN_MRDY
| ACC_IE
| IN_WEN
| ((info
& 0x30000) >> 12) | ACC_GO
;