2008-02-08 00:03:49 +01:00
/*
* drivers / s390 / net / ctcm_mpc . c
*
* Copyright IBM Corp . 2004 , 2007
* Authors : Belinda Thompson ( belindat @ us . ibm . com )
* Andy Richter ( richtera @ us . ibm . com )
* Peter Tiedemann ( ptiedem @ de . ibm . com )
*/
/*
This module exports functions to be used by CCS :
EXPORT_SYMBOL ( ctc_mpc_alloc_channel ) ;
EXPORT_SYMBOL ( ctc_mpc_establish_connectivity ) ;
EXPORT_SYMBOL ( ctc_mpc_dealloc_ch ) ;
EXPORT_SYMBOL ( ctc_mpc_flow_control ) ;
*/
# undef DEBUG
# undef DEBUGDATA
# undef DEBUGCCW
2008-12-25 13:39:54 +01:00
# define KMSG_COMPONENT "ctcm"
# define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
2008-02-08 00:03:49 +01:00
# include <linux/module.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/errno.h>
# include <linux/types.h>
# include <linux/interrupt.h>
# include <linux/timer.h>
# include <linux/sched.h>
# include <linux/signal.h>
# include <linux/string.h>
# include <linux/proc_fs.h>
# include <linux/ip.h>
# include <linux/if_arp.h>
# include <linux/tcp.h>
# include <linux/skbuff.h>
# include <linux/ctype.h>
# include <linux/netdevice.h>
# include <net/dst.h>
# include <linux/io.h> /* instead of <asm/io.h> ok ? */
# include <asm/ccwdev.h>
# include <asm/ccwgroup.h>
# include <linux/bitops.h> /* instead of <asm/bitops.h> ok ? */
# include <linux/uaccess.h> /* instead of <asm/uaccess.h> ok ? */
# include <linux/wait.h>
# include <linux/moduleparam.h>
# include <asm/idals.h>
# include "ctcm_mpc.h"
# include "ctcm_main.h"
# include "ctcm_fsms.h"
static const struct xid2 init_xid = {
. xid2_type_id = XID_FM2 ,
. xid2_len = 0x45 ,
. xid2_adj_id = 0 ,
. xid2_rlen = 0x31 ,
. xid2_resv1 = 0 ,
. xid2_flag1 = 0 ,
. xid2_fmtt = 0 ,
. xid2_flag4 = 0x80 ,
. xid2_resv2 = 0 ,
. xid2_tgnum = 0 ,
. xid2_sender_id = 0 ,
. xid2_flag2 = 0 ,
. xid2_option = XID2_0 ,
. xid2_resv3 = " \x00 " ,
. xid2_resv4 = 0 ,
. xid2_dlc_type = XID2_READ_SIDE ,
. xid2_resv5 = 0 ,
. xid2_mpc_flag = 0 ,
. xid2_resv6 = 0 ,
. xid2_buf_len = ( MPC_BUFSIZE_DEFAULT - 35 ) ,
} ;
static const struct th_header thnorm = {
. th_seg = 0x00 ,
. th_ch_flag = TH_IS_XID ,
. th_blk_flag = TH_DATA_IS_XID ,
. th_is_xid = 0x01 ,
. th_seq_num = 0x00000000 ,
} ;
static const struct th_header thdummy = {
. th_seg = 0x00 ,
. th_ch_flag = 0x00 ,
. th_blk_flag = TH_DATA_IS_XID ,
. th_is_xid = 0x01 ,
. th_seq_num = 0x00000000 ,
} ;
/*
* Definition of one MPC group
*/
/*
* Compatibility macros for busy handling
* of network devices .
*/
static void ctcmpc_unpack_skb ( struct channel * ch , struct sk_buff * pskb ) ;
/*
* MPC Group state machine actions ( static prototypes )
*/
static void mpc_action_nop ( fsm_instance * fsm , int event , void * arg ) ;
static void mpc_action_go_ready ( fsm_instance * fsm , int event , void * arg ) ;
static void mpc_action_go_inop ( fsm_instance * fi , int event , void * arg ) ;
static void mpc_action_timeout ( fsm_instance * fi , int event , void * arg ) ;
static int mpc_validate_xid ( struct mpcg_info * mpcginfo ) ;
static void mpc_action_yside_xid ( fsm_instance * fsm , int event , void * arg ) ;
static void mpc_action_doxid0 ( fsm_instance * fsm , int event , void * arg ) ;
static void mpc_action_doxid7 ( fsm_instance * fsm , int event , void * arg ) ;
static void mpc_action_xside_xid ( fsm_instance * fsm , int event , void * arg ) ;
static void mpc_action_rcvd_xid0 ( fsm_instance * fsm , int event , void * arg ) ;
static void mpc_action_rcvd_xid7 ( fsm_instance * fsm , int event , void * arg ) ;
# ifdef DEBUGDATA
/*-------------------------------------------------------------------*
* Dump buffer format *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void ctcmpc_dumpit ( char * buf , int len )
{
__u32 ct , sw , rm , dup ;
char * ptr , * rptr ;
char tbuf [ 82 ] , tdup [ 82 ] ;
# if (UTS_MACHINE == s390x)
char addr [ 22 ] ;
# else
char addr [ 12 ] ;
# endif
char boff [ 12 ] ;
char bhex [ 82 ] , duphex [ 82 ] ;
char basc [ 40 ] ;
sw = 0 ;
rptr = ptr = buf ;
rm = 16 ;
duphex [ 0 ] = 0x00 ;
dup = 0 ;
for ( ct = 0 ; ct < len ; ct + + , ptr + + , rptr + + ) {
if ( sw = = 0 ) {
# if (UTS_MACHINE == s390x)
2008-07-18 15:24:57 +02:00
sprintf ( addr , " %16.16lx " , ( __u64 ) rptr ) ;
2008-02-08 00:03:49 +01:00
# else
sprintf ( addr , " %8.8X " , ( __u32 ) rptr ) ;
# endif
sprintf ( boff , " %4.4X " , ( __u32 ) ct ) ;
bhex [ 0 ] = ' \0 ' ;
basc [ 0 ] = ' \0 ' ;
}
if ( ( sw = = 4 ) | | ( sw = = 12 ) )
strcat ( bhex , " " ) ;
if ( sw = = 8 )
strcat ( bhex , " " ) ;
# if (UTS_MACHINE == s390x)
2008-07-18 15:24:57 +02:00
sprintf ( tbuf , " %2.2lX " , ( __u64 ) * ptr ) ;
2008-02-08 00:03:49 +01:00
# else
sprintf ( tbuf , " %2.2X " , ( __u32 ) * ptr ) ;
# endif
tbuf [ 2 ] = ' \0 ' ;
strcat ( bhex , tbuf ) ;
if ( ( 0 ! = isprint ( * ptr ) ) & & ( * ptr > = 0x20 ) )
basc [ sw ] = * ptr ;
else
basc [ sw ] = ' . ' ;
basc [ sw + 1 ] = ' \0 ' ;
sw + + ;
rm - - ;
2008-07-18 15:24:57 +02:00
if ( sw ! = 16 )
continue ;
if ( ( strcmp ( duphex , bhex ) ) ! = 0 ) {
if ( dup ! = 0 ) {
sprintf ( tdup ,
" Duplicate as above to %s " , addr ) ;
ctcm_pr_debug ( " --- %s --- \n " ,
tdup ) ;
}
ctcm_pr_debug ( " %s (+%s) : %s [%s] \n " ,
2008-02-08 00:03:49 +01:00
addr , boff , bhex , basc ) ;
2008-07-18 15:24:57 +02:00
dup = 0 ;
strcpy ( duphex , bhex ) ;
} else
dup + + ;
2008-02-08 00:03:49 +01:00
2008-07-18 15:24:57 +02:00
sw = 0 ;
rm = 16 ;
2008-02-08 00:03:49 +01:00
} /* endfor */
if ( sw ! = 0 ) {
for ( ; rm > 0 ; rm - - , sw + + ) {
if ( ( sw = = 4 ) | | ( sw = = 12 ) )
strcat ( bhex , " " ) ;
if ( sw = = 8 )
strcat ( bhex , " " ) ;
strcat ( bhex , " " ) ;
strcat ( basc , " " ) ;
}
if ( dup ! = 0 ) {
sprintf ( tdup , " Duplicate as above to %s " , addr ) ;
2008-07-18 15:24:57 +02:00
ctcm_pr_debug ( " --- %s --- \n " , tdup ) ;
2008-02-08 00:03:49 +01:00
}
2008-07-18 15:24:57 +02:00
ctcm_pr_debug ( " %s (+%s) : %s [%s] \n " ,
addr , boff , bhex , basc ) ;
2008-02-08 00:03:49 +01:00
} else {
if ( dup > = 1 ) {
sprintf ( tdup , " Duplicate as above to %s " , addr ) ;
2008-07-18 15:24:57 +02:00
ctcm_pr_debug ( " --- %s --- \n " , tdup ) ;
2008-02-08 00:03:49 +01:00
}
if ( dup ! = 0 ) {
2008-07-18 15:24:57 +02:00
ctcm_pr_debug ( " %s (+%s) : %s [%s] \n " ,
2008-02-08 00:03:49 +01:00
addr , boff , bhex , basc ) ;
}
}
return ;
} /* end of ctcmpc_dumpit */
# endif
# ifdef DEBUGDATA
/*
* Dump header and first 16 bytes of an sk_buff for debugging purposes .
*
* skb The sk_buff to dump .
* offset Offset relative to skb - data , where to start the dump .
*/
void ctcmpc_dump_skb ( struct sk_buff * skb , int offset )
{
2008-07-18 15:24:57 +02:00
__u8 * p = skb - > data ;
2008-02-08 00:03:49 +01:00
struct th_header * header ;
struct pdu * pheader ;
int bl = skb - > len ;
int i ;
if ( p = = NULL )
return ;
p + = offset ;
header = ( struct th_header * ) p ;
2008-07-18 15:24:57 +02:00
ctcm_pr_debug ( " dump: \n " ) ;
ctcm_pr_debug ( " skb len=%d \n " , skb - > len ) ;
2008-02-08 00:03:49 +01:00
if ( skb - > len > 2 ) {
switch ( header - > th_ch_flag ) {
case TH_HAS_PDU :
break ;
case 0x00 :
case TH_IS_XID :
if ( ( header - > th_blk_flag = = TH_DATA_IS_XID ) & &
( header - > th_is_xid = = 0x01 ) )
goto dumpth ;
case TH_SWEEP_REQ :
goto dumpth ;
case TH_SWEEP_RESP :
goto dumpth ;
default :
break ;
}
pheader = ( struct pdu * ) p ;
2008-07-18 15:24:57 +02:00
ctcm_pr_debug ( " pdu->offset: %d hex: %04x \n " ,
pheader - > pdu_offset , pheader - > pdu_offset ) ;
ctcm_pr_debug ( " pdu->flag : %02x \n " , pheader - > pdu_flag ) ;
ctcm_pr_debug ( " pdu->proto : %02x \n " , pheader - > pdu_proto ) ;
ctcm_pr_debug ( " pdu->seq : %02x \n " , pheader - > pdu_seq ) ;
2008-02-08 00:03:49 +01:00
goto dumpdata ;
dumpth :
2008-07-18 15:24:57 +02:00
ctcm_pr_debug ( " th->seg : %02x \n " , header - > th_seg ) ;
ctcm_pr_debug ( " th->ch : %02x \n " , header - > th_ch_flag ) ;
ctcm_pr_debug ( " th->blk_flag: %02x \n " , header - > th_blk_flag ) ;
ctcm_pr_debug ( " th->type : %s \n " ,
( header - > th_is_xid ) ? " DATA " : " XID " ) ;
ctcm_pr_debug ( " th->seqnum : %04x \n " , header - > th_seq_num ) ;
2008-02-08 00:03:49 +01:00
}
dumpdata :
if ( bl > 32 )
bl = 32 ;
2008-07-18 15:24:57 +02:00
ctcm_pr_debug ( " data: " ) ;
2008-02-08 00:03:49 +01:00
for ( i = 0 ; i < bl ; i + + )
2008-07-18 15:24:57 +02:00
ctcm_pr_debug ( " %02x%s " , * p + + , ( i % 16 ) ? " " : " \n " ) ;
ctcm_pr_debug ( " \n " ) ;
2008-02-08 00:03:49 +01:00
}
# endif
2008-07-18 15:24:57 +02:00
static struct net_device * ctcmpc_get_dev ( int port_num )
{
char device [ 20 ] ;
struct net_device * dev ;
struct ctcm_priv * priv ;
sprintf ( device , " %s%i " , MPC_DEVICE_NAME , port_num ) ;
dev = __dev_get_by_name ( & init_net , device ) ;
if ( dev = = NULL ) {
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s: Device not found by name: %s " ,
CTCM_FUNTAIL , device ) ;
return NULL ;
}
2008-08-21 17:10:24 +02:00
priv = dev - > ml_priv ;
2008-07-18 15:24:57 +02:00
if ( priv = = NULL ) {
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
2008-08-21 17:10:24 +02:00
" %s(%s): dev->ml_priv is NULL " ,
2008-07-18 15:24:57 +02:00
CTCM_FUNTAIL , device ) ;
return NULL ;
}
if ( priv - > mpcg = = NULL ) {
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): priv->mpcg is NULL " ,
CTCM_FUNTAIL , device ) ;
return NULL ;
}
return dev ;
}
2008-02-08 00:03:49 +01:00
/*
* ctc_mpc_alloc_channel
* ( exported interface )
*
* Device Initialization :
* ACTPATH driven IO operations
*/
int ctc_mpc_alloc_channel ( int port_num , void ( * callback ) ( int , int ) )
{
struct net_device * dev ;
struct mpc_group * grp ;
struct ctcm_priv * priv ;
2008-07-18 15:24:57 +02:00
dev = ctcmpc_get_dev ( port_num ) ;
if ( dev = = NULL )
2008-02-08 00:03:49 +01:00
return 1 ;
2008-08-21 17:10:24 +02:00
priv = dev - > ml_priv ;
2008-02-08 00:03:49 +01:00
grp = priv - > mpcg ;
grp - > allochanfunc = callback ;
grp - > port_num = port_num ;
grp - > port_persist = 1 ;
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_SETUP , CTC_DBF_INFO ,
" %s(%s): state=%s " ,
CTCM_FUNTAIL , dev - > name , fsm_getstate_str ( grp - > fsm ) ) ;
2008-02-08 00:03:49 +01:00
switch ( fsm_getstate ( grp - > fsm ) ) {
case MPCG_STATE_INOP :
/* Group is in the process of terminating */
grp - > alloc_called = 1 ;
break ;
case MPCG_STATE_RESET :
/* MPC Group will transition to state */
/* MPCG_STATE_XID2INITW iff the minimum number */
/* of 1 read and 1 write channel have successfully*/
/* activated */
/*fsm_newstate(grp->fsm, MPCG_STATE_XID2INITW);*/
if ( callback )
grp - > send_qllc_disc = 1 ;
case MPCG_STATE_XID0IOWAIT :
fsm_deltimer ( & grp - > timer ) ;
grp - > outstanding_xid2 = 0 ;
grp - > outstanding_xid7 = 0 ;
grp - > outstanding_xid7_p2 = 0 ;
grp - > saved_xid2 = NULL ;
if ( callback )
ctcm_open ( dev ) ;
fsm_event ( priv - > fsm , DEV_EVENT_START , dev ) ;
break ;
case MPCG_STATE_READY :
/* XID exchanges completed after PORT was activated */
/* Link station already active */
/* Maybe timing issue...retry callback */
grp - > allocchan_callback_retries + + ;
if ( grp - > allocchan_callback_retries < 4 ) {
if ( grp - > allochanfunc )
grp - > allochanfunc ( grp - > port_num ,
2008-12-25 13:39:54 +01:00
grp - > group_max_buflen ) ;
2008-02-08 00:03:49 +01:00
} else {
/* there are problems...bail out */
/* there may be a state mismatch so restart */
fsm_event ( grp - > fsm , MPCG_EVENT_INOP , dev ) ;
grp - > allocchan_callback_retries = 0 ;
}
break ;
}
return 0 ;
}
EXPORT_SYMBOL ( ctc_mpc_alloc_channel ) ;
/*
* ctc_mpc_establish_connectivity
* ( exported interface )
*/
void ctc_mpc_establish_connectivity ( int port_num ,
void ( * callback ) ( int , int , int ) )
{
struct net_device * dev ;
struct mpc_group * grp ;
struct ctcm_priv * priv ;
struct channel * rch , * wch ;
2008-07-18 15:24:57 +02:00
dev = ctcmpc_get_dev ( port_num ) ;
if ( dev = = NULL )
2008-02-08 00:03:49 +01:00
return ;
2008-08-21 17:10:24 +02:00
priv = dev - > ml_priv ;
2008-07-18 15:24:57 +02:00
grp = priv - > mpcg ;
2008-02-08 00:03:49 +01:00
rch = priv - > channel [ READ ] ;
wch = priv - > channel [ WRITE ] ;
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_SETUP , CTC_DBF_INFO ,
" %s(%s): state=%s " ,
CTCM_FUNTAIL , dev - > name , fsm_getstate_str ( grp - > fsm ) ) ;
2008-02-08 00:03:49 +01:00
grp - > estconnfunc = callback ;
grp - > port_num = port_num ;
switch ( fsm_getstate ( grp - > fsm ) ) {
case MPCG_STATE_READY :
/* XID exchanges completed after PORT was activated */
/* Link station already active */
/* Maybe timing issue...retry callback */
fsm_deltimer ( & grp - > timer ) ;
grp - > estconn_callback_retries + + ;
if ( grp - > estconn_callback_retries < 4 ) {
if ( grp - > estconnfunc ) {
grp - > estconnfunc ( grp - > port_num , 0 ,
grp - > group_max_buflen ) ;
grp - > estconnfunc = NULL ;
}
} else {
/* there are problems...bail out */
fsm_event ( grp - > fsm , MPCG_EVENT_INOP , dev ) ;
grp - > estconn_callback_retries = 0 ;
}
break ;
case MPCG_STATE_INOP :
case MPCG_STATE_RESET :
/* MPC Group is not ready to start XID - min num of */
/* 1 read and 1 write channel have not been acquired*/
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): REJECTED - inactive channels " ,
CTCM_FUNTAIL , dev - > name ) ;
2008-02-08 00:03:49 +01:00
if ( grp - > estconnfunc ) {
grp - > estconnfunc ( grp - > port_num , - 1 , 0 ) ;
grp - > estconnfunc = NULL ;
}
break ;
case MPCG_STATE_XID2INITW :
/* alloc channel was called but no XID exchange */
/* has occurred. initiate xside XID exchange */
/* make sure yside XID0 processing has not started */
2008-07-18 15:24:57 +02:00
2008-02-08 00:03:49 +01:00
if ( ( fsm_getstate ( rch - > fsm ) > CH_XID0_PENDING ) | |
( fsm_getstate ( wch - > fsm ) > CH_XID0_PENDING ) ) {
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): ABORT - PASSIVE XID " ,
CTCM_FUNTAIL , dev - > name ) ;
2008-02-08 00:03:49 +01:00
break ;
}
grp - > send_qllc_disc = 1 ;
fsm_newstate ( grp - > fsm , MPCG_STATE_XID0IOWAIT ) ;
fsm_deltimer ( & grp - > timer ) ;
fsm_addtimer ( & grp - > timer , MPC_XID_TIMEOUT_VALUE ,
MPCG_EVENT_TIMER , dev ) ;
grp - > outstanding_xid7 = 0 ;
grp - > outstanding_xid7_p2 = 0 ;
grp - > saved_xid2 = NULL ;
if ( ( rch - > in_mpcgroup ) & &
( fsm_getstate ( rch - > fsm ) = = CH_XID0_PENDING ) )
fsm_event ( grp - > fsm , MPCG_EVENT_XID0DO , rch ) ;
else {
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): RX-%s not ready for ACTIVE XID0 " ,
CTCM_FUNTAIL , dev - > name , rch - > id ) ;
2008-02-08 00:03:49 +01:00
if ( grp - > estconnfunc ) {
grp - > estconnfunc ( grp - > port_num , - 1 , 0 ) ;
grp - > estconnfunc = NULL ;
}
fsm_deltimer ( & grp - > timer ) ;
goto done ;
}
if ( ( wch - > in_mpcgroup ) & &
( fsm_getstate ( wch - > fsm ) = = CH_XID0_PENDING ) )
fsm_event ( grp - > fsm , MPCG_EVENT_XID0DO , wch ) ;
else {
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): WX-%s not ready for ACTIVE XID0 " ,
CTCM_FUNTAIL , dev - > name , wch - > id ) ;
2008-02-08 00:03:49 +01:00
if ( grp - > estconnfunc ) {
grp - > estconnfunc ( grp - > port_num , - 1 , 0 ) ;
grp - > estconnfunc = NULL ;
}
fsm_deltimer ( & grp - > timer ) ;
goto done ;
}
break ;
case MPCG_STATE_XID0IOWAIT :
/* already in active XID negotiations */
default :
break ;
}
done :
2008-07-18 15:24:57 +02:00
CTCM_PR_DEBUG ( " Exit %s() \n " , __func__ ) ;
2008-02-08 00:03:49 +01:00
return ;
}
EXPORT_SYMBOL ( ctc_mpc_establish_connectivity ) ;
/*
* ctc_mpc_dealloc_ch
* ( exported interface )
*/
void ctc_mpc_dealloc_ch ( int port_num )
{
struct net_device * dev ;
struct ctcm_priv * priv ;
struct mpc_group * grp ;
2008-07-18 15:24:57 +02:00
dev = ctcmpc_get_dev ( port_num ) ;
if ( dev = = NULL )
return ;
2008-08-21 17:10:24 +02:00
priv = dev - > ml_priv ;
2008-07-18 15:24:57 +02:00
grp = priv - > mpcg ;
2008-02-08 00:03:49 +01:00
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_SETUP , CTC_DBF_DEBUG ,
" %s: %s: refcount = %d \n " ,
CTCM_FUNTAIL , dev - > name , atomic_read ( & dev - > refcnt ) ) ;
2008-02-08 00:03:49 +01:00
fsm_deltimer ( & priv - > restart_timer ) ;
grp - > channels_terminating = 0 ;
fsm_deltimer ( & grp - > timer ) ;
grp - > allochanfunc = NULL ;
grp - > estconnfunc = NULL ;
grp - > port_persist = 0 ;
grp - > send_qllc_disc = 0 ;
fsm_event ( grp - > fsm , MPCG_EVENT_INOP , dev ) ;
ctcm_close ( dev ) ;
return ;
}
EXPORT_SYMBOL ( ctc_mpc_dealloc_ch ) ;
/*
* ctc_mpc_flow_control
* ( exported interface )
*/
void ctc_mpc_flow_control ( int port_num , int flowc )
{
struct ctcm_priv * priv ;
struct mpc_group * grp ;
struct net_device * dev ;
struct channel * rch ;
int mpcg_state ;
2008-07-18 15:24:57 +02:00
dev = ctcmpc_get_dev ( port_num ) ;
if ( dev = = NULL )
2008-02-08 00:03:49 +01:00
return ;
2008-08-21 17:10:24 +02:00
priv = dev - > ml_priv ;
2008-07-18 15:24:57 +02:00
grp = priv - > mpcg ;
2008-02-08 00:03:49 +01:00
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_TRACE , CTC_DBF_DEBUG ,
" %s: %s: flowc = %d " ,
CTCM_FUNTAIL , dev - > name , flowc ) ;
2008-02-08 00:03:49 +01:00
rch = priv - > channel [ READ ] ;
mpcg_state = fsm_getstate ( grp - > fsm ) ;
switch ( flowc ) {
case 1 :
if ( mpcg_state = = MPCG_STATE_FLOWC )
break ;
if ( mpcg_state = = MPCG_STATE_READY ) {
if ( grp - > flow_off_called = = 1 )
grp - > flow_off_called = 0 ;
else
fsm_newstate ( grp - > fsm , MPCG_STATE_FLOWC ) ;
break ;
}
break ;
case 0 :
if ( mpcg_state = = MPCG_STATE_FLOWC ) {
fsm_newstate ( grp - > fsm , MPCG_STATE_READY ) ;
/* ensure any data that has accumulated */
/* on the io_queue will now be sen t */
tasklet_schedule ( & rch - > ch_tasklet ) ;
}
/* possible race condition */
if ( mpcg_state = = MPCG_STATE_READY ) {
grp - > flow_off_called = 1 ;
break ;
}
break ;
}
}
EXPORT_SYMBOL ( ctc_mpc_flow_control ) ;
static int mpc_send_qllc_discontact ( struct net_device * ) ;
/*
* helper function of ctcmpc_unpack_skb
*/
static void mpc_rcvd_sweep_resp ( struct mpcg_info * mpcginfo )
{
struct channel * rch = mpcginfo - > ch ;
struct net_device * dev = rch - > netdev ;
2008-08-21 17:10:24 +02:00
struct ctcm_priv * priv = dev - > ml_priv ;
2008-02-08 00:03:49 +01:00
struct mpc_group * grp = priv - > mpcg ;
struct channel * ch = priv - > channel [ WRITE ] ;
2008-07-18 15:24:57 +02:00
CTCM_PR_DEBUG ( " %s: ch=0x%p id=%s \n " , __func__ , ch , ch - > id ) ;
CTCM_D3_DUMP ( ( char * ) mpcginfo - > sweep , TH_SWEEP_LENGTH ) ;
2008-02-08 00:03:49 +01:00
grp - > sweep_rsp_pend_num - - ;
if ( ( grp - > sweep_req_pend_num = = 0 ) & &
( grp - > sweep_rsp_pend_num = = 0 ) ) {
fsm_deltimer ( & ch - > sweep_timer ) ;
grp - > in_sweep = 0 ;
rch - > th_seq_num = 0x00 ;
ch - > th_seq_num = 0x00 ;
ctcm_clear_busy_do ( dev ) ;
}
kfree ( mpcginfo ) ;
return ;
}
/*
* helper function of mpc_rcvd_sweep_req
* which is a helper of ctcmpc_unpack_skb
*/
static void ctcmpc_send_sweep_resp ( struct channel * rch )
{
struct net_device * dev = rch - > netdev ;
2008-08-21 17:10:24 +02:00
struct ctcm_priv * priv = dev - > ml_priv ;
2008-02-08 00:03:49 +01:00
struct mpc_group * grp = priv - > mpcg ;
int rc = 0 ;
struct th_sweep * header ;
struct sk_buff * sweep_skb ;
struct channel * ch = priv - > channel [ WRITE ] ;
2008-07-18 15:24:57 +02:00
CTCM_PR_DEBUG ( " %s: ch=0x%p id=%s \n " , __func__ , rch , rch - > id ) ;
2008-02-08 00:03:49 +01:00
2008-07-18 15:24:57 +02:00
sweep_skb = __dev_alloc_skb ( MPC_BUFSIZE_DEFAULT , GFP_ATOMIC | GFP_DMA ) ;
2008-02-08 00:03:49 +01:00
if ( sweep_skb = = NULL ) {
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): sweep_skb allocation ERROR \n " ,
CTCM_FUNTAIL , rch - > id ) ;
2008-02-08 00:03:49 +01:00
rc = - ENOMEM ;
goto done ;
}
header = ( struct th_sweep * )
kmalloc ( sizeof ( struct th_sweep ) , gfp_type ( ) ) ;
if ( ! header ) {
dev_kfree_skb_any ( sweep_skb ) ;
rc = - ENOMEM ;
goto done ;
}
header - > th . th_seg = 0x00 ;
header - > th . th_ch_flag = TH_SWEEP_RESP ;
header - > th . th_blk_flag = 0x00 ;
header - > th . th_is_xid = 0x00 ;
header - > th . th_seq_num = 0x00 ;
header - > sw . th_last_seq = ch - > th_seq_num ;
memcpy ( skb_put ( sweep_skb , TH_SWEEP_LENGTH ) , header , TH_SWEEP_LENGTH ) ;
kfree ( header ) ;
dev - > trans_start = jiffies ;
skb_queue_tail ( & ch - > sweep_queue , sweep_skb ) ;
fsm_addtimer ( & ch - > sweep_timer , 100 , CTC_EVENT_RSWEEP_TIMER , ch ) ;
return ;
done :
2009-03-24 03:27:49 +00:00
grp - > in_sweep = 0 ;
ctcm_clear_busy_do ( dev ) ;
fsm_event ( grp - > fsm , MPCG_EVENT_INOP , dev ) ;
2008-02-08 00:03:49 +01:00
return ;
}
/*
* helper function of ctcmpc_unpack_skb
*/
static void mpc_rcvd_sweep_req ( struct mpcg_info * mpcginfo )
{
struct channel * rch = mpcginfo - > ch ;
struct net_device * dev = rch - > netdev ;
2008-08-21 17:10:24 +02:00
struct ctcm_priv * priv = dev - > ml_priv ;
2008-02-08 00:03:49 +01:00
struct mpc_group * grp = priv - > mpcg ;
struct channel * ch = priv - > channel [ WRITE ] ;
if ( do_debug )
CTCM_DBF_TEXT_ ( MPC_TRACE , CTC_DBF_DEBUG ,
2008-07-18 15:24:57 +02:00
" %s(): ch=0x%p id=%s \n " , __func__ , ch , ch - > id ) ;
2008-02-08 00:03:49 +01:00
if ( grp - > in_sweep = = 0 ) {
grp - > in_sweep = 1 ;
ctcm_test_and_set_busy ( dev ) ;
grp - > sweep_req_pend_num = grp - > active_channels [ READ ] ;
grp - > sweep_rsp_pend_num = grp - > active_channels [ READ ] ;
}
2008-07-18 15:24:57 +02:00
CTCM_D3_DUMP ( ( char * ) mpcginfo - > sweep , TH_SWEEP_LENGTH ) ;
2008-02-08 00:03:49 +01:00
grp - > sweep_req_pend_num - - ;
ctcmpc_send_sweep_resp ( ch ) ;
kfree ( mpcginfo ) ;
return ;
}
/*
* MPC Group Station FSM definitions
*/
static const char * mpcg_event_names [ ] = {
[ MPCG_EVENT_INOP ] = " INOP Condition " ,
[ MPCG_EVENT_DISCONC ] = " Discontact Received " ,
[ MPCG_EVENT_XID0DO ] = " Channel Active - Start XID " ,
[ MPCG_EVENT_XID2 ] = " XID2 Received " ,
[ MPCG_EVENT_XID2DONE ] = " XID0 Complete " ,
[ MPCG_EVENT_XID7DONE ] = " XID7 Complete " ,
[ MPCG_EVENT_TIMER ] = " XID Setup Timer " ,
[ MPCG_EVENT_DOIO ] = " XID DoIO " ,
} ;
static const char * mpcg_state_names [ ] = {
[ MPCG_STATE_RESET ] = " Reset " ,
[ MPCG_STATE_INOP ] = " INOP " ,
[ MPCG_STATE_XID2INITW ] = " Passive XID- XID0 Pending Start " ,
[ MPCG_STATE_XID2INITX ] = " Passive XID- XID0 Pending Complete " ,
[ MPCG_STATE_XID7INITW ] = " Passive XID- XID7 Pending P1 Start " ,
[ MPCG_STATE_XID7INITX ] = " Passive XID- XID7 Pending P2 Complete " ,
[ MPCG_STATE_XID0IOWAIT ] = " Active XID- XID0 Pending Start " ,
[ MPCG_STATE_XID0IOWAIX ] = " Active XID- XID0 Pending Complete " ,
[ MPCG_STATE_XID7INITI ] = " Active XID- XID7 Pending Start " ,
[ MPCG_STATE_XID7INITZ ] = " Active XID- XID7 Pending Complete " ,
[ MPCG_STATE_XID7INITF ] = " XID - XID7 Complete " ,
[ MPCG_STATE_FLOWC ] = " FLOW CONTROL ON " ,
[ MPCG_STATE_READY ] = " READY " ,
} ;
/*
* The MPC Group Station FSM
* 22 events
*/
static const fsm_node mpcg_fsm [ ] = {
{ MPCG_STATE_RESET , MPCG_EVENT_INOP , mpc_action_go_inop } ,
{ MPCG_STATE_INOP , MPCG_EVENT_INOP , mpc_action_nop } ,
{ MPCG_STATE_FLOWC , MPCG_EVENT_INOP , mpc_action_go_inop } ,
{ MPCG_STATE_READY , MPCG_EVENT_DISCONC , mpc_action_discontact } ,
{ MPCG_STATE_READY , MPCG_EVENT_INOP , mpc_action_go_inop } ,
{ MPCG_STATE_XID2INITW , MPCG_EVENT_XID0DO , mpc_action_doxid0 } ,
{ MPCG_STATE_XID2INITW , MPCG_EVENT_XID2 , mpc_action_rcvd_xid0 } ,
{ MPCG_STATE_XID2INITW , MPCG_EVENT_INOP , mpc_action_go_inop } ,
{ MPCG_STATE_XID2INITW , MPCG_EVENT_TIMER , mpc_action_timeout } ,
{ MPCG_STATE_XID2INITW , MPCG_EVENT_DOIO , mpc_action_yside_xid } ,
{ MPCG_STATE_XID2INITX , MPCG_EVENT_XID0DO , mpc_action_doxid0 } ,
{ MPCG_STATE_XID2INITX , MPCG_EVENT_XID2 , mpc_action_rcvd_xid0 } ,
{ MPCG_STATE_XID2INITX , MPCG_EVENT_INOP , mpc_action_go_inop } ,
{ MPCG_STATE_XID2INITX , MPCG_EVENT_TIMER , mpc_action_timeout } ,
{ MPCG_STATE_XID2INITX , MPCG_EVENT_DOIO , mpc_action_yside_xid } ,
{ MPCG_STATE_XID7INITW , MPCG_EVENT_XID2DONE , mpc_action_doxid7 } ,
{ MPCG_STATE_XID7INITW , MPCG_EVENT_DISCONC , mpc_action_discontact } ,
{ MPCG_STATE_XID7INITW , MPCG_EVENT_XID2 , mpc_action_rcvd_xid7 } ,
{ MPCG_STATE_XID7INITW , MPCG_EVENT_INOP , mpc_action_go_inop } ,
{ MPCG_STATE_XID7INITW , MPCG_EVENT_TIMER , mpc_action_timeout } ,
{ MPCG_STATE_XID7INITW , MPCG_EVENT_XID7DONE , mpc_action_doxid7 } ,
{ MPCG_STATE_XID7INITW , MPCG_EVENT_DOIO , mpc_action_yside_xid } ,
{ MPCG_STATE_XID7INITX , MPCG_EVENT_DISCONC , mpc_action_discontact } ,
{ MPCG_STATE_XID7INITX , MPCG_EVENT_XID2 , mpc_action_rcvd_xid7 } ,
{ MPCG_STATE_XID7INITX , MPCG_EVENT_INOP , mpc_action_go_inop } ,
{ MPCG_STATE_XID7INITX , MPCG_EVENT_XID7DONE , mpc_action_doxid7 } ,
{ MPCG_STATE_XID7INITX , MPCG_EVENT_TIMER , mpc_action_timeout } ,
{ MPCG_STATE_XID7INITX , MPCG_EVENT_DOIO , mpc_action_yside_xid } ,
{ MPCG_STATE_XID0IOWAIT , MPCG_EVENT_XID0DO , mpc_action_doxid0 } ,
{ MPCG_STATE_XID0IOWAIT , MPCG_EVENT_DISCONC , mpc_action_discontact } ,
{ MPCG_STATE_XID0IOWAIT , MPCG_EVENT_XID2 , mpc_action_rcvd_xid0 } ,
{ MPCG_STATE_XID0IOWAIT , MPCG_EVENT_INOP , mpc_action_go_inop } ,
{ MPCG_STATE_XID0IOWAIT , MPCG_EVENT_TIMER , mpc_action_timeout } ,
{ MPCG_STATE_XID0IOWAIT , MPCG_EVENT_DOIO , mpc_action_xside_xid } ,
{ MPCG_STATE_XID0IOWAIX , MPCG_EVENT_XID0DO , mpc_action_doxid0 } ,
{ MPCG_STATE_XID0IOWAIX , MPCG_EVENT_DISCONC , mpc_action_discontact } ,
{ MPCG_STATE_XID0IOWAIX , MPCG_EVENT_XID2 , mpc_action_rcvd_xid0 } ,
{ MPCG_STATE_XID0IOWAIX , MPCG_EVENT_INOP , mpc_action_go_inop } ,
{ MPCG_STATE_XID0IOWAIX , MPCG_EVENT_TIMER , mpc_action_timeout } ,
{ MPCG_STATE_XID0IOWAIX , MPCG_EVENT_DOIO , mpc_action_xside_xid } ,
{ MPCG_STATE_XID7INITI , MPCG_EVENT_XID2DONE , mpc_action_doxid7 } ,
{ MPCG_STATE_XID7INITI , MPCG_EVENT_XID2 , mpc_action_rcvd_xid7 } ,
{ MPCG_STATE_XID7INITI , MPCG_EVENT_DISCONC , mpc_action_discontact } ,
{ MPCG_STATE_XID7INITI , MPCG_EVENT_INOP , mpc_action_go_inop } ,
{ MPCG_STATE_XID7INITI , MPCG_EVENT_TIMER , mpc_action_timeout } ,
{ MPCG_STATE_XID7INITI , MPCG_EVENT_XID7DONE , mpc_action_doxid7 } ,
{ MPCG_STATE_XID7INITI , MPCG_EVENT_DOIO , mpc_action_xside_xid } ,
{ MPCG_STATE_XID7INITZ , MPCG_EVENT_XID2 , mpc_action_rcvd_xid7 } ,
{ MPCG_STATE_XID7INITZ , MPCG_EVENT_XID7DONE , mpc_action_doxid7 } ,
{ MPCG_STATE_XID7INITZ , MPCG_EVENT_DISCONC , mpc_action_discontact } ,
{ MPCG_STATE_XID7INITZ , MPCG_EVENT_INOP , mpc_action_go_inop } ,
{ MPCG_STATE_XID7INITZ , MPCG_EVENT_TIMER , mpc_action_timeout } ,
{ MPCG_STATE_XID7INITZ , MPCG_EVENT_DOIO , mpc_action_xside_xid } ,
{ MPCG_STATE_XID7INITF , MPCG_EVENT_INOP , mpc_action_go_inop } ,
{ MPCG_STATE_XID7INITF , MPCG_EVENT_XID7DONE , mpc_action_go_ready } ,
} ;
static int mpcg_fsm_len = ARRAY_SIZE ( mpcg_fsm ) ;
/*
* MPC Group Station FSM action
* CTCM_PROTO_MPC only
*/
static void mpc_action_go_ready ( fsm_instance * fsm , int event , void * arg )
{
struct net_device * dev = arg ;
2008-08-21 17:10:24 +02:00
struct ctcm_priv * priv = dev - > ml_priv ;
2008-07-18 15:24:57 +02:00
struct mpc_group * grp = priv - > mpcg ;
2008-02-08 00:03:49 +01:00
if ( grp = = NULL ) {
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): No MPC group " ,
CTCM_FUNTAIL , dev - > name ) ;
2008-02-08 00:03:49 +01:00
return ;
}
fsm_deltimer ( & grp - > timer ) ;
if ( grp - > saved_xid2 - > xid2_flag2 = = 0x40 ) {
priv - > xid - > xid2_flag2 = 0x00 ;
if ( grp - > estconnfunc ) {
grp - > estconnfunc ( grp - > port_num , 1 ,
grp - > group_max_buflen ) ;
grp - > estconnfunc = NULL ;
} else if ( grp - > allochanfunc )
grp - > send_qllc_disc = 1 ;
2008-07-18 15:24:57 +02:00
fsm_event ( grp - > fsm , MPCG_EVENT_INOP , dev ) ;
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): fails " ,
CTCM_FUNTAIL , dev - > name ) ;
return ;
2008-02-08 00:03:49 +01:00
}
grp - > port_persist = 1 ;
grp - > out_of_sequence = 0 ;
grp - > estconn_called = 0 ;
tasklet_hi_schedule ( & grp - > mpc_tasklet2 ) ;
return ;
}
/*
* helper of ctcm_init_netdevice
* CTCM_PROTO_MPC only
*/
void mpc_group_ready ( unsigned long adev )
{
struct net_device * dev = ( struct net_device * ) adev ;
2008-08-21 17:10:24 +02:00
struct ctcm_priv * priv = dev - > ml_priv ;
2008-07-18 15:24:57 +02:00
struct mpc_group * grp = priv - > mpcg ;
2008-02-08 00:03:49 +01:00
struct channel * ch = NULL ;
if ( grp = = NULL ) {
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): No MPC group " ,
CTCM_FUNTAIL , dev - > name ) ;
2008-02-08 00:03:49 +01:00
return ;
}
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_SETUP , CTC_DBF_NOTICE ,
" %s: %s: GROUP TRANSITIONED TO READY, maxbuf = %d \n " ,
CTCM_FUNTAIL , dev - > name , grp - > group_max_buflen ) ;
2008-02-08 00:03:49 +01:00
fsm_newstate ( grp - > fsm , MPCG_STATE_READY ) ;
/* Put up a read on the channel */
ch = priv - > channel [ READ ] ;
ch - > pdu_seq = 0 ;
2008-07-18 15:24:57 +02:00
CTCM_PR_DBGDATA ( " ctcmpc: %s() ToDCM_pdu_seq= %08x \n " ,
__func__ , ch - > pdu_seq ) ;
2008-02-08 00:03:49 +01:00
ctcmpc_chx_rxidle ( ch - > fsm , CTC_EVENT_START , ch ) ;
/* Put the write channel in idle state */
ch = priv - > channel [ WRITE ] ;
if ( ch - > collect_len > 0 ) {
spin_lock ( & ch - > collect_lock ) ;
ctcm_purge_skb_queue ( & ch - > collect_queue ) ;
ch - > collect_len = 0 ;
spin_unlock ( & ch - > collect_lock ) ;
}
ctcm_chx_txidle ( ch - > fsm , CTC_EVENT_START , ch ) ;
ctcm_clear_busy ( dev ) ;
if ( grp - > estconnfunc ) {
grp - > estconnfunc ( grp - > port_num , 0 ,
grp - > group_max_buflen ) ;
grp - > estconnfunc = NULL ;
2008-07-18 15:24:57 +02:00
} else if ( grp - > allochanfunc )
grp - > allochanfunc ( grp - > port_num , grp - > group_max_buflen ) ;
2008-02-08 00:03:49 +01:00
grp - > send_qllc_disc = 1 ;
grp - > changed_side = 0 ;
return ;
}
/*
* Increment the MPC Group Active Channel Counts
* helper of dev_action ( called from channel fsm )
*/
2008-07-18 15:24:57 +02:00
void mpc_channel_action ( struct channel * ch , int direction , int action )
2008-02-08 00:03:49 +01:00
{
2008-07-18 15:24:57 +02:00
struct net_device * dev = ch - > netdev ;
2008-08-21 17:10:24 +02:00
struct ctcm_priv * priv = dev - > ml_priv ;
2008-07-18 15:24:57 +02:00
struct mpc_group * grp = priv - > mpcg ;
2008-02-08 00:03:49 +01:00
if ( grp = = NULL ) {
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): No MPC group " ,
CTCM_FUNTAIL , dev - > name ) ;
return ;
2008-02-08 00:03:49 +01:00
}
2008-07-18 15:24:57 +02:00
CTCM_PR_DEBUG ( " enter %s: ch=0x%p id=%s \n " , __func__ , ch , ch - > id ) ;
CTCM_DBF_TEXT_ ( MPC_TRACE , CTC_DBF_NOTICE ,
" %s: %i / Grp:%s total_channels=%i, active_channels: "
" read=%i, write=%i \n " , __func__ , action ,
fsm_getstate_str ( grp - > fsm ) , grp - > num_channel_paths ,
grp - > active_channels [ READ ] , grp - > active_channels [ WRITE ] ) ;
2008-02-08 00:03:49 +01:00
if ( ( action = = MPC_CHANNEL_ADD ) & & ( ch - > in_mpcgroup = = 0 ) ) {
grp - > num_channel_paths + + ;
grp - > active_channels [ direction ] + + ;
grp - > outstanding_xid2 + + ;
ch - > in_mpcgroup = 1 ;
if ( ch - > xid_skb ! = NULL )
dev_kfree_skb_any ( ch - > xid_skb ) ;
ch - > xid_skb = __dev_alloc_skb ( MPC_BUFSIZE_DEFAULT ,
GFP_ATOMIC | GFP_DMA ) ;
if ( ch - > xid_skb = = NULL ) {
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): Couldn't alloc ch xid_skb \n " ,
CTCM_FUNTAIL , dev - > name ) ;
2008-02-08 00:03:49 +01:00
fsm_event ( grp - > fsm , MPCG_EVENT_INOP , dev ) ;
2008-07-18 15:24:57 +02:00
return ;
2008-02-08 00:03:49 +01:00
}
ch - > xid_skb_data = ch - > xid_skb - > data ;
ch - > xid_th = ( struct th_header * ) ch - > xid_skb - > data ;
skb_put ( ch - > xid_skb , TH_HEADER_LENGTH ) ;
ch - > xid = ( struct xid2 * ) skb_tail_pointer ( ch - > xid_skb ) ;
skb_put ( ch - > xid_skb , XID2_LENGTH ) ;
ch - > xid_id = skb_tail_pointer ( ch - > xid_skb ) ;
ch - > xid_skb - > data = ch - > xid_skb_data ;
skb_reset_tail_pointer ( ch - > xid_skb ) ;
ch - > xid_skb - > len = 0 ;
memcpy ( skb_put ( ch - > xid_skb , grp - > xid_skb - > len ) ,
grp - > xid_skb - > data ,
grp - > xid_skb - > len ) ;
ch - > xid - > xid2_dlc_type = ( ( CHANNEL_DIRECTION ( ch - > flags ) = = READ )
? XID2_READ_SIDE : XID2_WRITE_SIDE ) ;
if ( CHANNEL_DIRECTION ( ch - > flags ) = = WRITE )
ch - > xid - > xid2_buf_len = 0x00 ;
ch - > xid_skb - > data = ch - > xid_skb_data ;
skb_reset_tail_pointer ( ch - > xid_skb ) ;
ch - > xid_skb - > len = 0 ;
fsm_newstate ( ch - > fsm , CH_XID0_PENDING ) ;
if ( ( grp - > active_channels [ READ ] > 0 ) & &
( grp - > active_channels [ WRITE ] > 0 ) & &
( fsm_getstate ( grp - > fsm ) < MPCG_STATE_XID2INITW ) ) {
fsm_newstate ( grp - > fsm , MPCG_STATE_XID2INITW ) ;
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_SETUP , CTC_DBF_NOTICE ,
" %s: %s: MPC GROUP CHANNELS ACTIVE \n " ,
__func__ , dev - > name ) ;
2008-02-08 00:03:49 +01:00
}
} else if ( ( action = = MPC_CHANNEL_REMOVE ) & &
( ch - > in_mpcgroup = = 1 ) ) {
ch - > in_mpcgroup = 0 ;
grp - > num_channel_paths - - ;
grp - > active_channels [ direction ] - - ;
if ( ch - > xid_skb ! = NULL )
dev_kfree_skb_any ( ch - > xid_skb ) ;
ch - > xid_skb = NULL ;
if ( grp - > channels_terminating )
goto done ;
if ( ( ( grp - > active_channels [ READ ] = = 0 ) & &
( grp - > active_channels [ WRITE ] > 0 ) )
| | ( ( grp - > active_channels [ WRITE ] = = 0 ) & &
( grp - > active_channels [ READ ] > 0 ) ) )
fsm_event ( grp - > fsm , MPCG_EVENT_INOP , dev ) ;
}
done :
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_TRACE , CTC_DBF_DEBUG ,
" exit %s: %i / Grp:%s total_channels=%i, active_channels: "
" read=%i, write=%i \n " , __func__ , action ,
fsm_getstate_str ( grp - > fsm ) , grp - > num_channel_paths ,
grp - > active_channels [ READ ] , grp - > active_channels [ WRITE ] ) ;
2008-02-08 00:03:49 +01:00
2008-07-18 15:24:57 +02:00
CTCM_PR_DEBUG ( " exit %s: ch=0x%p id=%s \n " , __func__ , ch , ch - > id ) ;
2008-02-08 00:03:49 +01:00
}
/**
* Unpack a just received skb and hand it over to
* upper layers .
* special MPC version of unpack_skb .
*
* ch The channel where this skb has been received .
* pskb The received skb .
*/
static void ctcmpc_unpack_skb ( struct channel * ch , struct sk_buff * pskb )
{
struct net_device * dev = ch - > netdev ;
2008-08-21 17:10:24 +02:00
struct ctcm_priv * priv = dev - > ml_priv ;
2008-02-08 00:03:49 +01:00
struct mpc_group * grp = priv - > mpcg ;
struct pdu * curr_pdu ;
struct mpcg_info * mpcginfo ;
struct th_header * header = NULL ;
struct th_sweep * sweep = NULL ;
int pdu_last_seen = 0 ;
__u32 new_len ;
struct sk_buff * skb ;
int skblen ;
int sendrc = 0 ;
2008-07-18 15:24:57 +02:00
CTCM_PR_DEBUG ( " ctcmpc enter: %s() %s cp:%i ch:%s \n " ,
__func__ , dev - > name , smp_processor_id ( ) , ch - > id ) ;
2008-02-08 00:03:49 +01:00
header = ( struct th_header * ) pskb - > data ;
if ( ( header - > th_seg = = 0 ) & &
( header - > th_ch_flag = = 0 ) & &
( header - > th_blk_flag = = 0 ) & &
( header - > th_seq_num = = 0 ) )
/* nothing for us */ goto done ;
2008-07-18 15:24:57 +02:00
CTCM_PR_DBGDATA ( " %s: th_header \n " , __func__ ) ;
CTCM_D3_DUMP ( ( char * ) header , TH_HEADER_LENGTH ) ;
CTCM_PR_DBGDATA ( " %s: pskb len: %04x \n " , __func__ , pskb - > len ) ;
2008-02-08 00:03:49 +01:00
pskb - > dev = dev ;
pskb - > ip_summed = CHECKSUM_UNNECESSARY ;
skb_pull ( pskb , TH_HEADER_LENGTH ) ;
if ( likely ( header - > th_ch_flag = = TH_HAS_PDU ) ) {
2008-07-18 15:24:57 +02:00
CTCM_PR_DBGDATA ( " %s: came into th_has_pdu \n " , __func__ ) ;
2008-02-08 00:03:49 +01:00
if ( ( fsm_getstate ( grp - > fsm ) = = MPCG_STATE_FLOWC ) | |
( ( fsm_getstate ( grp - > fsm ) = = MPCG_STATE_READY ) & &
( header - > th_seq_num ! = ch - > th_seq_num + 1 ) & &
( ch - > th_seq_num ! = 0 ) ) ) {
/* This is NOT the next segment *
* we are not the correct race winner *
* go away and let someone else win *
* BUT . . this only applies if xid negot *
* is done *
*/
grp - > out_of_sequence + = 1 ;
__skb_push ( pskb , TH_HEADER_LENGTH ) ;
skb_queue_tail ( & ch - > io_queue , pskb ) ;
2008-07-18 15:24:57 +02:00
CTCM_PR_DBGDATA ( " %s: th_seq_num expect:%08x "
" got:%08x \n " , __func__ ,
ch - > th_seq_num + 1 , header - > th_seq_num ) ;
2008-02-08 00:03:49 +01:00
return ;
}
grp - > out_of_sequence = 0 ;
ch - > th_seq_num = header - > th_seq_num ;
2008-07-18 15:24:57 +02:00
CTCM_PR_DBGDATA ( " ctcmpc: %s() FromVTAM_th_seq=%08x \n " ,
__func__ , ch - > th_seq_num ) ;
2008-02-08 00:03:49 +01:00
if ( unlikely ( fsm_getstate ( grp - > fsm ) ! = MPCG_STATE_READY ) )
goto done ;
while ( ( pskb - > len > 0 ) & & ! pdu_last_seen ) {
curr_pdu = ( struct pdu * ) pskb - > data ;
2008-07-18 15:24:57 +02:00
CTCM_PR_DBGDATA ( " %s: pdu_header \n " , __func__ ) ;
CTCM_D3_DUMP ( ( char * ) pskb - > data , PDU_HEADER_LENGTH ) ;
CTCM_PR_DBGDATA ( " %s: pskb len: %04x \n " ,
__func__ , pskb - > len ) ;
2008-02-08 00:03:49 +01:00
skb_pull ( pskb , PDU_HEADER_LENGTH ) ;
if ( curr_pdu - > pdu_flag & PDU_LAST )
pdu_last_seen = 1 ;
if ( curr_pdu - > pdu_flag & PDU_CNTL )
pskb - > protocol = htons ( ETH_P_SNAP ) ;
else
pskb - > protocol = htons ( ETH_P_SNA_DIX ) ;
if ( ( pskb - > len < = 0 ) | | ( pskb - > len > ch - > max_bufsize ) ) {
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): Dropping packet with "
" illegal siize %d " ,
CTCM_FUNTAIL , dev - > name , pskb - > len ) ;
2008-02-08 00:03:49 +01:00
priv - > stats . rx_dropped + + ;
priv - > stats . rx_length_errors + + ;
goto done ;
}
skb_reset_mac_header ( pskb ) ;
new_len = curr_pdu - > pdu_offset ;
2008-07-18 15:24:57 +02:00
CTCM_PR_DBGDATA ( " %s: new_len: %04x \n " ,
__func__ , new_len ) ;
2008-02-08 00:03:49 +01:00
if ( ( new_len = = 0 ) | | ( new_len > pskb - > len ) ) {
/* should never happen */
/* pskb len must be hosed...bail out */
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): non valid pdu_offset: %04x " ,
/* "data may be lost", */
CTCM_FUNTAIL , dev - > name , new_len ) ;
goto done ;
2008-02-08 00:03:49 +01:00
}
skb = __dev_alloc_skb ( new_len + 4 , GFP_ATOMIC ) ;
if ( ! skb ) {
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): MEMORY allocation error " ,
CTCM_FUNTAIL , dev - > name ) ;
2008-02-08 00:03:49 +01:00
priv - > stats . rx_dropped + + ;
2008-07-18 15:24:57 +02:00
fsm_event ( grp - > fsm , MPCG_EVENT_INOP , dev ) ;
2008-02-08 00:03:49 +01:00
goto done ;
}
2008-07-18 15:24:57 +02:00
memcpy ( skb_put ( skb , new_len ) , pskb - > data , new_len ) ;
2008-02-08 00:03:49 +01:00
skb_reset_mac_header ( skb ) ;
skb - > dev = pskb - > dev ;
skb - > protocol = pskb - > protocol ;
skb - > ip_summed = CHECKSUM_UNNECESSARY ;
* ( ( __u32 * ) skb_push ( skb , 4 ) ) = ch - > pdu_seq ;
ch - > pdu_seq + + ;
if ( do_debug_data ) {
2008-07-18 15:24:57 +02:00
ctcm_pr_debug ( " %s: ToDCM_pdu_seq= %08x \n " ,
__func__ , ch - > pdu_seq ) ;
ctcm_pr_debug ( " %s: skb:%0lx "
" skb len: %d \n " , __func__ ,
( unsigned long ) skb , skb - > len ) ;
ctcm_pr_debug ( " %s: up to 32 bytes "
" of pdu_data sent \n " , __func__ ) ;
2008-02-08 00:03:49 +01:00
ctcmpc_dump32 ( ( char * ) skb - > data , skb - > len ) ;
}
skblen = skb - > len ;
sendrc = netif_rx ( skb ) ;
priv - > stats . rx_packets + + ;
priv - > stats . rx_bytes + = skblen ;
skb_pull ( pskb , new_len ) ; /* point to next PDU */
}
} else {
mpcginfo = ( struct mpcg_info * )
kmalloc ( sizeof ( struct mpcg_info ) , gfp_type ( ) ) ;
if ( mpcginfo = = NULL )
goto done ;
mpcginfo - > ch = ch ;
mpcginfo - > th = header ;
mpcginfo - > skb = pskb ;
2008-07-18 15:24:57 +02:00
CTCM_PR_DEBUG ( " %s: Not PDU - may be control pkt \n " ,
__func__ ) ;
2008-02-08 00:03:49 +01:00
/* it's a sweep? */
sweep = ( struct th_sweep * ) pskb - > data ;
mpcginfo - > sweep = sweep ;
if ( header - > th_ch_flag = = TH_SWEEP_REQ )
mpc_rcvd_sweep_req ( mpcginfo ) ;
else if ( header - > th_ch_flag = = TH_SWEEP_RESP )
mpc_rcvd_sweep_resp ( mpcginfo ) ;
else if ( header - > th_blk_flag = = TH_DATA_IS_XID ) {
struct xid2 * thisxid = ( struct xid2 * ) pskb - > data ;
skb_pull ( pskb , XID2_LENGTH ) ;
mpcginfo - > xid = thisxid ;
fsm_event ( grp - > fsm , MPCG_EVENT_XID2 , mpcginfo ) ;
} else if ( header - > th_blk_flag = = TH_DISCONTACT )
fsm_event ( grp - > fsm , MPCG_EVENT_DISCONC , mpcginfo ) ;
else if ( header - > th_seq_num ! = 0 ) {
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): control pkt expected \n " ,
CTCM_FUNTAIL , dev - > name ) ;
2008-02-08 00:03:49 +01:00
priv - > stats . rx_dropped + + ;
/* mpcginfo only used for non-data transfers */
kfree ( mpcginfo ) ;
if ( do_debug_data )
ctcmpc_dump_skb ( pskb , - 8 ) ;
}
}
done :
dev_kfree_skb_any ( pskb ) ;
if ( sendrc = = NET_RX_DROP ) {
2008-12-25 13:39:54 +01:00
dev_warn ( & dev - > dev ,
" The network backlog for %s is exceeded, "
" package dropped \n " , __func__ ) ;
2008-02-08 00:03:49 +01:00
fsm_event ( grp - > fsm , MPCG_EVENT_INOP , dev ) ;
}
2008-07-18 15:24:57 +02:00
CTCM_PR_DEBUG ( " exit %s: %s: ch=0x%p id=%s \n " ,
__func__ , dev - > name , ch , ch - > id ) ;
2008-02-08 00:03:49 +01:00
}
/**
* tasklet helper for mpc ' s skb unpacking .
*
* ch The channel to work on .
* Allow flow control back pressure to occur here .
* Throttling back channel can result in excessive
* channel inactivity and system deact of channel
*/
void ctcmpc_bh ( unsigned long thischan )
{
2008-07-18 15:24:57 +02:00
struct channel * ch = ( struct channel * ) thischan ;
2008-02-08 00:03:49 +01:00
struct sk_buff * skb ;
2008-07-18 15:24:57 +02:00
struct net_device * dev = ch - > netdev ;
2008-08-21 17:10:24 +02:00
struct ctcm_priv * priv = dev - > ml_priv ;
2008-07-18 15:24:57 +02:00
struct mpc_group * grp = priv - > mpcg ;
2008-02-08 00:03:49 +01:00
2008-07-18 15:24:57 +02:00
CTCM_PR_DEBUG ( " %s cp:%i enter: %s() %s \n " ,
dev - > name , smp_processor_id ( ) , __func__ , ch - > id ) ;
2008-02-08 00:03:49 +01:00
/* caller has requested driver to throttle back */
while ( ( fsm_getstate ( grp - > fsm ) ! = MPCG_STATE_FLOWC ) & &
( skb = skb_dequeue ( & ch - > io_queue ) ) ) {
ctcmpc_unpack_skb ( ch , skb ) ;
if ( grp - > out_of_sequence > 20 ) {
/* assume data loss has occurred if */
/* missing seq_num for extended */
/* period of time */
grp - > out_of_sequence = 0 ;
fsm_event ( grp - > fsm , MPCG_EVENT_INOP , dev ) ;
break ;
}
if ( skb = = skb_peek ( & ch - > io_queue ) )
break ;
}
2008-07-18 15:24:57 +02:00
CTCM_PR_DEBUG ( " exit %s: %s: ch=0x%p id=%s \n " ,
__func__ , dev - > name , ch , ch - > id ) ;
2008-02-08 00:03:49 +01:00
return ;
}
/*
* MPC Group Initializations
*/
struct mpc_group * ctcmpc_init_mpc_group ( struct ctcm_priv * priv )
{
struct mpc_group * grp ;
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_SETUP , CTC_DBF_INFO ,
" Enter %s(%p) " , CTCM_FUNTAIL , priv ) ;
2008-02-08 00:03:49 +01:00
grp = kzalloc ( sizeof ( struct mpc_group ) , GFP_KERNEL ) ;
if ( grp = = NULL )
return NULL ;
2008-07-18 15:24:57 +02:00
grp - > fsm = init_fsm ( " mpcg " , mpcg_state_names , mpcg_event_names ,
MPCG_NR_STATES , MPCG_NR_EVENTS , mpcg_fsm ,
mpcg_fsm_len , GFP_KERNEL ) ;
2008-02-08 00:03:49 +01:00
if ( grp - > fsm = = NULL ) {
kfree ( grp ) ;
return NULL ;
}
fsm_newstate ( grp - > fsm , MPCG_STATE_RESET ) ;
fsm_settimer ( grp - > fsm , & grp - > timer ) ;
grp - > xid_skb =
__dev_alloc_skb ( MPC_BUFSIZE_DEFAULT , GFP_ATOMIC | GFP_DMA ) ;
if ( grp - > xid_skb = = NULL ) {
kfree_fsm ( grp - > fsm ) ;
kfree ( grp ) ;
return NULL ;
}
/* base xid for all channels in group */
grp - > xid_skb_data = grp - > xid_skb - > data ;
grp - > xid_th = ( struct th_header * ) grp - > xid_skb - > data ;
memcpy ( skb_put ( grp - > xid_skb , TH_HEADER_LENGTH ) ,
& thnorm , TH_HEADER_LENGTH ) ;
2008-07-18 15:24:57 +02:00
grp - > xid = ( struct xid2 * ) skb_tail_pointer ( grp - > xid_skb ) ;
2008-02-08 00:03:49 +01:00
memcpy ( skb_put ( grp - > xid_skb , XID2_LENGTH ) , & init_xid , XID2_LENGTH ) ;
grp - > xid - > xid2_adj_id = jiffies | 0xfff00000 ;
grp - > xid - > xid2_sender_id = jiffies ;
grp - > xid_id = skb_tail_pointer ( grp - > xid_skb ) ;
memcpy ( skb_put ( grp - > xid_skb , 4 ) , " VTAM " , 4 ) ;
grp - > rcvd_xid_skb =
__dev_alloc_skb ( MPC_BUFSIZE_DEFAULT , GFP_ATOMIC | GFP_DMA ) ;
if ( grp - > rcvd_xid_skb = = NULL ) {
kfree_fsm ( grp - > fsm ) ;
dev_kfree_skb ( grp - > xid_skb ) ;
kfree ( grp ) ;
return NULL ;
}
grp - > rcvd_xid_data = grp - > rcvd_xid_skb - > data ;
grp - > rcvd_xid_th = ( struct th_header * ) grp - > rcvd_xid_skb - > data ;
memcpy ( skb_put ( grp - > rcvd_xid_skb , TH_HEADER_LENGTH ) ,
& thnorm , TH_HEADER_LENGTH ) ;
grp - > saved_xid2 = NULL ;
priv - > xid = grp - > xid ;
priv - > mpcg = grp ;
return grp ;
}
/*
* The MPC Group Station FSM
*/
/*
* MPC Group Station FSM actions
* CTCM_PROTO_MPC only
*/
/**
* NOP action for statemachines
*/
static void mpc_action_nop ( fsm_instance * fi , int event , void * arg )
{
}
/*
* invoked when the device transitions to dev_stopped
* MPC will stop each individual channel if a single XID failure
* occurs , or will intitiate all channels be stopped if a GROUP
* level failure occurs .
*/
static void mpc_action_go_inop ( fsm_instance * fi , int event , void * arg )
{
struct net_device * dev = arg ;
struct ctcm_priv * priv ;
struct mpc_group * grp ;
int rc = 0 ;
struct channel * wch , * rch ;
2008-07-18 15:24:57 +02:00
BUG_ON ( dev = = NULL ) ;
CTCM_PR_DEBUG ( " Enter %s: %s \n " , __func__ , dev - > name ) ;
2008-02-08 00:03:49 +01:00
2008-08-21 17:10:24 +02:00
priv = dev - > ml_priv ;
2008-02-08 00:03:49 +01:00
grp = priv - > mpcg ;
grp - > flow_off_called = 0 ;
fsm_deltimer ( & grp - > timer ) ;
if ( grp - > channels_terminating )
2008-07-18 15:24:57 +02:00
return ;
2008-02-08 00:03:49 +01:00
grp - > channels_terminating = 1 ;
grp - > saved_state = fsm_getstate ( grp - > fsm ) ;
fsm_newstate ( grp - > fsm , MPCG_STATE_INOP ) ;
if ( grp - > saved_state > MPCG_STATE_XID7INITF )
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_TRACE , CTC_DBF_NOTICE ,
" %s(%s): MPC GROUP INOPERATIVE " ,
CTCM_FUNTAIL , dev - > name ) ;
2008-02-08 00:03:49 +01:00
if ( ( grp - > saved_state ! = MPCG_STATE_RESET ) | |
/* dealloc_channel has been called */
2009-03-24 03:27:49 +00:00
( grp - > port_persist = = 0 ) )
2008-02-08 00:03:49 +01:00
fsm_deltimer ( & priv - > restart_timer ) ;
wch = priv - > channel [ WRITE ] ;
rch = priv - > channel [ READ ] ;
switch ( grp - > saved_state ) {
case MPCG_STATE_RESET :
case MPCG_STATE_INOP :
case MPCG_STATE_XID2INITW :
case MPCG_STATE_XID0IOWAIT :
case MPCG_STATE_XID2INITX :
case MPCG_STATE_XID7INITW :
case MPCG_STATE_XID7INITX :
case MPCG_STATE_XID0IOWAIX :
case MPCG_STATE_XID7INITI :
case MPCG_STATE_XID7INITZ :
case MPCG_STATE_XID7INITF :
break ;
case MPCG_STATE_FLOWC :
case MPCG_STATE_READY :
default :
tasklet_hi_schedule ( & wch - > ch_disc_tasklet ) ;
}
grp - > xid2_tgnum = 0 ;
grp - > group_max_buflen = 0 ; /*min of all received */
grp - > outstanding_xid2 = 0 ;
grp - > outstanding_xid7 = 0 ;
grp - > outstanding_xid7_p2 = 0 ;
grp - > saved_xid2 = NULL ;
grp - > xidnogood = 0 ;
grp - > changed_side = 0 ;
grp - > rcvd_xid_skb - > data = grp - > rcvd_xid_data ;
skb_reset_tail_pointer ( grp - > rcvd_xid_skb ) ;
grp - > rcvd_xid_skb - > len = 0 ;
grp - > rcvd_xid_th = ( struct th_header * ) grp - > rcvd_xid_skb - > data ;
memcpy ( skb_put ( grp - > rcvd_xid_skb , TH_HEADER_LENGTH ) , & thnorm ,
TH_HEADER_LENGTH ) ;
if ( grp - > send_qllc_disc = = 1 ) {
grp - > send_qllc_disc = 0 ;
rc = mpc_send_qllc_discontact ( dev ) ;
}
/* DO NOT issue DEV_EVENT_STOP directly out of this code */
/* This can result in INOP of VTAM PU due to halting of */
/* outstanding IO which causes a sense to be returned */
/* Only about 3 senses are allowed and then IOS/VTAM will*/
2008-07-18 15:24:57 +02:00
/* become unreachable without manual intervention */
if ( ( grp - > port_persist = = 1 ) | | ( grp - > alloc_called ) ) {
2008-02-08 00:03:49 +01:00
grp - > alloc_called = 0 ;
fsm_deltimer ( & priv - > restart_timer ) ;
2008-07-18 15:24:57 +02:00
fsm_addtimer ( & priv - > restart_timer , 500 , DEV_EVENT_RESTART , dev ) ;
2008-02-08 00:03:49 +01:00
fsm_newstate ( grp - > fsm , MPCG_STATE_RESET ) ;
if ( grp - > saved_state > MPCG_STATE_XID7INITF )
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_TRACE , CTC_DBF_ALWAYS ,
" %s(%s): MPC GROUP RECOVERY SCHEDULED " ,
CTCM_FUNTAIL , dev - > name ) ;
2008-02-08 00:03:49 +01:00
} else {
fsm_deltimer ( & priv - > restart_timer ) ;
fsm_addtimer ( & priv - > restart_timer , 500 , DEV_EVENT_STOP , dev ) ;
fsm_newstate ( grp - > fsm , MPCG_STATE_RESET ) ;
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_TRACE , CTC_DBF_ALWAYS ,
" %s(%s): NO MPC GROUP RECOVERY ATTEMPTED " ,
CTCM_FUNTAIL , dev - > name ) ;
2008-02-08 00:03:49 +01:00
}
}
/**
* Handle mpc group action timeout .
* MPC Group Station FSM action
* CTCM_PROTO_MPC only
*
* fi An instance of an mpc_group fsm .
* event The event , just happened .
* arg Generic pointer , casted from net_device * upon call .
*/
static void mpc_action_timeout ( fsm_instance * fi , int event , void * arg )
{
struct net_device * dev = arg ;
struct ctcm_priv * priv ;
struct mpc_group * grp ;
struct channel * wch ;
struct channel * rch ;
2008-07-18 15:24:57 +02:00
BUG_ON ( dev = = NULL ) ;
2008-02-08 00:03:49 +01:00
2008-08-21 17:10:24 +02:00
priv = dev - > ml_priv ;
2008-02-08 00:03:49 +01:00
grp = priv - > mpcg ;
wch = priv - > channel [ WRITE ] ;
rch = priv - > channel [ READ ] ;
switch ( fsm_getstate ( grp - > fsm ) ) {
case MPCG_STATE_XID2INITW :
/* Unless there is outstanding IO on the */
/* channel just return and wait for ATTN */
/* interrupt to begin XID negotiations */
if ( ( fsm_getstate ( rch - > fsm ) = = CH_XID0_PENDING ) & &
( fsm_getstate ( wch - > fsm ) = = CH_XID0_PENDING ) )
break ;
default :
fsm_event ( grp - > fsm , MPCG_EVENT_INOP , dev ) ;
}
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_TRACE , CTC_DBF_DEBUG ,
" %s: dev=%s exit " ,
CTCM_FUNTAIL , dev - > name ) ;
2008-02-08 00:03:49 +01:00
return ;
}
/*
* MPC Group Station FSM action
* CTCM_PROTO_MPC only
*/
void mpc_action_discontact ( fsm_instance * fi , int event , void * arg )
{
struct mpcg_info * mpcginfo = arg ;
struct channel * ch = mpcginfo - > ch ;
2008-07-18 15:24:57 +02:00
struct net_device * dev ;
struct ctcm_priv * priv ;
struct mpc_group * grp ;
2008-02-08 00:03:49 +01:00
2008-07-18 15:24:57 +02:00
if ( ch ) {
dev = ch - > netdev ;
if ( dev ) {
2008-08-21 17:10:24 +02:00
priv = dev - > ml_priv ;
2008-07-18 15:24:57 +02:00
if ( priv ) {
CTCM_DBF_TEXT_ ( MPC_TRACE , CTC_DBF_NOTICE ,
" %s: %s: %s \n " ,
CTCM_FUNTAIL , dev - > name , ch - > id ) ;
grp = priv - > mpcg ;
grp - > send_qllc_disc = 1 ;
fsm_event ( grp - > fsm , MPCG_EVENT_INOP , dev ) ;
}
}
2008-02-08 00:03:49 +01:00
}
return ;
}
/*
* MPC Group Station - not part of FSM
* CTCM_PROTO_MPC only
* called from add_channel in ctcm_main . c
*/
void mpc_action_send_discontact ( unsigned long thischan )
{
2008-07-18 15:24:57 +02:00
int rc ;
struct channel * ch = ( struct channel * ) thischan ;
unsigned long saveflags = 0 ;
2008-02-08 00:03:49 +01:00
spin_lock_irqsave ( get_ccwdev_lock ( ch - > cdev ) , saveflags ) ;
rc = ccw_device_start ( ch - > cdev , & ch - > ccw [ 15 ] ,
( unsigned long ) ch , 0xff , 0 ) ;
spin_unlock_irqrestore ( get_ccwdev_lock ( ch - > cdev ) , saveflags ) ;
if ( rc ! = 0 ) {
2008-07-18 15:24:57 +02:00
ctcm_ccw_check_rc ( ch , rc , ( char * ) __func__ ) ;
2008-02-08 00:03:49 +01:00
}
return ;
}
/*
* helper function of mpc FSM
* CTCM_PROTO_MPC only
* mpc_action_rcvd_xid7
*/
static int mpc_validate_xid ( struct mpcg_info * mpcginfo )
{
2008-07-18 15:24:57 +02:00
struct channel * ch = mpcginfo - > ch ;
struct net_device * dev = ch - > netdev ;
2008-08-21 17:10:24 +02:00
struct ctcm_priv * priv = dev - > ml_priv ;
2008-02-08 00:03:49 +01:00
struct mpc_group * grp = priv - > mpcg ;
2008-07-18 15:24:57 +02:00
struct xid2 * xid = mpcginfo - > xid ;
int rc = 0 ;
__u64 our_id = 0 ;
__u64 their_id = 0 ;
int len = TH_HEADER_LENGTH + PDU_HEADER_LENGTH ;
2008-02-08 00:03:49 +01:00
2008-07-18 15:24:57 +02:00
CTCM_PR_DEBUG ( " Enter %s: xid=%p \n " , __func__ , xid ) ;
2008-02-08 00:03:49 +01:00
2008-07-18 15:24:57 +02:00
if ( xid = = NULL ) {
2008-02-08 00:03:49 +01:00
rc = 1 ;
2008-07-18 15:24:57 +02:00
/* XID REJECTED: xid == NULL */
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): xid = NULL " ,
CTCM_FUNTAIL , ch - > id ) ;
goto done ;
2008-02-08 00:03:49 +01:00
}
2008-07-18 15:24:57 +02:00
CTCM_D3_DUMP ( ( char * ) xid , XID2_LENGTH ) ;
2008-02-08 00:03:49 +01:00
/*the received direction should be the opposite of ours */
if ( ( ( CHANNEL_DIRECTION ( ch - > flags ) = = READ ) ? XID2_WRITE_SIDE :
XID2_READ_SIDE ) ! = xid - > xid2_dlc_type ) {
2008-07-18 15:24:57 +02:00
rc = 2 ;
/* XID REJECTED: r/w channel pairing mismatch */
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): r/w channel pairing mismatch " ,
CTCM_FUNTAIL , ch - > id ) ;
goto done ;
2008-02-08 00:03:49 +01:00
}
if ( xid - > xid2_dlc_type = = XID2_READ_SIDE ) {
2008-07-18 15:24:57 +02:00
CTCM_PR_DEBUG ( " %s: grpmaxbuf:%d xid2buflen:%d \n " , __func__ ,
grp - > group_max_buflen , xid - > xid2_buf_len ) ;
2008-02-08 00:03:49 +01:00
2008-07-18 15:24:57 +02:00
if ( grp - > group_max_buflen = = 0 | | grp - > group_max_buflen >
xid - > xid2_buf_len - len )
2008-02-08 00:03:49 +01:00
grp - > group_max_buflen = xid - > xid2_buf_len - len ;
}
2008-07-18 15:24:57 +02:00
if ( grp - > saved_xid2 = = NULL ) {
2008-02-08 00:03:49 +01:00
grp - > saved_xid2 =
( struct xid2 * ) skb_tail_pointer ( grp - > rcvd_xid_skb ) ;
memcpy ( skb_put ( grp - > rcvd_xid_skb ,
XID2_LENGTH ) , xid , XID2_LENGTH ) ;
grp - > rcvd_xid_skb - > data = grp - > rcvd_xid_data ;
skb_reset_tail_pointer ( grp - > rcvd_xid_skb ) ;
grp - > rcvd_xid_skb - > len = 0 ;
/* convert two 32 bit numbers into 1 64 bit for id compare */
our_id = ( __u64 ) priv - > xid - > xid2_adj_id ;
our_id = our_id < < 32 ;
our_id = our_id + priv - > xid - > xid2_sender_id ;
their_id = ( __u64 ) xid - > xid2_adj_id ;
their_id = their_id < < 32 ;
their_id = their_id + xid - > xid2_sender_id ;
/* lower id assume the xside role */
if ( our_id < their_id ) {
grp - > roll = XSIDE ;
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_TRACE , CTC_DBF_NOTICE ,
" %s(%s): WE HAVE LOW ID - TAKE XSIDE " ,
CTCM_FUNTAIL , ch - > id ) ;
2008-02-08 00:03:49 +01:00
} else {
grp - > roll = YSIDE ;
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_TRACE , CTC_DBF_NOTICE ,
" %s(%s): WE HAVE HIGH ID - TAKE YSIDE " ,
CTCM_FUNTAIL , ch - > id ) ;
2008-02-08 00:03:49 +01:00
}
} else {
if ( xid - > xid2_flag4 ! = grp - > saved_xid2 - > xid2_flag4 ) {
2008-07-18 15:24:57 +02:00
rc = 3 ;
/* XID REJECTED: xid flag byte4 mismatch */
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): xid flag byte4 mismatch " ,
CTCM_FUNTAIL , ch - > id ) ;
2008-02-08 00:03:49 +01:00
}
if ( xid - > xid2_flag2 = = 0x40 ) {
2008-07-18 15:24:57 +02:00
rc = 4 ;
/* XID REJECTED - xid NOGOOD */
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): xid NOGOOD " ,
CTCM_FUNTAIL , ch - > id ) ;
2008-02-08 00:03:49 +01:00
}
if ( xid - > xid2_adj_id ! = grp - > saved_xid2 - > xid2_adj_id ) {
2008-07-18 15:24:57 +02:00
rc = 5 ;
/* XID REJECTED - Adjacent Station ID Mismatch */
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): Adjacent Station ID Mismatch " ,
CTCM_FUNTAIL , ch - > id ) ;
2008-02-08 00:03:49 +01:00
}
if ( xid - > xid2_sender_id ! = grp - > saved_xid2 - > xid2_sender_id ) {
2008-07-18 15:24:57 +02:00
rc = 6 ;
/* XID REJECTED - Sender Address Mismatch */
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): Sender Address Mismatch " ,
CTCM_FUNTAIL , ch - > id ) ;
2008-02-08 00:03:49 +01:00
}
}
2008-07-18 15:24:57 +02:00
done :
if ( rc ) {
2008-12-25 13:39:54 +01:00
dev_warn ( & dev - > dev ,
" The XID used in the MPC protocol is not valid, "
" rc = %d \n " , rc ) ;
2008-02-08 00:03:49 +01:00
priv - > xid - > xid2_flag2 = 0x40 ;
grp - > saved_xid2 - > xid2_flag2 = 0x40 ;
}
return rc ;
}
/*
* MPC Group Station FSM action
* CTCM_PROTO_MPC only
*/
static void mpc_action_side_xid ( fsm_instance * fsm , void * arg , int side )
{
struct channel * ch = arg ;
int rc = 0 ;
int gotlock = 0 ;
unsigned long saveflags = 0 ; /* avoids compiler warning with
2008-07-18 15:24:57 +02:00
spin_unlock_irqrestore */
2008-02-08 00:03:49 +01:00
2008-07-18 15:24:57 +02:00
CTCM_PR_DEBUG ( " Enter %s: cp=%i ch=0x%p id=%s \n " ,
__func__ , smp_processor_id ( ) , ch , ch - > id ) ;
2008-02-08 00:03:49 +01:00
if ( ctcm_checkalloc_buffer ( ch ) )
goto done ;
2008-07-18 15:24:57 +02:00
/*
* skb data - buffer referencing :
*/
2008-02-08 00:03:49 +01:00
ch - > trans_skb - > data = ch - > trans_skb_data ;
skb_reset_tail_pointer ( ch - > trans_skb ) ;
ch - > trans_skb - > len = 0 ;
/* result of the previous 3 statements is NOT always
* already set after ctcm_checkalloc_buffer
* because of possible reuse of the trans_skb
*/
memset ( ch - > trans_skb - > data , 0 , 16 ) ;
ch - > rcvd_xid_th = ( struct th_header * ) ch - > trans_skb_data ;
/* check is main purpose here: */
skb_put ( ch - > trans_skb , TH_HEADER_LENGTH ) ;
ch - > rcvd_xid = ( struct xid2 * ) skb_tail_pointer ( ch - > trans_skb ) ;
/* check is main purpose here: */
skb_put ( ch - > trans_skb , XID2_LENGTH ) ;
ch - > rcvd_xid_id = skb_tail_pointer ( ch - > trans_skb ) ;
/* cleanup back to startpoint */
ch - > trans_skb - > data = ch - > trans_skb_data ;
skb_reset_tail_pointer ( ch - > trans_skb ) ;
ch - > trans_skb - > len = 0 ;
/* non-checking rewrite of above skb data-buffer referencing: */
/*
memset ( ch - > trans_skb - > data , 0 , 16 ) ;
ch - > rcvd_xid_th = ( struct th_header * ) ch - > trans_skb_data ;
ch - > rcvd_xid = ( struct xid2 * ) ( ch - > trans_skb_data + TH_HEADER_LENGTH ) ;
ch - > rcvd_xid_id = ch - > trans_skb_data + TH_HEADER_LENGTH + XID2_LENGTH ;
*/
ch - > ccw [ 8 ] . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
ch - > ccw [ 8 ] . count = 0 ;
ch - > ccw [ 8 ] . cda = 0x00 ;
2008-07-18 15:24:57 +02:00
if ( ! ( ch - > xid_th & & ch - > xid & & ch - > xid_id ) )
CTCM_DBF_TEXT_ ( MPC_TRACE , CTC_DBF_INFO ,
" %s(%s): xid_th=%p, xid=%p, xid_id=%p " ,
CTCM_FUNTAIL , ch - > id , ch - > xid_th , ch - > xid , ch - > xid_id ) ;
2008-02-08 00:03:49 +01:00
if ( side = = XSIDE ) {
/* mpc_action_xside_xid */
2008-07-18 15:24:57 +02:00
if ( ch - > xid_th = = NULL )
goto done ;
2008-02-08 00:03:49 +01:00
ch - > ccw [ 9 ] . cmd_code = CCW_CMD_WRITE ;
ch - > ccw [ 9 ] . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
ch - > ccw [ 9 ] . count = TH_HEADER_LENGTH ;
ch - > ccw [ 9 ] . cda = virt_to_phys ( ch - > xid_th ) ;
2008-07-18 15:24:57 +02:00
if ( ch - > xid = = NULL )
goto done ;
2008-02-08 00:03:49 +01:00
ch - > ccw [ 10 ] . cmd_code = CCW_CMD_WRITE ;
ch - > ccw [ 10 ] . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
ch - > ccw [ 10 ] . count = XID2_LENGTH ;
ch - > ccw [ 10 ] . cda = virt_to_phys ( ch - > xid ) ;
ch - > ccw [ 11 ] . cmd_code = CCW_CMD_READ ;
ch - > ccw [ 11 ] . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
ch - > ccw [ 11 ] . count = TH_HEADER_LENGTH ;
ch - > ccw [ 11 ] . cda = virt_to_phys ( ch - > rcvd_xid_th ) ;
ch - > ccw [ 12 ] . cmd_code = CCW_CMD_READ ;
ch - > ccw [ 12 ] . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
ch - > ccw [ 12 ] . count = XID2_LENGTH ;
ch - > ccw [ 12 ] . cda = virt_to_phys ( ch - > rcvd_xid ) ;
ch - > ccw [ 13 ] . cmd_code = CCW_CMD_READ ;
ch - > ccw [ 13 ] . cda = virt_to_phys ( ch - > rcvd_xid_id ) ;
} else { /* side == YSIDE : mpc_action_yside_xid */
ch - > ccw [ 9 ] . cmd_code = CCW_CMD_READ ;
ch - > ccw [ 9 ] . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
ch - > ccw [ 9 ] . count = TH_HEADER_LENGTH ;
ch - > ccw [ 9 ] . cda = virt_to_phys ( ch - > rcvd_xid_th ) ;
ch - > ccw [ 10 ] . cmd_code = CCW_CMD_READ ;
ch - > ccw [ 10 ] . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
ch - > ccw [ 10 ] . count = XID2_LENGTH ;
ch - > ccw [ 10 ] . cda = virt_to_phys ( ch - > rcvd_xid ) ;
2008-07-18 15:24:57 +02:00
if ( ch - > xid_th = = NULL )
goto done ;
2008-02-08 00:03:49 +01:00
ch - > ccw [ 11 ] . cmd_code = CCW_CMD_WRITE ;
ch - > ccw [ 11 ] . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
ch - > ccw [ 11 ] . count = TH_HEADER_LENGTH ;
ch - > ccw [ 11 ] . cda = virt_to_phys ( ch - > xid_th ) ;
2008-07-18 15:24:57 +02:00
if ( ch - > xid = = NULL )
goto done ;
2008-02-08 00:03:49 +01:00
ch - > ccw [ 12 ] . cmd_code = CCW_CMD_WRITE ;
ch - > ccw [ 12 ] . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
ch - > ccw [ 12 ] . count = XID2_LENGTH ;
ch - > ccw [ 12 ] . cda = virt_to_phys ( ch - > xid ) ;
2008-07-18 15:24:57 +02:00
if ( ch - > xid_id = = NULL )
goto done ;
2008-02-08 00:03:49 +01:00
ch - > ccw [ 13 ] . cmd_code = CCW_CMD_WRITE ;
ch - > ccw [ 13 ] . cda = virt_to_phys ( ch - > xid_id ) ;
}
ch - > ccw [ 13 ] . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
ch - > ccw [ 13 ] . count = 4 ;
ch - > ccw [ 14 ] . cmd_code = CCW_CMD_NOOP ;
ch - > ccw [ 14 ] . flags = CCW_FLAG_SLI ;
ch - > ccw [ 14 ] . count = 0 ;
ch - > ccw [ 14 ] . cda = 0 ;
2008-07-18 15:24:57 +02:00
CTCM_CCW_DUMP ( ( char * ) & ch - > ccw [ 8 ] , sizeof ( struct ccw1 ) * 7 ) ;
CTCM_D3_DUMP ( ( char * ) ch - > xid_th , TH_HEADER_LENGTH ) ;
CTCM_D3_DUMP ( ( char * ) ch - > xid , XID2_LENGTH ) ;
CTCM_D3_DUMP ( ( char * ) ch - > xid_id , 4 ) ;
2008-02-08 00:03:49 +01:00
if ( ! in_irq ( ) ) {
/* Such conditional locking is a known problem for
* sparse because its static undeterministic .
* Warnings should be ignored here . */
spin_lock_irqsave ( get_ccwdev_lock ( ch - > cdev ) , saveflags ) ;
gotlock = 1 ;
}
fsm_addtimer ( & ch - > timer , 5000 , CTC_EVENT_TIMER , ch ) ;
rc = ccw_device_start ( ch - > cdev , & ch - > ccw [ 8 ] ,
( unsigned long ) ch , 0xff , 0 ) ;
if ( gotlock ) /* see remark above about conditional locking */
spin_unlock_irqrestore ( get_ccwdev_lock ( ch - > cdev ) , saveflags ) ;
if ( rc ! = 0 ) {
ctcm_ccw_check_rc ( ch , rc ,
( side = = XSIDE ) ? " x-side XID " : " y-side XID " ) ;
}
done :
2008-07-18 15:24:57 +02:00
CTCM_PR_DEBUG ( " Exit %s: ch=0x%p id=%s \n " ,
__func__ , ch , ch - > id ) ;
2008-02-08 00:03:49 +01:00
return ;
}
/*
* MPC Group Station FSM action
* CTCM_PROTO_MPC only
*/
static void mpc_action_xside_xid ( fsm_instance * fsm , int event , void * arg )
{
mpc_action_side_xid ( fsm , arg , XSIDE ) ;
}
/*
* MPC Group Station FSM action
* CTCM_PROTO_MPC only
*/
static void mpc_action_yside_xid ( fsm_instance * fsm , int event , void * arg )
{
mpc_action_side_xid ( fsm , arg , YSIDE ) ;
}
/*
* MPC Group Station FSM action
* CTCM_PROTO_MPC only
*/
static void mpc_action_doxid0 ( fsm_instance * fsm , int event , void * arg )
{
2008-07-18 15:24:57 +02:00
struct channel * ch = arg ;
struct net_device * dev = ch - > netdev ;
2008-08-21 17:10:24 +02:00
struct ctcm_priv * priv = dev - > ml_priv ;
2008-07-18 15:24:57 +02:00
struct mpc_group * grp = priv - > mpcg ;
2008-02-08 00:03:49 +01:00
2008-07-18 15:24:57 +02:00
CTCM_PR_DEBUG ( " Enter %s: cp=%i ch=0x%p id=%s \n " ,
__func__ , smp_processor_id ( ) , ch , ch - > id ) ;
2008-02-08 00:03:49 +01:00
if ( ch - > xid = = NULL ) {
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): ch->xid == NULL " ,
CTCM_FUNTAIL , dev - > name ) ;
return ;
2008-02-08 00:03:49 +01:00
}
fsm_newstate ( ch - > fsm , CH_XID0_INPROGRESS ) ;
ch - > xid - > xid2_option = XID2_0 ;
switch ( fsm_getstate ( grp - > fsm ) ) {
case MPCG_STATE_XID2INITW :
case MPCG_STATE_XID2INITX :
ch - > ccw [ 8 ] . cmd_code = CCW_CMD_SENSE_CMD ;
break ;
case MPCG_STATE_XID0IOWAIT :
case MPCG_STATE_XID0IOWAIX :
ch - > ccw [ 8 ] . cmd_code = CCW_CMD_WRITE_CTL ;
break ;
}
fsm_event ( grp - > fsm , MPCG_EVENT_DOIO , ch ) ;
return ;
}
/*
* MPC Group Station FSM action
* CTCM_PROTO_MPC only
*/
static void mpc_action_doxid7 ( fsm_instance * fsm , int event , void * arg )
{
struct net_device * dev = arg ;
2008-08-21 17:10:24 +02:00
struct ctcm_priv * priv = dev - > ml_priv ;
2008-07-18 15:24:57 +02:00
struct mpc_group * grp = NULL ;
2008-02-08 00:03:49 +01:00
int direction ;
int send = 0 ;
2008-07-18 15:24:57 +02:00
if ( priv )
grp = priv - > mpcg ;
2009-03-24 03:27:49 +00:00
if ( grp = = NULL )
2008-07-18 15:24:57 +02:00
return ;
2008-02-08 00:03:49 +01:00
for ( direction = READ ; direction < = WRITE ; direction + + ) {
struct channel * ch = priv - > channel [ direction ] ;
struct xid2 * thisxid = ch - > xid ;
ch - > xid_skb - > data = ch - > xid_skb_data ;
skb_reset_tail_pointer ( ch - > xid_skb ) ;
ch - > xid_skb - > len = 0 ;
thisxid - > xid2_option = XID2_7 ;
send = 0 ;
/* xid7 phase 1 */
if ( grp - > outstanding_xid7_p2 > 0 ) {
if ( grp - > roll = = YSIDE ) {
if ( fsm_getstate ( ch - > fsm ) = = CH_XID7_PENDING1 ) {
fsm_newstate ( ch - > fsm , CH_XID7_PENDING2 ) ;
ch - > ccw [ 8 ] . cmd_code = CCW_CMD_SENSE_CMD ;
memcpy ( skb_put ( ch - > xid_skb ,
TH_HEADER_LENGTH ) ,
& thdummy , TH_HEADER_LENGTH ) ;
send = 1 ;
}
} else if ( fsm_getstate ( ch - > fsm ) < CH_XID7_PENDING2 ) {
fsm_newstate ( ch - > fsm , CH_XID7_PENDING2 ) ;
ch - > ccw [ 8 ] . cmd_code = CCW_CMD_WRITE_CTL ;
memcpy ( skb_put ( ch - > xid_skb ,
TH_HEADER_LENGTH ) ,
& thnorm , TH_HEADER_LENGTH ) ;
send = 1 ;
}
} else {
/* xid7 phase 2 */
if ( grp - > roll = = YSIDE ) {
if ( fsm_getstate ( ch - > fsm ) < CH_XID7_PENDING4 ) {
fsm_newstate ( ch - > fsm , CH_XID7_PENDING4 ) ;
memcpy ( skb_put ( ch - > xid_skb ,
TH_HEADER_LENGTH ) ,
& thnorm , TH_HEADER_LENGTH ) ;
ch - > ccw [ 8 ] . cmd_code = CCW_CMD_WRITE_CTL ;
send = 1 ;
}
} else if ( fsm_getstate ( ch - > fsm ) = = CH_XID7_PENDING3 ) {
fsm_newstate ( ch - > fsm , CH_XID7_PENDING4 ) ;
ch - > ccw [ 8 ] . cmd_code = CCW_CMD_SENSE_CMD ;
memcpy ( skb_put ( ch - > xid_skb , TH_HEADER_LENGTH ) ,
& thdummy , TH_HEADER_LENGTH ) ;
send = 1 ;
}
}
if ( send )
fsm_event ( grp - > fsm , MPCG_EVENT_DOIO , ch ) ;
}
return ;
}
/*
* MPC Group Station FSM action
* CTCM_PROTO_MPC only
*/
static void mpc_action_rcvd_xid0 ( fsm_instance * fsm , int event , void * arg )
{
2008-07-18 15:24:57 +02:00
struct mpcg_info * mpcginfo = arg ;
struct channel * ch = mpcginfo - > ch ;
struct net_device * dev = ch - > netdev ;
2008-08-21 17:10:24 +02:00
struct ctcm_priv * priv = dev - > ml_priv ;
2008-07-18 15:24:57 +02:00
struct mpc_group * grp = priv - > mpcg ;
2008-02-08 00:03:49 +01:00
2008-07-18 15:24:57 +02:00
CTCM_PR_DEBUG ( " %s: ch-id:%s xid2:%i xid7:%i xidt_p2:%i \n " ,
__func__ , ch - > id , grp - > outstanding_xid2 ,
grp - > outstanding_xid7 , grp - > outstanding_xid7_p2 ) ;
2008-02-08 00:03:49 +01:00
if ( fsm_getstate ( ch - > fsm ) < CH_XID7_PENDING )
fsm_newstate ( ch - > fsm , CH_XID7_PENDING ) ;
grp - > outstanding_xid2 - - ;
grp - > outstanding_xid7 + + ;
grp - > outstanding_xid7_p2 + + ;
/* must change state before validating xid to */
/* properly handle interim interrupts received*/
switch ( fsm_getstate ( grp - > fsm ) ) {
case MPCG_STATE_XID2INITW :
fsm_newstate ( grp - > fsm , MPCG_STATE_XID2INITX ) ;
mpc_validate_xid ( mpcginfo ) ;
break ;
case MPCG_STATE_XID0IOWAIT :
fsm_newstate ( grp - > fsm , MPCG_STATE_XID0IOWAIX ) ;
mpc_validate_xid ( mpcginfo ) ;
break ;
case MPCG_STATE_XID2INITX :
if ( grp - > outstanding_xid2 = = 0 ) {
fsm_newstate ( grp - > fsm , MPCG_STATE_XID7INITW ) ;
mpc_validate_xid ( mpcginfo ) ;
fsm_event ( grp - > fsm , MPCG_EVENT_XID2DONE , dev ) ;
}
break ;
case MPCG_STATE_XID0IOWAIX :
if ( grp - > outstanding_xid2 = = 0 ) {
fsm_newstate ( grp - > fsm , MPCG_STATE_XID7INITI ) ;
mpc_validate_xid ( mpcginfo ) ;
fsm_event ( grp - > fsm , MPCG_EVENT_XID2DONE , dev ) ;
}
break ;
}
kfree ( mpcginfo ) ;
2008-07-18 15:24:57 +02:00
CTCM_PR_DEBUG ( " ctcmpc:%s() %s xid2:%i xid7:%i xidt_p2:%i \n " ,
__func__ , ch - > id , grp - > outstanding_xid2 ,
grp - > outstanding_xid7 , grp - > outstanding_xid7_p2 ) ;
CTCM_PR_DEBUG ( " ctcmpc:%s() %s grpstate: %s chanstate: %s \n " ,
__func__ , ch - > id ,
fsm_getstate_str ( grp - > fsm ) , fsm_getstate_str ( ch - > fsm ) ) ;
2008-02-08 00:03:49 +01:00
return ;
}
/*
* MPC Group Station FSM action
* CTCM_PROTO_MPC only
*/
static void mpc_action_rcvd_xid7 ( fsm_instance * fsm , int event , void * arg )
{
struct mpcg_info * mpcginfo = arg ;
struct channel * ch = mpcginfo - > ch ;
struct net_device * dev = ch - > netdev ;
2008-08-21 17:10:24 +02:00
struct ctcm_priv * priv = dev - > ml_priv ;
2008-02-08 00:03:49 +01:00
struct mpc_group * grp = priv - > mpcg ;
2008-07-18 15:24:57 +02:00
CTCM_PR_DEBUG ( " Enter %s: cp=%i ch=0x%p id=%s \n " ,
__func__ , smp_processor_id ( ) , ch , ch - > id ) ;
CTCM_PR_DEBUG ( " %s: outstanding_xid7: %i, outstanding_xid7_p2: %i \n " ,
__func__ , grp - > outstanding_xid7 , grp - > outstanding_xid7_p2 ) ;
2008-02-08 00:03:49 +01:00
grp - > outstanding_xid7 - - ;
ch - > xid_skb - > data = ch - > xid_skb_data ;
skb_reset_tail_pointer ( ch - > xid_skb ) ;
ch - > xid_skb - > len = 0 ;
switch ( fsm_getstate ( grp - > fsm ) ) {
case MPCG_STATE_XID7INITI :
fsm_newstate ( grp - > fsm , MPCG_STATE_XID7INITZ ) ;
mpc_validate_xid ( mpcginfo ) ;
break ;
case MPCG_STATE_XID7INITW :
fsm_newstate ( grp - > fsm , MPCG_STATE_XID7INITX ) ;
mpc_validate_xid ( mpcginfo ) ;
break ;
case MPCG_STATE_XID7INITZ :
case MPCG_STATE_XID7INITX :
if ( grp - > outstanding_xid7 = = 0 ) {
if ( grp - > outstanding_xid7_p2 > 0 ) {
grp - > outstanding_xid7 =
grp - > outstanding_xid7_p2 ;
grp - > outstanding_xid7_p2 = 0 ;
} else
fsm_newstate ( grp - > fsm , MPCG_STATE_XID7INITF ) ;
mpc_validate_xid ( mpcginfo ) ;
fsm_event ( grp - > fsm , MPCG_EVENT_XID7DONE , dev ) ;
break ;
}
mpc_validate_xid ( mpcginfo ) ;
break ;
}
kfree ( mpcginfo ) ;
return ;
}
/*
* mpc_action helper of an MPC Group Station FSM action
* CTCM_PROTO_MPC only
*/
static int mpc_send_qllc_discontact ( struct net_device * dev )
{
__u32 new_len = 0 ;
struct sk_buff * skb ;
struct qllc * qllcptr ;
2008-08-21 17:10:24 +02:00
struct ctcm_priv * priv = dev - > ml_priv ;
2008-07-18 15:24:57 +02:00
struct mpc_group * grp = priv - > mpcg ;
2008-02-08 00:03:49 +01:00
2008-07-18 15:24:57 +02:00
CTCM_PR_DEBUG ( " %s: GROUP STATE: %s \n " ,
__func__ , mpcg_state_names [ grp - > saved_state ] ) ;
2008-02-08 00:03:49 +01:00
switch ( grp - > saved_state ) {
/*
* establish conn callback function is
* preferred method to report failure
*/
case MPCG_STATE_XID0IOWAIT :
case MPCG_STATE_XID0IOWAIX :
case MPCG_STATE_XID7INITI :
case MPCG_STATE_XID7INITZ :
case MPCG_STATE_XID2INITW :
case MPCG_STATE_XID2INITX :
case MPCG_STATE_XID7INITW :
case MPCG_STATE_XID7INITX :
if ( grp - > estconnfunc ) {
grp - > estconnfunc ( grp - > port_num , - 1 , 0 ) ;
grp - > estconnfunc = NULL ;
break ;
}
case MPCG_STATE_FLOWC :
case MPCG_STATE_READY :
grp - > send_qllc_disc = 2 ;
new_len = sizeof ( struct qllc ) ;
qllcptr = kzalloc ( new_len , gfp_type ( ) | GFP_DMA ) ;
if ( qllcptr = = NULL ) {
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): qllcptr allocation error " ,
CTCM_FUNTAIL , dev - > name ) ;
return - ENOMEM ;
2008-02-08 00:03:49 +01:00
}
qllcptr - > qllc_address = 0xcc ;
qllcptr - > qllc_commands = 0x03 ;
skb = __dev_alloc_skb ( new_len , GFP_ATOMIC ) ;
if ( skb = = NULL ) {
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): skb allocation error " ,
CTCM_FUNTAIL , dev - > name ) ;
2008-02-08 00:03:49 +01:00
priv - > stats . rx_dropped + + ;
kfree ( qllcptr ) ;
2008-07-18 15:24:57 +02:00
return - ENOMEM ;
2008-02-08 00:03:49 +01:00
}
memcpy ( skb_put ( skb , new_len ) , qllcptr , new_len ) ;
kfree ( qllcptr ) ;
if ( skb_headroom ( skb ) < 4 ) {
2008-07-18 15:24:57 +02:00
CTCM_DBF_TEXT_ ( MPC_ERROR , CTC_DBF_ERROR ,
" %s(%s): skb_headroom error " ,
CTCM_FUNTAIL , dev - > name ) ;
2008-02-08 00:03:49 +01:00
dev_kfree_skb_any ( skb ) ;
2008-07-18 15:24:57 +02:00
return - ENOMEM ;
2008-02-08 00:03:49 +01:00
}
* ( ( __u32 * ) skb_push ( skb , 4 ) ) = priv - > channel [ READ ] - > pdu_seq ;
priv - > channel [ READ ] - > pdu_seq + + ;
2008-07-18 15:24:57 +02:00
CTCM_PR_DBGDATA ( " ctcmpc: %s ToDCM_pdu_seq= %08x \n " ,
__func__ , priv - > channel [ READ ] - > pdu_seq ) ;
2008-02-08 00:03:49 +01:00
/* receipt of CC03 resets anticipated sequence number on
receiving side */
priv - > channel [ READ ] - > pdu_seq = 0x00 ;
skb_reset_mac_header ( skb ) ;
skb - > dev = dev ;
skb - > protocol = htons ( ETH_P_SNAP ) ;
skb - > ip_summed = CHECKSUM_UNNECESSARY ;
2008-07-18 15:24:57 +02:00
CTCM_D3_DUMP ( skb - > data , ( sizeof ( struct qllc ) + 4 ) ) ;
2008-02-08 00:03:49 +01:00
netif_rx ( skb ) ;
break ;
default :
break ;
}
2008-07-18 15:24:57 +02:00
return 0 ;
2008-02-08 00:03:49 +01:00
}
/* --- This is the END my friend --- */