* @(#)if_hy.c 7.1 (Berkeley) 6/5/86
* 4.2 BSD Unix Kernel - Vax Network Interface Support
* $Header: if_hy.c,v 10.1 84/07/22 21:02:56 steveg Exp $
* Modifications from Berkeley 4.2 BSD
* Copyright (c) 1983, Tektronix Inc.
* Revision 10.1 84/07/22 21:02:56 steveg
* define PI13 (moved from if_hyreg.h, somehow got dropped in the process)
* rework hywatch to check for power fails first
* Revision 10.0 84/06/30 19:54:27 steveg
* Revision 3.17 84/06/20 19:20:28 steveg
* increment hy_ntime in hywatch
* print out state name, csr, last command, and hy_flags when watchdog timer
* Revision 3.16 84/06/20 19:09:34 steveg
* turn on continuous logging by default
* Revision 3.15 84/05/30 22:19:09 steveg
* changes to reflect new layout ot statistics data
* Revision 3.14 84/05/30 19:25:15 steveg
* move driver states to if_hy.h so log printing programs can use them
* Revision 3.13 84/05/30 17:13:26 steveg
* Revision 3.12 84/05/30 13:46:16 steveg
* Revision 3.11 84/05/18 19:35:02 steveg
* clear IFF_RUNNING and IFF_UP on unibus reset to force resource allocation
* Revision 3.10 84/05/04 12:14:44 steveg
* more rework to make it actually work under 4.2
* Revision 3.9 84/05/01 23:34:52 steveg
* fix typo so it compiles (unit -> ui->ui_unit)
* Revision 3.8 84/05/01 23:18:30 steveg
* changes after talking with rickk
* - check power off more closely
* - support remote loopback through A710 adapters
* - return EHOSTUNREACH on hyroute failure
* - bump if_collisions on abnormal interrupts that aren't input or output
* Network Systems Copropration Hyperchanel 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 "../vaxuba/ubareg.h"
#include "../vaxuba/ubavar.h"
* configuration specific paramters
* - change as appropriate for particular installaions
int hyprobe(), hyattach(), hyinit(), hyioctl();
int hyoutput(), hyreset(), hywatch();
struct uba_device
*hyinfo
[NHY
];
u_short hystd
[] = { 0772410, 0 };
struct uba_driver hydriver
=
{ hyprobe
, 0, hyattach
, 0, hystd
, "hy", hyinfo
};
* Hyperchannel software status per interface.
* Each interface is referenced by a network interface structure,
* hy_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 ifnet hy_if
; /* network-visible interface */
struct ifuba hy_ifuba
; /* UNIBUS resources */
short hy_flags
; /* flags */
short hy_state
; /* driver state */
u_short hy_host
; /* local host number */
struct in_addr hy_addr
; /* internet address */
int hy_olen
; /* packet length on output */
int hy_lastwcr
; /* last command's word count */
short hy_savedstate
; /* saved for reissue after status */
short hy_savedcmd
; /* saved command for reissue */
int hy_savedcount
; /* saved byte count for reissue */
int hy_savedaddr
; /* saved unibus address for reissue */
int hy_ntime
; /* number of timeouts since last cmd */
int hy_retry
; /* retry counter */
struct hy_stat hy_stat
; /* statistics */
struct hy_status hy_status
; /* status */
u_long hy_elog
[HYE_SIZE
];
struct hy_route hy_route
[NHY
];
#define printD if (hy_debug_flag) printf
* hy_nodebug bit 0x01 set hy_debug_flag on hycancel
* hy_nodebug bit 0x02 set hy_debug_flag on command reissue
* hy_nodebug bit 0x04 set hy_debug_flag on abnormal interrupt
#define SCANINTERVAL 10 /* seconds */
#define MAXINTERVAL 20 /* seconds (max action) */
* Cause a device interrupt. This code uses a buffer starting at
* location zero on the unibus (which is already mapped by the
* autoconfigure code in the kernel).
register int br
, cvec
; /* r11, r10 value-result */
register struct hydevice
*addr
= (struct hydevice
*) reg
;
br
= 0; cvec
= br
; br
= cvec
;
* request adapter status to a buffer starting at unibus location 0
addr
->hyd_wcr
= -((sizeof(struct hy_status
) + 1) >> 1);
addr
->hyd_dbuf
= HYF_STATUS
;
addr
->hyd_csr
|= S_GO
| S_IE
| S_IATTN
;
addr
->hyd_csr
|= S_GO
| S_IE
;
addr
->hyd_csr
|= S_CLRINT
; /* clear any stacked interrupts */
addr
->hyd_csr
&= ~(S_IE
| S_CLRINT
); /* disable further interrupts */
return(sizeof(struct hydevice
));
* Interface exists: make available by filling in network interface
* record. System will initialize the interface when it is ready
register struct hy_softc
*is
= &hy_softc
[ui
->ui_unit
];
register struct ifnet
*ifp
= &is
->hy_if
;
ifp
->if_unit
= ui
->ui_unit
;
is
->hy_state
= STARTUP
; /* don't allow state transitions yet */
ifp
->if_output
= hyoutput
;
ifp
->if_watchdog
= hywatch
;
ifp
->if_timer
= SCANINTERVAL
;
is
->hy_ifuba
.ifu_flags
= UBA_CANTWAIT
;
is
->hy_ifuba
.ifu_flags
|= UBA_NEEDBDP
;
* Reset of interface after UNIBUS reset.
* If interface is on specified uba, reset its state.
register struct uba_device
*ui
;
register struct hy_softc
*is
;
if (unit
>= NHY
|| (ui
= hyinfo
[unit
]) == 0 || ui
->ui_alive
== 0 ||
is
= &hy_softc
[unit
]; /* force unibus resource allocation */
is
->hy_if
.if_flags
&= ~(IFF_UP
|IFF_RUNNING
);
* Initialization of interface; clear recorded pending
* operations, and reinitialize UNIBUS usage.
register struct hy_softc
*is
= &hy_softc
[unit
];
register struct uba_device
*ui
= hyinfo
[unit
];
if (is
->hy_if
.if_addrlist
== 0) /* address still unknown */
if (is
->hy_if
.if_flags
& IFF_RUNNING
) /* just reset the device */
if (if_ubainit(&is
->hy_ifuba
, ui
->ui_ubanum
,
sizeof (struct hym_hdr
), (int)btoc(HYMTU
)) == 0) {
printf("hy%d: can't initialize\n", unit
);
is
->hy_if
.if_flags
&= ~IFF_UP
;
is
->hy_if
.if_flags
|= IFF_RUNNING
;
* remove any left over outgoing messages, reset the hardware and
* start the state machine
hylog(HYL_RESET
, 0, (char *)0);
is
->hy_flags
= RQ_STATUS
| RQ_STATISTICS
| RQ_MARKUP
;
IF_DEQUEUE(&is
->hy_if
.if_snd
, m
);
hycancel(ui
); /* also bumps the state machine */
* Issue a command to the adapter
hystart(ui
, cmd
, count
, ubaddr
)
register struct hy_softc
*is
= &hy_softc
[ui
->ui_unit
];
register struct hydevice
*addr
= (struct hydevice
*)ui
->ui_addr
;
printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n",
ui
->ui_unit
, cmd
, count
, ubaddr
);
printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
ui
->ui_unit
, addr
->hyd_csr
, HY_CSR_BITS
, addr
->hyd_bar
,
if (((is
->hy_flags
& RQ_REISSUE
) == 0) &&
(cmd
!= HYF_STATUS
) && (cmd
!= HYF_END_OP
) && (cmd
!= HYF_RSTATS
)) {
is
->hy_savedstate
= is
->hy_state
;
is
->hy_savedcount
= count
;
is
->hy_savedaddr
= ubaddr
;
if (addr
->hyd_csr
& S_POWEROFF
) {
printf("hy%d: \"Soft\" Adapter Power Failure (hystart)\n", ui
->ui_unit
);
addr
->hyd_csr
|= S_POWEROFF
;
if (addr
->hyd_csr
& S_POWEROFF
) {
printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hystart)\n", ui
->ui_unit
);
is
->hy_if
.if_flags
&= ~IFF_UP
;
printf("hy%d: Adapter Power Restored (hystart)\n", ui
->ui_unit
);
addr
->hyd_bar
= ubaddr
& 0xffff;
addr
->hyd_wcr
= is
->hy_lastwcr
= -((count
+1) >> 1);
addr
->hyd_csr
= ((ubaddr
>> XBASHIFT
) & S_XBA
) | S_GO
| S_IE
| S_IATTN
;
addr
->hyd_csr
= ((ubaddr
>> XBASHIFT
) & S_XBA
) | S_GO
| S_IE
;
printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
ui
->ui_unit
, addr
->hyd_csr
, HY_CSR_BITS
, addr
->hyd_bar
,
hcl
.hstate
= is
->hy_state
;
hylog(HYL_CMD
, sizeof(hcl
), (char *)&hcl
);
int hyint_active
= 0; /* set during hy interrupt */
* Hyperchannel interface interrupt.
* An interrupt can occur for many reasons. Examine the status of
* the hyperchannel status bits to determine what to do next.
* If input error just drop packet.
* Otherwise purge input buffered data path and examine
* packet to determine type. Othewise decapsulate
* packet based on type and pass to type specific higher-level
register struct hy_softc
*is
= &hy_softc
[unit
];
register struct uba_device
*ui
= hyinfo
[unit
];
register struct hydevice
*addr
= (struct hydevice
*)ui
->ui_addr
;
panic("RECURSIVE HYPERCHANNEL INTERRUPT");
printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
unit
, addr
->hyd_csr
, HY_CSR_BITS
, addr
->hyd_bar
, addr
->hyd_wcr
);
hil
.hstate
= is
->hy_state
;
hil
.hflags
= is
->hy_flags
;
hil
.hcsr
= addr
->hyd_csr
;
hil
.hwcr
= addr
->hyd_wcr
;
hylog(HYL_INT
, sizeof(hil
), (char *)&hil
);
if (HYS_ERROR(addr
) && ((addr
->hyd_csr
& S_ATTN
) == 0)) {
* Error bit set, some sort of error in the interface.
* The adapter sets attn on command completion so that's not
* a real error even though the interface considers it one.
printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n",
addr
->hyd_csr
, HY_CSR_BITS
, addr
->hyd_bar
,
if (addr
->hyd_csr
& S_NEX
) {
printf("hy%d: NEX - Non Existant Memory\n", unit
);
addr
->hyd_csr
|= S_NEX
; /* as per PI13 manual */
} else if (addr
->hyd_csr
& S_POWEROFF
) {
printf("hy%d: \"Soft\" Adapter Power Failure (hyint)\n", unit
);
addr
->hyd_csr
|= S_POWEROFF
;
if (addr
->hyd_csr
& S_POWEROFF
) {
printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hyint)\n", unit
);
is
->hy_if
.if_flags
&= ~IFF_UP
;
printf("hy%d: Adapter Power Restored (hyint)\n", unit
);
printf("hy%d: BAR overflow\n", unit
);
} else if (HYS_NORMAL(addr
)) {
* Normal interrupt, bump state machine unless in state
* waiting and no data present (assumed to be word count
* zero interrupt or other hardware botch).
if (is
->hy_state
!= WAITING
|| HYS_RECVDATA(addr
))
} else if (HYS_ABNORMAL(addr
)) {
* bump error counts, retry the last function
* 'MAXRETRY' times before kicking the bucket.
* Don't reissue the cmd if in certain states, abnormal
* on a reissued cmd or max retry exceeded.
if (hy_log
.hyl_enable
!= hy_log
.hyl_onerr
) {
hy_log
.hyl_enable
= hy_log
.hyl_onerr
;
printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n",
unit
, hy_state_names
[is
->hy_state
], is
->hy_state
);
printD("\tflags 0x%x olen %d lastwcr %d retry %d\n",
is
->hy_flags
, is
->hy_olen
, is
->hy_lastwcr
, is
->hy_retry
);
printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n",
is
->hy_savedstate
, is
->hy_savedcount
,
is
->hy_savedaddr
, is
->hy_savedcmd
);
addr
->hyd_csr
&= ~S_C
; /* clear the damned PI-13 */
if (is
->hy_state
== XMITSENT
|| is
->hy_state
== XMITDATASENT
)
else if (is
->hy_state
== RECVSENT
|| is
->hy_state
== RECVDATASENT
)
is
->hy_if
.if_collisions
++; /* other errors */
if (is
->hy_state
== XMITDATASENT
||
is
->hy_state
== RECVSENT
||
is
->hy_state
== RECVDATASENT
||
(is
->hy_flags
& RQ_REISSUE
) != 0 || is
->hy_retry
> MAXRETRY
)
is
->hy_flags
|= RQ_ENDOP
| RQ_STATUS
| RQ_REISSUE
;
* Interrupt is neither normal, abnormal, or interface error.
* Ignore it. It's either stacked or a word count 0.
if (hy_log
.hyl_enable
!= hy_log
.hyl_onerr
) {
hy_log
.hyl_enable
= hy_log
.hyl_onerr
;
printD("hy%d: possible stacked interrupt ignored\n", unit
);
printD("hy%d: hyint exit\n\n", unit
);
* Encapsulate a packet of type family for the local net.
register struct hym_hdr
*hym
;
int dlen
; /* packet size, incl hardware header, but not sw header */
* Calculate packet length for later deciding whether it will fit
* in a message proper or we also need associated data.
for (m
= m0
; m
; m
= m
->m_next
)
if (dst
->sa_family
== AF_HYLINK
) { /* don't add header */
* Add the software and hardware hyperchannel headers.
* If there's not enough space in the first mbuf, allocate another.
* If that should fail, drop this sucker.
* No extra space for headers is allocated.
mp
= mtod(m
, char *); /* save pointer to real message */
if (m
->m_off
> MMAXOFF
||
MMINOFF
+ sizeof(struct hym_hdr
) > m
->m_off
) {
m
= m_get(M_DONTWAIT
, MT_HEADER
);
m
->m_len
= sizeof(struct hym_hdr
);
m
->m_off
-= sizeof(struct hym_hdr
);
m
->m_len
+= sizeof(struct hym_hdr
);
dlen
+= sizeof(struct hym_hdr
) - HYM_SWLEN
;
hym
= mtod(m
, struct hym_hdr
*);
bzero((caddr_t
)hym
, sizeof(struct hym_hdr
));
* if loopback address, swizzle ip header so when
* it comes back it looks like it was addressed to us
i
= hyroute(ifp
, (u_long
)in_lnaof(((struct sockaddr_in
*)dst
)->sin_addr
), hym
);
temp
.s_addr
= ((struct ip
*)mp
)->ip_dst
.s_addr
;
((struct ip
*)mp
)->ip_dst
.s_addr
= ((struct ip
*)mp
)->ip_src
.s_addr
;
((struct ip
*)mp
)->ip_src
.s_addr
= temp
.s_addr
;
* If entire packet won't fit in message proper, just
* send hyperchannel hardware header and ip header in
* This insures that the associated data is at least a
* TCP/UDP header in length and thus prevents potential
* problems with very short word counts.
hym
->hym_mplen
= sizeof(struct hy_hdr
) + (((struct ip
*)mp
)->ip_hl
<< 2);
hym
->hym_type
= HYLINK_IP
;
printf("hy%d: can't handle af%d\n", ifp
->if_unit
,
* insure message proper is below the maximum
if (hym
->hym_mplen
> MPSIZE
|| (dlen
> MPSIZE
&& hym
->hym_mplen
== 0))
hym
->hym_from
= htons(hy_softc
[ifp
->if_unit
].hy_host
);
hym
->hym_ctl
&= ~H_ASSOC
;
if (hyoutprint
) printf("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n",
ifp
->if_unit
, hym
->hym_mplen
, hym
->hym_ctl
,
hym
->hym_access
, hym
->hym_to
, hym
->hym_from
,
hym
->hym_param
, hym
->hym_type
);
printD("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n",
ifp
->if_unit
, hym
->hym_mplen
, hym
->hym_ctl
,
hym
->hym_access
, hym
->hym_to
, hym
->hym_from
,
hym
->hym_param
, hym
->hym_type
);
if (IF_QFULL(&ifp
->if_snd
)) {
IF_ENQUEUE(&ifp
->if_snd
, m
);
if (hy_softc
[ifp
->if_unit
].hy_state
== WAITING
)
hyact(hyinfo
[ifp
->if_unit
]);
register struct ifnet
*ifp
;
register struct hym_hdr
*hym
;
register struct hy_route
*rt
= &hy_route
[ifp
->if_unit
];
register struct hyr_hash
*rhash
;
if (rt
->hyr_lasttime
!= 0) {
rhash
= &rt
->hyr_hash
[i
];
while (rhash
->hyr_key
!= dest
) {
if (rhash
->hyr_flags
== 0 || i
> HYRSIZE
)
if (rhash
>= &rt
->hyr_hash
[HYRSIZE
])
rhash
= &rt
->hyr_hash
[0];
if (rhash
->hyr_flags
& HYR_GATE
) {
if (i
>= rhash
->hyr_egate
)
rhash
->hyr_nextgate
= rhash
->hyr_pgate
;
rhash
= &rt
->hyr_hash
[rt
->hyr_gateway
[i
]];
if ((rhash
->hyr_flags
& HYR_DIR
) == 0)
} else if (rhash
->hyr_flags
& HYR_LOOP
) {
hym
->hym_param
= H_LOOPBK
; /* adapter loopback */
} else if (rhash
->hyr_flags
& HYR_RLOOP
) {
hym
->hym_param
= H_RLOOPBK
; /* A710 remote loopback */
hym
->hym_ctl
= rhash
->hyr_ctl
;
hym
->hym_access
= rhash
->hyr_access
;
hym
->hym_to
= rhash
->hyr_dst
;
hym
->hym_ctl
= H_XTRUNKS
| H_RTRUNKS
;
hym
->hym_to
= htons((u_short
)dest
);
hym
->hym_param
= H_LOOPBK
; /* adapter loopback */
else if (dest
& 0x020000)
hym
->hym_param
= H_RLOOPBK
; /* A710 remote loopback */
register struct uba_device
*ui
;
register struct hy_softc
*is
= &hy_softc
[ui
->ui_unit
];
register struct hydevice
*addr
= (struct hydevice
*)ui
->ui_addr
;
printD("hy%d: hyact, enter state \"%s\"\n", ui
->ui_unit
,
hy_state_names
[is
->hy_state
]);
register rq
= is
->hy_flags
;
is
->hy_flags
&= ~RQ_STATUS
;
hystart(ui
, HYF_STATUS
, sizeof (is
->hy_status
),
is
->hy_ifuba
.ifu_r
.ifrw_info
);
} else if (rq
& RQ_ENDOP
) {
is
->hy_flags
&= ~RQ_ENDOP
;
is
->hy_state
= ENDOPSENT
;
hystart(ui
, HYF_END_OP
, 0, 0);
} else if (rq
& RQ_STATISTICS
) {
is
->hy_flags
&= ~RQ_STATISTICS
;
is
->hy_state
= RSTATSENT
;
hystart(ui
, HYF_RSTATS
, sizeof (is
->hy_stat
),
is
->hy_ifuba
.ifu_r
.ifrw_info
);
} else if (HYS_RECVDATA(addr
)) {
hystart(ui
, HYF_INPUTMSG
, MPSIZE
, is
->hy_ifuba
.ifu_r
.ifrw_info
+ HYM_SWLEN
);
} else if (rq
& RQ_REISSUE
) {
is
->hy_flags
&= ~RQ_REISSUE
;
is
->hy_state
= is
->hy_savedstate
;
printD("hy%d: reissue cmd=0x%x count=%d",
ui
->ui_unit
, is
->hy_savedcmd
, is
->hy_savedcount
);
printD(" ubaddr=0x%x retry=%d\n",
is
->hy_savedaddr
, is
->hy_retry
);
hystart(ui
, is
->hy_savedcmd
, is
->hy_savedcount
,
IF_DEQUEUE(&is
->hy_if
.if_snd
, m
);
register struct hym_hdr
*hym
;
hym
= mtod(m
, struct hym_hdr
*);
hylog(HYL_XMIT
, sizeof(struct hym_hdr
),
if (hym
->hym_to_adapter
== hym
->hym_from_adapter
)
printD("hy%d: hym_hdr = ", ui
->ui_unit
);
sizeof (struct hym_hdr
));
is
->hy_olen
= if_wubaput(&is
->hy_ifuba
, m
) - HYM_SWLEN
;
if (is
->hy_ifuba
.ifu_flags
& UBA_NEEDBDP
)
UBAPURGE(is
->hy_ifuba
.ifu_uba
,
is
->hy_ifuba
.ifu_w
.ifrw_bdp
);
"hy%d: sending packet (mplen = %d, hy_olen = %d) data = ",
ui
->ui_unit
, mplen
, is
->hy_olen
);
is
->hy_ifuba
.ifu_w
.ifrw_addr
,
is
->hy_olen
+ HYM_SWLEN
);
is
->hy_flags
&= ~RQ_XASSOC
;
is
->hy_flags
|= RQ_XASSOC
;
hystart(ui
, cmd
, mplen
, is
->hy_ifuba
.ifu_w
.ifrw_info
+ HYM_SWLEN
);
} else if (rq
& RQ_MARKDOWN
) {
is
->hy_flags
&= ~(RQ_MARKUP
| RQ_MARKDOWN
);
* Port number is taken from status data
(int)(HYF_MARKP0
|(PORTNUM(&is
->hy_status
)<<2)),
} else if (rq
& RQ_MARKUP
) {
register struct ifnet
*ifp
= &is
->hy_if
;
is
->hy_flags
&= ~RQ_MARKUP
;
* Fill in the host number
"hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n",
(is
->hy_stat
.hyc_atype
[0]<<8) |
is
->hy_stat
.hyc_atype
[1],
is
->hy_stat
.hyc_atype
[2]);
(is
->hy_stat
.hyc_uaddr
<< 8) |
hylog(HYL_UP
, 0, (char *)0);
hystart(ui
, HYF_WAITFORMSG
, 0, 0);
bcopy(is
->hy_ifuba
.ifu_r
.ifrw_addr
, (caddr_t
)&is
->hy_status
,
sizeof (struct hy_status
));
printD("hy%d: status - %x %x %x %x %x %x %x %x\n",
ui
->ui_unit
, is
->hy_status
.hys_gen_status
,
is
->hy_status
.hys_last_fcn
,
is
->hy_status
.hys_resp_trunk
,
is
->hy_status
.hys_status_trunk
,
is
->hy_status
.hys_recd_resp
,
hylog(HYL_STATUS
, sizeof (struct hy_status
),
i
= is
->hy_status
.hys_error
;
switch (is
->hy_status
.hys_last_fcn
) {
i
+= HYE_MAX
+1; /* fall through */
i
+= HYE_MAX
+1; /* fall through */
register struct hy_stat
*p
=
(struct hy_stat
*)is
->hy_ifuba
.ifu_r
.ifrw_addr
;
bcopy((caddr_t
)p
, (caddr_t
)&is
->hy_stat
, sizeof(struct hy_stat
));
printD("hy%d: statistics - df0 %d df1 %d df2 %d df3 %d\n",
(is
->hy_stat
.hyc_df0
[0]<<16) | (is
->hy_stat
.hyc_df0
[1]<<8) | is
->hy_stat
.hyc_df0
[2],
(is
->hy_stat
.hyc_df1
[0]<<16) | (is
->hy_stat
.hyc_df1
[1]<<8) | is
->hy_stat
.hyc_df1
[2],
(is
->hy_stat
.hyc_df2
[0]<<16) | (is
->hy_stat
.hyc_df2
[1]<<8) | is
->hy_stat
.hyc_df2
[2],
(is
->hy_stat
.hyc_df3
[0]<<16) | (is
->hy_stat
.hyc_df3
[1]<<8) | is
->hy_stat
.hyc_df3
[2]);
printD(" ret0 %d ret1 %d ret2 %d ret3 %d\n",
(is
->hy_stat
.hyc_ret0
[0]<<16) | (is
->hy_stat
.hyc_ret0
[1]<<8) | is
->hy_stat
.hyc_ret0
[2],
(is
->hy_stat
.hyc_ret1
[0]<<16) | (is
->hy_stat
.hyc_ret1
[1]<<8) | is
->hy_stat
.hyc_ret1
[2],
(is
->hy_stat
.hyc_ret2
[0]<<16) | (is
->hy_stat
.hyc_ret2
[1]<<8) | is
->hy_stat
.hyc_ret2
[2],
(is
->hy_stat
.hyc_ret3
[0]<<16) | (is
->hy_stat
.hyc_ret3
[1]<<8) | is
->hy_stat
.hyc_ret3
[2]);
printD(" cancel %d abort %d atype %x %x %x uaddr %x\n",
(is
->hy_stat
.hyc_cancel
[0]<<8) | is
->hy_stat
.hyc_cancel
[1],
(is
->hy_stat
.hyc_abort
[0]<<8) | is
->hy_stat
.hyc_abort
[1],
is
->hy_stat
.hyc_atype
[0], is
->hy_stat
.hyc_atype
[1],
is
->hy_stat
.hyc_atype
[2], is
->hy_stat
.hyc_uaddr
);
hylog(HYL_STATISTICS
, sizeof (struct hy_stat
),
register struct hym_hdr
*hym
;
if (is
->hy_ifuba
.ifu_flags
& UBA_NEEDBDP
)
UBAPURGE(is
->hy_ifuba
.ifu_uba
,
is
->hy_ifuba
.ifu_r
.ifrw_bdp
);
hym
= (struct hym_hdr
*) (is
->hy_ifuba
.ifu_r
.ifrw_addr
);
len
= (0xffff & (addr
->hyd_wcr
- is
->hy_lastwcr
)) << 1;
printf("hy%d: RECVD MP > MPSIZE (%d)\n",
printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
ui
->ui_unit
, addr
->hyd_csr
, HY_CSR_BITS
,
addr
->hyd_bar
, addr
->hyd_wcr
);
printD("hy%d: recvd mp, len = %d, data = ", ui
->ui_unit
, len
);
hyprintdata((char *)hym
, len
+ HYM_SWLEN
);
if (hym
->hym_ctl
& H_ASSOC
) {
is
->hy_state
= RECVDATASENT
;
hystart(ui
, HYF_INPUTDATA
,
(int)(HYMTU
+ sizeof (struct hy_hdr
) - len
),
(int)(HYM_SWLEN
+ is
->hy_ifuba
.ifu_r
.ifrw_info
+ len
));
hyrecvdata(ui
, hym
, (int)len
+ HYM_SWLEN
);
register struct hym_hdr
*hym
;
if (is
->hy_ifuba
.ifu_flags
& UBA_NEEDBDP
)
UBAPURGE(is
->hy_ifuba
.ifu_uba
,
is
->hy_ifuba
.ifu_r
.ifrw_bdp
);
hym
= (struct hym_hdr
*) (is
->hy_ifuba
.ifu_r
.ifrw_addr
);
len
= (0xffff & (addr
->hyd_wcr
- is
->hy_lastwcr
)) << 1;
printD("hy%d: recvd assoc data, len = %d, data = ",
hyprintdata((char *)hym
+ hym
->hym_mplen
, len
);
hyrecvdata(ui
, hym
, (int)(len
+ hym
->hym_mplen
+ HYM_SWLEN
));
if (is
->hy_flags
& RQ_XASSOC
) {
is
->hy_flags
&= ~RQ_XASSOC
;
is
->hy_state
= XMITDATASENT
;
len
= (0xffff & (addr
->hyd_wcr
- is
->hy_lastwcr
)) << 1;
"hy%d: xmit error - len > hy_olen [%d > %d]\n",
ui
->ui_unit
, len
, is
->hy_olen
);
hystart(ui
, HYF_XMITLSTDATA
, is
->hy_olen
- len
,
is
->hy_ifuba
.ifu_w
.ifrw_info
+ HYM_SWLEN
+ len
);
/* fall through to ... */
case WAITING
: /* wait for message complete or output requested */
is
->hy_state
= CLEARSENT
;
hystart(ui
, HYF_CLRWFMSG
, 0, 0);
is
->hy_if
.if_flags
&= ~IFF_UP
;
printf("hy%d: DRIVER BUG - INVALID STATE %d\n",
ui
->ui_unit
, is
->hy_state
);
panic("HYPERCHANNEL IN INVALID STATE");
if (is
->hy_state
== IDLE
)
printD("hy%d: hyact, exit at \"%s\"\n", ui
->ui_unit
,
hy_state_names
[is
->hy_state
]);
struct sockproto hypproto
= { PF_HYLINK
};
struct sockaddr_in hypdst
= { AF_HYLINK
};
struct sockaddr_in hypsrc
= { AF_HYLINK
};
* Called from device interrupt when receiving data.
* Examine packet to determine type. Decapsulate packet
* based on type and pass to type specific higher-level
register struct hym_hdr
*hym
;
register struct hy_softc
*is
= &hy_softc
[ui
->ui_unit
];
register struct ifqueue
*inq
;
printD("hy%d: recieved packet, len = %d\n", ui
->ui_unit
, len
);
hylog(HYL_RECV
, sizeof(hh
), (char *)&hh
);
if (len
> HYMTU
+ MPSIZE
|| len
== 0)
* Pull packet off interface.
m
= if_rubaget(&is
->hy_ifuba
, len
, 0, &is
->hy_if
);
* if normal or adapter loopback response packet believe hym_type,
* otherwise, use the raw input queue cause it's a response from an
if (hym
->hym_param
!= 0 && (u_short
)hym
->hym_param
!= 0x80ff)
MGET(m0
, M_DONTWAIT
, MT_DATA
);
m0
->m_len
= sizeof(struct hym_hdr
);
bcopy((caddr_t
)hym
, mtod(m0
, caddr_t
), sizeof(struct hym_hdr
));
hypproto
.sp_protocol
= 0;
hypdst
.sin_addr
= is
->hy_addr
;
hypsrc
.sin_addr
= is
->hy_addr
;
raw_input(m
, &hypproto
, (struct sockaddr
*)&hypsrc
,
(struct sockaddr
*)&hypdst
);
* Transmit done, release resources, bump counters.
register struct hy_softc
*is
= &hy_softc
[ui
->ui_unit
];
if (is
->hy_ifuba
.ifu_xtofree
) {
m_freem(is
->hy_ifuba
.ifu_xtofree
);
is
->hy_ifuba
.ifu_xtofree
= 0;
register struct uba_device
*ui
;
register struct hy_softc
*is
= &hy_softc
[ui
->ui_unit
];
if (is
->hy_ifuba
.ifu_xtofree
) {
m_freem(is
->hy_ifuba
.ifu_xtofree
);
is
->hy_ifuba
.ifu_xtofree
= 0;
hylog(HYL_CANCEL
, 0, (char *)0);
printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n",
ui
->ui_unit
, hy_state_names
[is
->hy_state
], is
->hy_savedcmd
,
is
->hy_savedcount
, is
->hy_savedaddr
);
printD("\tflags 0x%x olen %d lastwcr %d retry %d\n",
is
->hy_flags
, is
->hy_olen
, is
->hy_lastwcr
, is
->hy_retry
);
printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n",
is
->hy_savedstate
, is
->hy_savedcount
, is
->hy_savedaddr
,
is
->hy_flags
|= (RQ_ENDOP
| RQ_STATUS
);
static char regfmt
[] = "\n\t %x";
printL(fmt
, *cp
++ & 0xff);
register struct hy_softc
*is
= &hy_softc
[unit
];
register struct uba_device
*ui
= hyinfo
[unit
];
register struct hydevice
*addr
= (struct hydevice
*)ui
->ui_addr
;
if ((addr
->hyd_csr
& S_POWEROFF
) != 0) {
addr
->hyd_csr
|= S_POWEROFF
;
if ((addr
->hyd_csr
& S_POWEROFF
) == 0) {
printf("hy%d: Adapter Power Restored (hywatch)\n", unit
);
(RQ_MARKUP
| RQ_STATISTICS
| RQ_ENDOP
| RQ_STATUS
);
if (++is
->hy_ntime
>= 2 && is
->hy_state
!= WAITING
&&
is
->hy_state
!= STARTUP
&& is
->hy_state
!= IDLE
) {
printf("hy%d: watchdog timer expired in state \"%s\"\n", unit
,
hy_state_names
[is
->hy_state
]);
printf("hy%d: watchdog timer expired in state %d\n", unit
,
printf("hy%d: last command 0x%x, flags 0x%x, csr 0x%b\n", unit
,
is
->hy_savedcmd
, is
->hy_flags
, addr
->hyd_csr
, HY_CSR_BITS
);
is
->hy_if
.if_timer
= SCANINTERVAL
;
register unsigned char *p
;
if (hy_log
.hyl_self
!= &hy_log
) {
hy_log
.hyl_eptr
= &hy_log
.hyl_buf
[HYL_SIZE
];
hy_log
.hyl_ptr
= &hy_log
.hyl_buf
[0];
hy_log
.hyl_self
= &hy_log
;
hy_log
.hyl_enable
= HYL_CONTINUOUS
;
hy_log
.hyl_onerr
= HYL_CONTINUOUS
;
hy_log
.hyl_filter
= 0xffff; /* enable all */
if (hy_log
.hyl_enable
== HYL_DISABLED
|| ((1 << code
) & hy_log
.hyl_filter
) == 0)
if (p
+ len
+ 3 >= hy_log
.hyl_eptr
) {
bzero((caddr_t
)p
, (unsigned)(hy_log
.hyl_eptr
- p
));
if (hy_log
.hyl_enable
!= HYL_CONTINUOUS
) {
hy_log
.hyl_enable
= HYL_DISABLED
;
bcopy((caddr_t
)ptr
, (caddr_t
)p
, (unsigned)len
);
if (hy_log
.hyl_count
!= 0 && --hy_log
.hyl_count
== 0) {
hy_log
.hyl_enable
= HYL_DISABLED
;
hy_log
.hyl_count
= hy_log
.hyl_icount
;
if (hy_log
.hyl_wait
!= 0) { /* wakeup HYGETLOG if wanted */
if (hy_log
.hyl_wait
<= p
- hy_log
.hyl_ptr
) {
wakeup((caddr_t
)&hy_log
);
hy_log
.hyl_wait
-= p
- hy_log
.hyl_ptr
;
register struct ifnet
*ifp
;
struct ifaddr
*ifa
= (struct ifaddr
*) data
;
struct hyrsetget
*sg
= (struct hyrsetget
*)data
;
#if defined(HYLOG) || defined(HYELOG)
struct hylsetget
*sgl
= (struct hylsetget
*)data
;
struct hy_route
*r
= (struct hy_route
*)&hy_route
[ifp
->if_unit
];
int s
= splimp(), error
= 0;
struct hy_softc
*is
= &hy_softc
[ifp
->if_unit
];
hil
.hstate
= is
->hy_state
;
hil
.hflags
= is
->hy_flags
;
if (ifa
->ifa_addr
.sa_family
!= AF_INET
)
if ((ifp
->if_flags
& IFF_RUNNING
) == 0)
hy_softc
[ifp
->if_unit
].hy_addr
= IA_SIN(ifa
)->sin_addr
;
hil
.haddr
= is
->hy_addr
.s_addr
;
if (sg
->hyrsg_len
!= sizeof(struct hy_route
)) {
if (copyin((caddr_t
)(sg
->hyrsg_ptr
), (caddr_t
)r
, sg
->hyrsg_len
)) {
r
->hyr_lasttime
= 0; /* disable further routing if trouble */
r
->hyr_lasttime
= time
.tv_sec
;
hil
.hmisc
= r
->hyr_lasttime
;
if (sg
->hyrsg_len
< sizeof(struct hy_route
)) {
if (copyout((caddr_t
)r
, (caddr_t
) (sg
->hyrsg_ptr
), sizeof(struct hy_route
))) {
if (sgl
->hylsg_len
< sizeof(hy_elog
)) {
if (copyout((caddr_t
)hy_elog
, sgl
->hylsg_ptr
, sizeof(hy_elog
))) {
bzero((caddr_t
)hy_elog
, sizeof(hy_elog
));
hy_log
.hyl_enable
= HYL_DISABLED
;
hylog(HYL_NOP
, 0, (char *)0); /* force log init */
hy_log
.hyl_enable
= sgl
->hylsg_cmd
& 0x0f;
hy_log
.hyl_onerr
= (sgl
->hylsg_cmd
>> 4) & 0x0f;
hy_log
.hyl_filter
= (sgl
->hylsg_cmd
>> 8) & 0xffffff;
hy_log
.hyl_count
= hy_log
.hyl_icount
= sgl
->hylsg_len
;
wakeup((caddr_t
)&hy_log
); /* wakeup sleeping HYGETLOG */
if (sgl
->hylsg_len
< sizeof(hy_log
)) {
if (sgl
->hylsg_cmd
!= 0) {
hy_log
.hyl_wait
= sgl
->hylsg_cmd
;
sleep((caddr_t
)&hy_log
, PZERO
- 1);
if (copyout((caddr_t
)&hy_log
, sgl
->hylsg_ptr
, sizeof(hy_log
))) {
hil
.iflags
= ifp
->if_flags
;
hil
.haddr
= is
->hy_addr
.s_addr
;
hylog(HYL_IOCTL
, sizeof(hil
), (char *)&hil
);