linux/drivers/net/fddi/skfp/srf.c
Thomas Gleixner 2874c5fd28 treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 152
Based on 1 normalized pattern(s):

  this program is free software you can redistribute it and or modify
  it under the terms of the gnu general public license as published by
  the free software foundation either version 2 of the license or at
  your option any later version

extracted by the scancode license scanner the SPDX license identifier

  GPL-2.0-or-later

has been chosen to replace the boilerplate/reference in 3029 file(s).

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Allison Randal <allison@lohutok.net>
Cc: linux-spdx@vger.kernel.org
Link: https://lkml.kernel.org/r/20190527070032.746973796@linutronix.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-05-30 11:26:32 -07:00

424 lines
9.9 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/******************************************************************************
*
* (C)Copyright 1998,1999 SysKonnect,
* a business unit of Schneider & Koch & Co. Datensysteme GmbH.
*
* See the file "skfddi.c" for further information.
*
* The information in this file is provided "AS IS" without warranty.
*
******************************************************************************/
/*
SMT 7.2 Status Response Frame Implementation
SRF state machine and frame generation
*/
#include "h/types.h"
#include "h/fddi.h"
#include "h/smc.h"
#include "h/smt_p.h"
#define KERNEL
#include "h/smtstate.h"
#ifndef SLIM_SMT
#ifndef BOOT
#ifndef lint
static const char ID_sccs[] = "@(#)srf.c 1.18 97/08/04 (C) SK " ;
#endif
/*
* function declarations
*/
static void clear_all_rep(struct s_smc *smc);
static void clear_reported(struct s_smc *smc);
static void smt_send_srf(struct s_smc *smc);
static struct s_srf_evc *smt_get_evc(struct s_smc *smc, int code, int index);
#define MAX_EVCS ARRAY_SIZE(smc->evcs)
struct evc_init {
u_char code ;
u_char index ;
u_char n ;
u_short para ;
} ;
static const struct evc_init evc_inits[] = {
{ SMT_COND_SMT_PEER_WRAP, 0,1,SMT_P1048 } ,
{ SMT_COND_MAC_DUP_ADDR, INDEX_MAC, NUMMACS,SMT_P208C } ,
{ SMT_COND_MAC_FRAME_ERROR, INDEX_MAC, NUMMACS,SMT_P208D } ,
{ SMT_COND_MAC_NOT_COPIED, INDEX_MAC, NUMMACS,SMT_P208E } ,
{ SMT_EVENT_MAC_NEIGHBOR_CHANGE, INDEX_MAC, NUMMACS,SMT_P208F } ,
{ SMT_EVENT_MAC_PATH_CHANGE, INDEX_MAC, NUMMACS,SMT_P2090 } ,
{ SMT_COND_PORT_LER, INDEX_PORT,NUMPHYS,SMT_P4050 } ,
{ SMT_COND_PORT_EB_ERROR, INDEX_PORT,NUMPHYS,SMT_P4052 } ,
{ SMT_EVENT_PORT_CONNECTION, INDEX_PORT,NUMPHYS,SMT_P4051 } ,
{ SMT_EVENT_PORT_PATH_CHANGE, INDEX_PORT,NUMPHYS,SMT_P4053 } ,
} ;
#define MAX_INIT_EVC ARRAY_SIZE(evc_inits)
void smt_init_evc(struct s_smc *smc)
{
struct s_srf_evc *evc ;
const struct evc_init *init ;
unsigned int i ;
int index ;
int offset ;
static u_char fail_safe = FALSE ;
memset((char *)smc->evcs,0,sizeof(smc->evcs)) ;
evc = smc->evcs ;
init = evc_inits ;
for (i = 0 ; i < MAX_INIT_EVC ; i++) {
for (index = 0 ; index < init->n ; index++) {
evc->evc_code = init->code ;
evc->evc_para = init->para ;
evc->evc_index = init->index + index ;
#ifndef DEBUG
evc->evc_multiple = &fail_safe ;
evc->evc_cond_state = &fail_safe ;
#endif
evc++ ;
}
init++ ;
}
if ((unsigned int) (evc - smc->evcs) > MAX_EVCS) {
SMT_PANIC(smc,SMT_E0127, SMT_E0127_MSG) ;
}
/*
* conditions
*/
smc->evcs[0].evc_cond_state = &smc->mib.fddiSMTPeerWrapFlag ;
smc->evcs[1].evc_cond_state =
&smc->mib.m[MAC0].fddiMACDuplicateAddressCond ;
smc->evcs[2].evc_cond_state =
&smc->mib.m[MAC0].fddiMACFrameErrorFlag ;
smc->evcs[3].evc_cond_state =
&smc->mib.m[MAC0].fddiMACNotCopiedFlag ;
/*
* events
*/
smc->evcs[4].evc_multiple = &smc->mib.m[MAC0].fddiMACMultiple_N ;
smc->evcs[5].evc_multiple = &smc->mib.m[MAC0].fddiMACMultiple_P ;
offset = 6 ;
for (i = 0 ; i < NUMPHYS ; i++) {
/*
* conditions
*/
smc->evcs[offset + 0*NUMPHYS].evc_cond_state =
&smc->mib.p[i].fddiPORTLerFlag ;
smc->evcs[offset + 1*NUMPHYS].evc_cond_state =
&smc->mib.p[i].fddiPORTEB_Condition ;
/*
* events
*/
smc->evcs[offset + 2*NUMPHYS].evc_multiple =
&smc->mib.p[i].fddiPORTMultiple_U ;
smc->evcs[offset + 3*NUMPHYS].evc_multiple =
&smc->mib.p[i].fddiPORTMultiple_P ;
offset++ ;
}
#ifdef DEBUG
for (i = 0, evc = smc->evcs ; i < MAX_EVCS ; i++, evc++) {
if (SMT_IS_CONDITION(evc->evc_code)) {
if (!evc->evc_cond_state) {
SMT_PANIC(smc,SMT_E0128, SMT_E0128_MSG) ;
}
evc->evc_multiple = &fail_safe ;
}
else {
if (!evc->evc_multiple) {
SMT_PANIC(smc,SMT_E0129, SMT_E0129_MSG) ;
}
evc->evc_cond_state = &fail_safe ;
}
}
#endif
smc->srf.TSR = smt_get_time() ;
smc->srf.sr_state = SR0_WAIT ;
}
static struct s_srf_evc *smt_get_evc(struct s_smc *smc, int code, int index)
{
unsigned int i ;
struct s_srf_evc *evc ;
for (i = 0, evc = smc->evcs ; i < MAX_EVCS ; i++, evc++) {
if (evc->evc_code == code && evc->evc_index == index)
return evc;
}
return NULL;
}
#define THRESHOLD_2 (2*TICKS_PER_SECOND)
#define THRESHOLD_32 (32*TICKS_PER_SECOND)
static const char * const srf_names[] = {
"None","MACPathChangeEvent", "MACNeighborChangeEvent",
"PORTPathChangeEvent", "PORTUndesiredConnectionAttemptEvent",
"SMTPeerWrapCondition", "SMTHoldCondition",
"MACFrameErrorCondition", "MACDuplicateAddressCondition",
"MACNotCopiedCondition", "PORTEBErrorCondition",
"PORTLerCondition"
} ;
void smt_srf_event(struct s_smc *smc, int code, int index, int cond)
{
struct s_srf_evc *evc ;
int cond_asserted = 0 ;
int cond_deasserted = 0 ;
int event_occurred = 0 ;
int tsr ;
int T_Limit = 2*TICKS_PER_SECOND ;
if (code == SMT_COND_MAC_DUP_ADDR && cond) {
RS_SET(smc,RS_DUPADDR) ;
}
if (code) {
DB_SMT("SRF: %s index %d", srf_names[code], index);
if (!(evc = smt_get_evc(smc,code,index))) {
DB_SMT("SRF : smt_get_evc() failed");
return ;
}
/*
* ignore condition if no change
*/
if (SMT_IS_CONDITION(code)) {
if (*evc->evc_cond_state == cond)
return ;
}
/*
* set transition time stamp
*/
smt_set_timestamp(smc,smc->mib.fddiSMTTransitionTimeStamp) ;
if (SMT_IS_CONDITION(code)) {
DB_SMT("SRF: condition is %s", cond ? "ON" : "OFF");
if (cond) {
*evc->evc_cond_state = TRUE ;
evc->evc_rep_required = TRUE ;
smc->srf.any_report = TRUE ;
cond_asserted = TRUE ;
}
else {
*evc->evc_cond_state = FALSE ;
cond_deasserted = TRUE ;
}
}
else {
if (evc->evc_rep_required) {
*evc->evc_multiple = TRUE ;
}
else {
evc->evc_rep_required = TRUE ;
*evc->evc_multiple = FALSE ;
}
smc->srf.any_report = TRUE ;
event_occurred = TRUE ;
}
#ifdef FDDI_MIB
snmp_srf_event(smc,evc) ;
#endif /* FDDI_MIB */
}
tsr = smt_get_time() - smc->srf.TSR ;
switch (smc->srf.sr_state) {
case SR0_WAIT :
/* SR01a */
if (cond_asserted && tsr < T_Limit) {
smc->srf.SRThreshold = THRESHOLD_2 ;
smc->srf.sr_state = SR1_HOLDOFF ;
break ;
}
/* SR01b */
if (cond_deasserted && tsr < T_Limit) {
smc->srf.sr_state = SR1_HOLDOFF ;
break ;
}
/* SR01c */
if (event_occurred && tsr < T_Limit) {
smc->srf.sr_state = SR1_HOLDOFF ;
break ;
}
/* SR00b */
if (cond_asserted && tsr >= T_Limit) {
smc->srf.SRThreshold = THRESHOLD_2 ;
smc->srf.TSR = smt_get_time() ;
smt_send_srf(smc) ;
break ;
}
/* SR00c */
if (cond_deasserted && tsr >= T_Limit) {
smc->srf.TSR = smt_get_time() ;
smt_send_srf(smc) ;
break ;
}
/* SR00d */
if (event_occurred && tsr >= T_Limit) {
smc->srf.TSR = smt_get_time() ;
smt_send_srf(smc) ;
break ;
}
/* SR00e */
if (smc->srf.any_report && (u_long) tsr >=
smc->srf.SRThreshold) {
smc->srf.SRThreshold *= 2 ;
if (smc->srf.SRThreshold > THRESHOLD_32)
smc->srf.SRThreshold = THRESHOLD_32 ;
smc->srf.TSR = smt_get_time() ;
smt_send_srf(smc) ;
break ;
}
/* SR02 */
if (!smc->mib.fddiSMTStatRptPolicy) {
smc->srf.sr_state = SR2_DISABLED ;
break ;
}
break ;
case SR1_HOLDOFF :
/* SR10b */
if (tsr >= T_Limit) {
smc->srf.sr_state = SR0_WAIT ;
smc->srf.TSR = smt_get_time() ;
smt_send_srf(smc) ;
break ;
}
/* SR11a */
if (cond_asserted) {
smc->srf.SRThreshold = THRESHOLD_2 ;
}
/* SR11b */
/* SR11c */
/* handled above */
/* SR12 */
if (!smc->mib.fddiSMTStatRptPolicy) {
smc->srf.sr_state = SR2_DISABLED ;
break ;
}
break ;
case SR2_DISABLED :
if (smc->mib.fddiSMTStatRptPolicy) {
smc->srf.sr_state = SR0_WAIT ;
smc->srf.TSR = smt_get_time() ;
smc->srf.SRThreshold = THRESHOLD_2 ;
clear_all_rep(smc) ;
break ;
}
break ;
}
}
static void clear_all_rep(struct s_smc *smc)
{
struct s_srf_evc *evc ;
unsigned int i ;
for (i = 0, evc = smc->evcs ; i < MAX_EVCS ; i++, evc++) {
evc->evc_rep_required = FALSE ;
if (SMT_IS_CONDITION(evc->evc_code))
*evc->evc_cond_state = FALSE ;
}
smc->srf.any_report = FALSE ;
}
static void clear_reported(struct s_smc *smc)
{
struct s_srf_evc *evc ;
unsigned int i ;
smc->srf.any_report = FALSE ;
for (i = 0, evc = smc->evcs ; i < MAX_EVCS ; i++, evc++) {
if (SMT_IS_CONDITION(evc->evc_code)) {
if (*evc->evc_cond_state == FALSE)
evc->evc_rep_required = FALSE ;
else
smc->srf.any_report = TRUE ;
}
else {
evc->evc_rep_required = FALSE ;
*evc->evc_multiple = FALSE ;
}
}
}
/*
* build and send SMT SRF frame
*/
static void smt_send_srf(struct s_smc *smc)
{
struct smt_header *smt ;
struct s_srf_evc *evc ;
SK_LOC_DECL(struct s_pcon,pcon) ;
SMbuf *mb ;
unsigned int i ;
static const struct fddi_addr SMT_SRF_DA = {
{ 0x80, 0x01, 0x43, 0x00, 0x80, 0x08 }
} ;
/*
* build SMT header
*/
if (!smc->r.sm_ma_avail)
return ;
if (!(mb = smt_build_frame(smc,SMT_SRF,SMT_ANNOUNCE,0)))
return ;
RS_SET(smc,RS_SOFTERROR) ;
smt = smtod(mb, struct smt_header *) ;
smt->smt_dest = SMT_SRF_DA ; /* DA == SRF multicast */
/*
* setup parameter status
*/
pcon.pc_len = SMT_MAX_INFO_LEN ; /* max para length */
pcon.pc_err = 0 ; /* no error */
pcon.pc_badset = 0 ; /* no bad set count */
pcon.pc_p = (void *) (smt + 1) ; /* paras start here */
smt_add_para(smc,&pcon,(u_short) SMT_P1033,0,0) ;
smt_add_para(smc,&pcon,(u_short) SMT_P1034,0,0) ;
for (i = 0, evc = smc->evcs ; i < MAX_EVCS ; i++, evc++) {
if (evc->evc_rep_required) {
smt_add_para(smc,&pcon,evc->evc_para,
(int)evc->evc_index,0) ;
}
}
smt->smt_len = SMT_MAX_INFO_LEN - pcon.pc_len ;
mb->sm_len = smt->smt_len + sizeof(struct smt_header) ;
DB_SMT("SRF: sending SRF at %p, len %d", smt, mb->sm_len);
DB_SMT("SRF: state SR%d Threshold %lu",
smc->srf.sr_state, smc->srf.SRThreshold / TICKS_PER_SECOND);
#ifdef DEBUG
dump_smt(smc,smt,"SRF Send") ;
#endif
smt_send_frame(smc,mb,FC_SMT_INFO,0) ;
clear_reported(smc) ;
}
#endif /* no BOOT */
#endif /* no SLIM_SMT */