root/drivers/net/fddi/skfp/ecm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ecm_init
  2. ecm
  3. ecm_fsm
  4. prop_actions
  5. prop_actions
  6. start_ecm_timer
  7. stop_ecm_timer

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /******************************************************************************
   3  *
   4  *      (C)Copyright 1998,1999 SysKonnect,
   5  *      a business unit of Schneider & Koch & Co. Datensysteme GmbH.
   6  *
   7  *      See the file "skfddi.c" for further information.
   8  *
   9  *      The information in this file is provided "AS IS" without warranty.
  10  *
  11  ******************************************************************************/
  12 
  13 /*
  14         SMT ECM
  15         Entity Coordination Management
  16         Hardware independent state machine
  17 */
  18 
  19 /*
  20  * Hardware independent state machine implemantation
  21  * The following external SMT functions are referenced :
  22  *
  23  *              queue_event()
  24  *              smt_timer_start()
  25  *              smt_timer_stop()
  26  *
  27  *      The following external HW dependent functions are referenced :
  28  *              sm_pm_bypass_req()
  29  *              sm_pm_get_ls()
  30  * 
  31  *      The following HW dependent events are required :
  32  *              NONE
  33  *
  34  */
  35 
  36 #include "h/types.h"
  37 #include "h/fddi.h"
  38 #include "h/smc.h"
  39 
  40 #define KERNEL
  41 #include "h/smtstate.h"
  42 
  43 #ifndef lint
  44 static const char ID_sccs[] = "@(#)ecm.c        2.7 99/08/05 (C) SK " ;
  45 #endif
  46 
  47 /*
  48  * FSM Macros
  49  */
  50 #define AFLAG   0x10
  51 #define GO_STATE(x)     (smc->mib.fddiSMTECMState = (x)|AFLAG)
  52 #define ACTIONS_DONE()  (smc->mib.fddiSMTECMState &= ~AFLAG)
  53 #define ACTIONS(x)      (x|AFLAG)
  54 
  55 #define EC0_OUT         0                       /* not inserted */
  56 #define EC1_IN          1                       /* inserted */
  57 #define EC2_TRACE       2                       /* tracing */
  58 #define EC3_LEAVE       3                       /* leaving the ring */
  59 #define EC4_PATH_TEST   4                       /* performing path test */
  60 #define EC5_INSERT      5                       /* bypass being turned on */
  61 #define EC6_CHECK       6                       /* checking bypass */
  62 #define EC7_DEINSERT    7                       /* bypass being turnde off */
  63 
  64 /*
  65  * symbolic state names
  66  */
  67 static const char * const ecm_states[] = {
  68         "EC0_OUT","EC1_IN","EC2_TRACE","EC3_LEAVE","EC4_PATH_TEST",
  69         "EC5_INSERT","EC6_CHECK","EC7_DEINSERT"
  70 } ;
  71 
  72 /*
  73  * symbolic event names
  74  */
  75 static const char * const ecm_events[] = {
  76         "NONE","EC_CONNECT","EC_DISCONNECT","EC_TRACE_PROP","EC_PATH_TEST",
  77         "EC_TIMEOUT_TD","EC_TIMEOUT_TMAX",
  78         "EC_TIMEOUT_IMAX","EC_TIMEOUT_INMAX","EC_TEST_DONE"
  79 } ;
  80 
  81 /*
  82  * all Globals  are defined in smc.h
  83  * struct s_ecm
  84  */
  85 
  86 /*
  87  * function declarations
  88  */
  89 
  90 static void ecm_fsm(struct s_smc *smc, int cmd);
  91 static void start_ecm_timer(struct s_smc *smc, u_long value, int event);
  92 static void stop_ecm_timer(struct s_smc *smc);
  93 static void prop_actions(struct s_smc *smc);
  94 
  95 /*
  96         init ECM state machine
  97         clear all ECM vars and flags
  98 */
  99 void ecm_init(struct s_smc *smc)
 100 {
 101         smc->e.path_test = PT_PASSED ;
 102         smc->e.trace_prop = 0 ;
 103         smc->e.sb_flag = 0 ;
 104         smc->mib.fddiSMTECMState = ACTIONS(EC0_OUT) ;
 105         smc->e.ecm_line_state = FALSE ;
 106 }
 107 
 108 /*
 109         ECM state machine
 110         called by dispatcher
 111 
 112         do
 113                 display state change
 114                 process event
 115         until SM is stable
 116 */
 117 void ecm(struct s_smc *smc, int event)
 118 {
 119         int     state ;
 120 
 121         do {
 122                 DB_ECM("ECM : state %s%s event %s",
 123                        smc->mib.fddiSMTECMState & AFLAG ? "ACTIONS " : "",
 124                        ecm_states[smc->mib.fddiSMTECMState & ~AFLAG],
 125                        ecm_events[event]);
 126                 state = smc->mib.fddiSMTECMState ;
 127                 ecm_fsm(smc,event) ;
 128                 event = 0 ;
 129         } while (state != smc->mib.fddiSMTECMState) ;
 130         ecm_state_change(smc,(int)smc->mib.fddiSMTECMState) ;
 131 }
 132 
 133 /*
 134         process ECM event
 135 */
 136 static void ecm_fsm(struct s_smc *smc, int cmd)
 137 {
 138         int ls_a ;                      /* current line state PHY A */
 139         int ls_b ;                      /* current line state PHY B */
 140         int     p ;                     /* ports */
 141 
 142 
 143         smc->mib.fddiSMTBypassPresent = sm_pm_bypass_present(smc) ;
 144         if (cmd == EC_CONNECT)
 145                 smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ;
 146 
 147         /* For AIX event notification: */
 148         /* Is a disconnect  command remotely issued ? */
 149         if (cmd == EC_DISCONNECT &&
 150                 smc->mib.fddiSMTRemoteDisconnectFlag == TRUE)
 151                 AIX_EVENT (smc, (u_long) CIO_HARD_FAIL, (u_long)
 152                         FDDI_REMOTE_DISCONNECT, smt_get_event_word(smc),
 153                         smt_get_error_word(smc) );
 154 
 155         /*jd 05-Aug-1999 Bug #10419 "Port Disconnect fails at Dup MAc Cond."*/
 156         if (cmd == EC_CONNECT) {
 157                 smc->e.DisconnectFlag = FALSE ;
 158         }
 159         else if (cmd == EC_DISCONNECT) {
 160                 smc->e.DisconnectFlag = TRUE ;
 161         }
 162         
 163         switch(smc->mib.fddiSMTECMState) {
 164         case ACTIONS(EC0_OUT) :
 165                 /*
 166                  * We do not perform a path test
 167                  */
 168                 smc->e.path_test = PT_PASSED ;
 169                 smc->e.ecm_line_state = FALSE ;
 170                 stop_ecm_timer(smc) ;
 171                 ACTIONS_DONE() ;
 172                 break ;
 173         case EC0_OUT:
 174                 /*EC01*/
 175                 if (cmd == EC_CONNECT && !smc->mib.fddiSMTBypassPresent
 176                         && smc->e.path_test==PT_PASSED) {
 177                         GO_STATE(EC1_IN) ;
 178                         break ;
 179                 }
 180                 /*EC05*/
 181                 else if (cmd == EC_CONNECT && (smc->e.path_test==PT_PASSED) &&
 182                         smc->mib.fddiSMTBypassPresent &&
 183                         (smc->s.sas == SMT_DAS)) {
 184                         GO_STATE(EC5_INSERT) ;
 185                         break ;
 186                 }
 187                 break;
 188         case ACTIONS(EC1_IN) :
 189                 stop_ecm_timer(smc) ;
 190                 smc->e.trace_prop = 0 ;
 191                 sm_ma_control(smc,MA_TREQ) ;
 192                 for (p = 0 ; p < NUMPHYS ; p++)
 193                         if (smc->mib.p[p].fddiPORTHardwarePresent)
 194                                 queue_event(smc,EVENT_PCMA+p,PC_START) ;
 195                 ACTIONS_DONE() ;
 196                 break ;
 197         case EC1_IN:
 198                 /*EC12*/
 199                 if (cmd == EC_TRACE_PROP) {
 200                         prop_actions(smc) ;
 201                         GO_STATE(EC2_TRACE) ;
 202                         break ;
 203                 }
 204                 /*EC13*/
 205                 else if (cmd == EC_DISCONNECT) {
 206                         GO_STATE(EC3_LEAVE) ;
 207                         break ;
 208                 }
 209                 break;
 210         case ACTIONS(EC2_TRACE) :
 211                 start_ecm_timer(smc,MIB2US(smc->mib.fddiSMTTrace_MaxExpiration),
 212                         EC_TIMEOUT_TMAX) ;
 213                 ACTIONS_DONE() ;
 214                 break ;
 215         case EC2_TRACE :
 216                 /*EC22*/
 217                 if (cmd == EC_TRACE_PROP) {
 218                         prop_actions(smc) ;
 219                         GO_STATE(EC2_TRACE) ;
 220                         break ;
 221                 }
 222                 /*EC23a*/
 223                 else if (cmd == EC_DISCONNECT) {
 224                         smc->e.path_test = PT_EXITING ;
 225                         GO_STATE(EC3_LEAVE) ;
 226                         break ;
 227                 }
 228                 /*EC23b*/
 229                 else if (smc->e.path_test == PT_PENDING) {
 230                         GO_STATE(EC3_LEAVE) ;
 231                         break ;
 232                 }
 233                 /*EC23c*/
 234                 else if (cmd == EC_TIMEOUT_TMAX) {
 235                         /* Trace_Max is expired */
 236                         /* -> send AIX_EVENT */
 237                         AIX_EVENT(smc, (u_long) FDDI_RING_STATUS,
 238                                 (u_long) FDDI_SMT_ERROR, (u_long)
 239                                 FDDI_TRACE_MAX, smt_get_error_word(smc));
 240                         smc->e.path_test = PT_PENDING ;
 241                         GO_STATE(EC3_LEAVE) ;
 242                         break ;
 243                 }
 244                 break ;
 245         case ACTIONS(EC3_LEAVE) :
 246                 start_ecm_timer(smc,smc->s.ecm_td_min,EC_TIMEOUT_TD) ;
 247                 for (p = 0 ; p < NUMPHYS ; p++)
 248                         queue_event(smc,EVENT_PCMA+p,PC_STOP) ;
 249                 ACTIONS_DONE() ;
 250                 break ;
 251         case EC3_LEAVE:
 252                 /*EC30*/
 253                 if (cmd == EC_TIMEOUT_TD && !smc->mib.fddiSMTBypassPresent &&
 254                         (smc->e.path_test != PT_PENDING)) {
 255                         GO_STATE(EC0_OUT) ;
 256                         break ;
 257                 }
 258                 /*EC34*/
 259                 else if (cmd == EC_TIMEOUT_TD &&
 260                         (smc->e.path_test == PT_PENDING)) {
 261                         GO_STATE(EC4_PATH_TEST) ;
 262                         break ;
 263                 }
 264                 /*EC31*/
 265                 else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) {
 266                         GO_STATE(EC1_IN) ;
 267                         break ;
 268                 }
 269                 /*EC33*/
 270                 else if (cmd == EC_DISCONNECT &&
 271                         smc->e.path_test == PT_PENDING) {
 272                         smc->e.path_test = PT_EXITING ;
 273                         /*
 274                          * stay in state - state will be left via timeout
 275                          */
 276                 }
 277                 /*EC37*/
 278                 else if (cmd == EC_TIMEOUT_TD &&
 279                         smc->mib.fddiSMTBypassPresent &&
 280                         smc->e.path_test != PT_PENDING) {
 281                         GO_STATE(EC7_DEINSERT) ;
 282                         break ;
 283                 }
 284                 break ;
 285         case ACTIONS(EC4_PATH_TEST) :
 286                 stop_ecm_timer(smc) ;
 287                 smc->e.path_test = PT_TESTING ;
 288                 start_ecm_timer(smc,smc->s.ecm_test_done,EC_TEST_DONE) ;
 289                 /* now perform path test ... just a simulation */
 290                 ACTIONS_DONE() ;
 291                 break ;
 292         case EC4_PATH_TEST :
 293                 /* path test done delay */
 294                 if (cmd == EC_TEST_DONE)
 295                         smc->e.path_test = PT_PASSED ;
 296 
 297                 if (smc->e.path_test == PT_FAILED)
 298                         RS_SET(smc,RS_PATHTEST) ;
 299 
 300                 /*EC40a*/
 301                 if (smc->e.path_test == PT_FAILED &&
 302                         !smc->mib.fddiSMTBypassPresent) {
 303                         GO_STATE(EC0_OUT) ;
 304                         break ;
 305                 }
 306                 /*EC40b*/
 307                 else if (cmd == EC_DISCONNECT &&
 308                         !smc->mib.fddiSMTBypassPresent) {
 309                         GO_STATE(EC0_OUT) ;
 310                         break ;
 311                 }
 312                 /*EC41*/
 313                 else if (smc->e.path_test == PT_PASSED) {
 314                         GO_STATE(EC1_IN) ;
 315                         break ;
 316                 }
 317                 /*EC47a*/
 318                 else if (smc->e.path_test == PT_FAILED &&
 319                         smc->mib.fddiSMTBypassPresent) {
 320                         GO_STATE(EC7_DEINSERT) ;
 321                         break ;
 322                 }
 323                 /*EC47b*/
 324                 else if (cmd == EC_DISCONNECT &&
 325                         smc->mib.fddiSMTBypassPresent) {
 326                         GO_STATE(EC7_DEINSERT) ;
 327                         break ;
 328                 }
 329                 break ;
 330         case ACTIONS(EC5_INSERT) :
 331                 sm_pm_bypass_req(smc,BP_INSERT);
 332                 start_ecm_timer(smc,smc->s.ecm_in_max,EC_TIMEOUT_INMAX) ;
 333                 ACTIONS_DONE() ;
 334                 break ;
 335         case EC5_INSERT :
 336                 /*EC56*/
 337                 if (cmd == EC_TIMEOUT_INMAX) {
 338                         GO_STATE(EC6_CHECK) ;
 339                         break ;
 340                 }
 341                 /*EC57*/
 342                 else if (cmd == EC_DISCONNECT) {
 343                         GO_STATE(EC7_DEINSERT) ;
 344                         break ;
 345                 }
 346                 break ;
 347         case ACTIONS(EC6_CHECK) :
 348                 /*
 349                  * in EC6_CHECK, we *POLL* the line state !
 350                  * check whether both bypass switches have switched.
 351                  */
 352                 start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;
 353                 smc->e.ecm_line_state = TRUE ;  /* flag to pcm: report Q/HLS */
 354                 ACTIONS_DONE() ;
 355                 break ;
 356         case EC6_CHECK :
 357                 ls_a = sm_pm_get_ls(smc,PA) ;
 358                 ls_b = sm_pm_get_ls(smc,PB) ;
 359 
 360                 /*EC61*/
 361                 if (((ls_a == PC_QLS) || (ls_a == PC_HLS)) &&
 362                     ((ls_b == PC_QLS) || (ls_b == PC_HLS)) ) {
 363                         smc->e.sb_flag = FALSE ;
 364                         smc->e.ecm_line_state = FALSE ;
 365                         GO_STATE(EC1_IN) ;
 366                         break ;
 367                 }
 368                 /*EC66*/
 369                 else if (!smc->e.sb_flag &&
 370                          (((ls_a == PC_ILS) && (ls_b == PC_QLS)) ||
 371                           ((ls_a == PC_QLS) && (ls_b == PC_ILS)))){
 372                         smc->e.sb_flag = TRUE ;
 373                         DB_ECMN(1, "ECM : EC6_CHECK - stuck bypass");
 374                         AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
 375                                 FDDI_SMT_ERROR, (u_long) FDDI_BYPASS_STUCK,
 376                                 smt_get_error_word(smc));
 377                 }
 378                 /*EC67*/
 379                 else if (cmd == EC_DISCONNECT) {
 380                         smc->e.ecm_line_state = FALSE ;
 381                         GO_STATE(EC7_DEINSERT) ;
 382                         break ;
 383                 }
 384                 else {
 385                         /*
 386                          * restart poll
 387                          */
 388                         start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;
 389                 }
 390                 break ;
 391         case ACTIONS(EC7_DEINSERT) :
 392                 sm_pm_bypass_req(smc,BP_DEINSERT);
 393                 start_ecm_timer(smc,smc->s.ecm_i_max,EC_TIMEOUT_IMAX) ;
 394                 ACTIONS_DONE() ;
 395                 break ;
 396         case EC7_DEINSERT:
 397                 /*EC70*/
 398                 if (cmd == EC_TIMEOUT_IMAX) {
 399                         GO_STATE(EC0_OUT) ;
 400                         break ;
 401                 }
 402                 /*EC75*/
 403                 else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) {
 404                         GO_STATE(EC5_INSERT) ;
 405                         break ;
 406                 }
 407                 break;
 408         default:
 409                 SMT_PANIC(smc,SMT_E0107, SMT_E0107_MSG) ;
 410                 break;
 411         }
 412 }
 413 
 414 #ifndef CONCENTRATOR
 415 /*
 416  * trace propagation actions for SAS & DAS
 417  */
 418 static void prop_actions(struct s_smc *smc)
 419 {
 420         int     port_in = 0 ;
 421         int     port_out = 0 ;
 422 
 423         RS_SET(smc,RS_EVENT) ;
 424         switch (smc->s.sas) {
 425         case SMT_SAS :
 426                 port_in = port_out = pcm_get_s_port(smc) ;
 427                 break ;
 428         case SMT_DAS :
 429                 port_in = cfm_get_mac_input(smc) ;      /* PA or PB */
 430                 port_out = cfm_get_mac_output(smc) ;    /* PA or PB */
 431                 break ;
 432         case SMT_NAC :
 433                 SMT_PANIC(smc,SMT_E0108, SMT_E0108_MSG) ;
 434                 return ;
 435         }
 436 
 437         DB_ECM("ECM : prop_actions - trace_prop %lu", smc->e.trace_prop);
 438         DB_ECM("ECM : prop_actions - in %d out %d", port_in, port_out);
 439 
 440         if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) {
 441                 /* trace initiatior */
 442                 DB_ECM("ECM : initiate TRACE on PHY %c", 'A' + port_in - PA);
 443                 queue_event(smc,EVENT_PCM+port_in,PC_TRACE) ;
 444         }
 445         else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PA))) &&
 446                 port_out != PA) {
 447                 /* trace propagate upstream */
 448                 DB_ECM("ECM : propagate TRACE on PHY B");
 449                 queue_event(smc,EVENT_PCMB,PC_TRACE) ;
 450         }
 451         else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PB))) &&
 452                 port_out != PB) {
 453                 /* trace propagate upstream */
 454                 DB_ECM("ECM : propagate TRACE on PHY A");
 455                 queue_event(smc,EVENT_PCMA,PC_TRACE) ;
 456         }
 457         else {
 458                 /* signal trace termination */
 459                 DB_ECM("ECM : TRACE terminated");
 460                 smc->e.path_test = PT_PENDING ;
 461         }
 462         smc->e.trace_prop = 0 ;
 463 }
 464 #else
 465 /*
 466  * trace propagation actions for Concentrator
 467  */
 468 static void prop_actions(struct s_smc *smc)
 469 {
 470         int     initiator ;
 471         int     upstream ;
 472         int     p ;
 473 
 474         RS_SET(smc,RS_EVENT) ;
 475         while (smc->e.trace_prop) {
 476                 DB_ECM("ECM : prop_actions - trace_prop %d",
 477                        smc->e.trace_prop);
 478 
 479                 if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) {
 480                         initiator = ENTITY_MAC ;
 481                         smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_MAC) ;
 482                         DB_ECM("ECM: MAC initiates trace");
 483                 }
 484                 else {
 485                         for (p = NUMPHYS-1 ; p >= 0 ; p--) {
 486                                 if (smc->e.trace_prop &
 487                                         ENTITY_BIT(ENTITY_PHY(p)))
 488                                         break ;
 489                         }
 490                         initiator = ENTITY_PHY(p) ;
 491                         smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_PHY(p)) ;
 492                 }
 493                 upstream = cem_get_upstream(smc,initiator) ;
 494 
 495                 if (upstream == ENTITY_MAC) {
 496                         /* signal trace termination */
 497                         DB_ECM("ECM : TRACE terminated");
 498                         smc->e.path_test = PT_PENDING ;
 499                 }
 500                 else {
 501                         /* trace propagate upstream */
 502                         DB_ECM("ECM : propagate TRACE on PHY %d", upstream);
 503                         queue_event(smc,EVENT_PCM+upstream,PC_TRACE) ;
 504                 }
 505         }
 506 }
 507 #endif
 508 
 509 
 510 /*
 511  * SMT timer interface
 512  *      start ECM timer
 513  */
 514 static void start_ecm_timer(struct s_smc *smc, u_long value, int event)
 515 {
 516         smt_timer_start(smc,&smc->e.ecm_timer,value,EV_TOKEN(EVENT_ECM,event));
 517 }
 518 
 519 /*
 520  * SMT timer interface
 521  *      stop ECM timer
 522  */
 523 static void stop_ecm_timer(struct s_smc *smc)
 524 {
 525         if (smc->e.ecm_timer.tm_active)
 526                 smt_timer_stop(smc,&smc->e.ecm_timer) ;
 527 }

/* [<][>][^][v][top][bottom][index][help] */