/* process ECM event */ static void ecm_fsm(struct s_smc *smc, int cmd) { int ls_a ; /* current line state PHY A */ int ls_b ; /* current line state PHY B */ int p ; /* ports */ smc->mib.fddiSMTBypassPresent = sm_pm_bypass_present(smc) ; if (cmd == EC_CONNECT) smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ; /* For AIX event notification: */ /* Is a disconnect command remotely issued ? */ if (cmd == EC_DISCONNECT && smc->mib.fddiSMTRemoteDisconnectFlag == TRUE) AIX_EVENT (smc, (u_long) CIO_HARD_FAIL, (u_long) FDDI_REMOTE_DISCONNECT, smt_get_event_word(smc), smt_get_error_word(smc) ); /*jd 05-Aug-1999 Bug #10419 "Port Disconnect fails at Dup MAc Cond."*/ if (cmd == EC_CONNECT) { smc->e.DisconnectFlag = FALSE ; } else if (cmd == EC_DISCONNECT) { smc->e.DisconnectFlag = TRUE ; } switch(smc->mib.fddiSMTECMState) { case ACTIONS(EC0_OUT) : /* * We do not perform a path test */ smc->e.path_test = PT_PASSED ; smc->e.ecm_line_state = FALSE ; stop_ecm_timer(smc) ; ACTIONS_DONE() ; break ; case EC0_OUT: /*EC01*/ if (cmd == EC_CONNECT && !smc->mib.fddiSMTBypassPresent && smc->e.path_test==PT_PASSED) { GO_STATE(EC1_IN) ; break ; } /*EC05*/ else if (cmd == EC_CONNECT && (smc->e.path_test==PT_PASSED) && smc->mib.fddiSMTBypassPresent && (smc->s.sas == SMT_DAS)) { GO_STATE(EC5_INSERT) ; break ; } break; case ACTIONS(EC1_IN) : stop_ecm_timer(smc) ; smc->e.trace_prop = 0 ; sm_ma_control(smc,MA_TREQ) ; for (p = 0 ; p < NUMPHYS ; p++) if (smc->mib.p[p].fddiPORTHardwarePresent) queue_event(smc,EVENT_PCMA+p,PC_START) ; ACTIONS_DONE() ; break ; case EC1_IN: /*EC12*/ if (cmd == EC_TRACE_PROP) { prop_actions(smc) ; GO_STATE(EC2_TRACE) ; break ; } /*EC13*/ else if (cmd == EC_DISCONNECT) { GO_STATE(EC3_LEAVE) ; break ; } break; case ACTIONS(EC2_TRACE) : start_ecm_timer(smc,MIB2US(smc->mib.fddiSMTTrace_MaxExpiration), EC_TIMEOUT_TMAX) ; ACTIONS_DONE() ; break ; case EC2_TRACE : /*EC22*/ if (cmd == EC_TRACE_PROP) { prop_actions(smc) ; GO_STATE(EC2_TRACE) ; break ; } /*EC23a*/ else if (cmd == EC_DISCONNECT) { smc->e.path_test = PT_EXITING ; GO_STATE(EC3_LEAVE) ; break ; } /*EC23b*/ else if (smc->e.path_test == PT_PENDING) { GO_STATE(EC3_LEAVE) ; break ; } /*EC23c*/ else if (cmd == EC_TIMEOUT_TMAX) { /* Trace_Max is expired */ /* -> send AIX_EVENT */ AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) FDDI_SMT_ERROR, (u_long) FDDI_TRACE_MAX, smt_get_error_word(smc)); smc->e.path_test = PT_PENDING ; GO_STATE(EC3_LEAVE) ; break ; } break ; case ACTIONS(EC3_LEAVE) : start_ecm_timer(smc,smc->s.ecm_td_min,EC_TIMEOUT_TD) ; for (p = 0 ; p < NUMPHYS ; p++) queue_event(smc,EVENT_PCMA+p,PC_STOP) ; ACTIONS_DONE() ; break ; case EC3_LEAVE: /*EC30*/ if (cmd == EC_TIMEOUT_TD && !smc->mib.fddiSMTBypassPresent && (smc->e.path_test != PT_PENDING)) { GO_STATE(EC0_OUT) ; break ; } /*EC34*/ else if (cmd == EC_TIMEOUT_TD && (smc->e.path_test == PT_PENDING)) { GO_STATE(EC4_PATH_TEST) ; break ; } /*EC31*/ else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) { GO_STATE(EC1_IN) ; break ; } /*EC33*/ else if (cmd == EC_DISCONNECT && smc->e.path_test == PT_PENDING) { smc->e.path_test = PT_EXITING ; /* * stay in state - state will be left via timeout */ } /*EC37*/ else if (cmd == EC_TIMEOUT_TD && smc->mib.fddiSMTBypassPresent && smc->e.path_test != PT_PENDING) { GO_STATE(EC7_DEINSERT) ; break ; } break ; case ACTIONS(EC4_PATH_TEST) : stop_ecm_timer(smc) ; smc->e.path_test = PT_TESTING ; start_ecm_timer(smc,smc->s.ecm_test_done,EC_TEST_DONE) ; /* now perform path test ... just a simulation */ ACTIONS_DONE() ; break ; case EC4_PATH_TEST : /* path test done delay */ if (cmd == EC_TEST_DONE) smc->e.path_test = PT_PASSED ; if (smc->e.path_test == PT_FAILED) RS_SET(smc,RS_PATHTEST) ; /*EC40a*/ if (smc->e.path_test == PT_FAILED && !smc->mib.fddiSMTBypassPresent) { GO_STATE(EC0_OUT) ; break ; } /*EC40b*/ else if (cmd == EC_DISCONNECT && !smc->mib.fddiSMTBypassPresent) { GO_STATE(EC0_OUT) ; break ; } /*EC41*/ else if (smc->e.path_test == PT_PASSED) { GO_STATE(EC1_IN) ; break ; } /*EC47a*/ else if (smc->e.path_test == PT_FAILED && smc->mib.fddiSMTBypassPresent) { GO_STATE(EC7_DEINSERT) ; break ; } /*EC47b*/ else if (cmd == EC_DISCONNECT && smc->mib.fddiSMTBypassPresent) { GO_STATE(EC7_DEINSERT) ; break ; } break ; case ACTIONS(EC5_INSERT) : sm_pm_bypass_req(smc,BP_INSERT); start_ecm_timer(smc,smc->s.ecm_in_max,EC_TIMEOUT_INMAX) ; ACTIONS_DONE() ; break ; case EC5_INSERT : /*EC56*/ if (cmd == EC_TIMEOUT_INMAX) { GO_STATE(EC6_CHECK) ; break ; } /*EC57*/ else if (cmd == EC_DISCONNECT) { GO_STATE(EC7_DEINSERT) ; break ; } break ; case ACTIONS(EC6_CHECK) : /* * in EC6_CHECK, we *POLL* the line state ! * check whether both bypass switches have switched. */ start_ecm_timer(smc,smc->s.ecm_check_poll,0) ; smc->e.ecm_line_state = TRUE ; /* flag to pcm: report Q/HLS */ (void) sm_pm_ls_latch(smc,PA,1) ; /* enable line state latch */ (void) sm_pm_ls_latch(smc,PB,1) ; /* enable line state latch */ ACTIONS_DONE() ; break ; case EC6_CHECK : ls_a = sm_pm_get_ls(smc,PA) ; ls_b = sm_pm_get_ls(smc,PB) ; /*EC61*/ if (((ls_a == PC_QLS) || (ls_a == PC_HLS)) && ((ls_b == PC_QLS) || (ls_b == PC_HLS)) ) { smc->e.sb_flag = FALSE ; smc->e.ecm_line_state = FALSE ; GO_STATE(EC1_IN) ; break ; } /*EC66*/ else if (!smc->e.sb_flag && (((ls_a == PC_ILS) && (ls_b == PC_QLS)) || ((ls_a == PC_QLS) && (ls_b == PC_ILS)))){ smc->e.sb_flag = TRUE ; DB_ECMN(1,"ECM : EC6_CHECK - stuck bypass\n",0,0) ; AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) FDDI_SMT_ERROR, (u_long) FDDI_BYPASS_STUCK, smt_get_error_word(smc)); } /*EC67*/ else if (cmd == EC_DISCONNECT) { smc->e.ecm_line_state = FALSE ; GO_STATE(EC7_DEINSERT) ; break ; } else { /* * restart poll */ start_ecm_timer(smc,smc->s.ecm_check_poll,0) ; } break ; case ACTIONS(EC7_DEINSERT) : sm_pm_bypass_req(smc,BP_DEINSERT); start_ecm_timer(smc,smc->s.ecm_i_max,EC_TIMEOUT_IMAX) ; ACTIONS_DONE() ; break ; case EC7_DEINSERT: /*EC70*/ if (cmd == EC_TIMEOUT_IMAX) { GO_STATE(EC0_OUT) ; break ; } /*EC75*/ else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) { GO_STATE(EC5_INSERT) ; break ; } break; default: SMT_PANIC(smc,SMT_E0107, SMT_E0107_MSG) ; break; } }
/* process RMT event */ static void rmt_fsm(struct s_smc *smc, int cmd) { /* * RM00-RM70 : from all states */ if (!smc->r.rm_join && !smc->r.rm_loop && smc->mib.m[MAC0].fddiMACRMTState != ACTIONS(RM0_ISOLATED) && smc->mib.m[MAC0].fddiMACRMTState != RM0_ISOLATED) { RS_SET(smc,RS_NORINGOP) ; rmt_indication(smc,0) ; GO_STATE(RM0_ISOLATED) ; return ; } switch(smc->mib.m[MAC0].fddiMACRMTState) { case ACTIONS(RM0_ISOLATED) : stop_rmt_timer0(smc) ; stop_rmt_timer1(smc) ; stop_rmt_timer2(smc) ; /* * Disable MAC. */ sm_ma_control(smc,MA_OFFLINE) ; smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; smc->r.loop_avail = FALSE ; smc->r.sm_ma_avail = FALSE ; smc->r.no_flag = TRUE ; DB_RMTN(1,"RMT : ISOLATED\n",0,0) ; ACTIONS_DONE() ; break ; case RM0_ISOLATED : /*RM01*/ if (smc->r.rm_join || smc->r.rm_loop) { /* * According to the standard the MAC must be reset * here. The FORMAC will be initialized and Claim * and Beacon Frames will be uploaded to the MAC. * So any change of Treq will take effect NOW. */ sm_ma_control(smc,MA_RESET) ; GO_STATE(RM1_NON_OP) ; break ; } break ; case ACTIONS(RM1_NON_OP) : start_rmt_timer0(smc,smc->s.rmt_t_non_op,RM_TIMEOUT_NON_OP) ; stop_rmt_timer1(smc) ; stop_rmt_timer2(smc) ; sm_ma_control(smc,MA_BEACON) ; DB_RMTN(1,"RMT : RING DOWN\n",0,0) ; RS_SET(smc,RS_NORINGOP) ; smc->r.sm_ma_avail = FALSE ; rmt_indication(smc,0) ; ACTIONS_DONE() ; break ; case RM1_NON_OP : /*RM12*/ if (cmd == RM_RING_OP) { RS_SET(smc,RS_RINGOPCHANGE) ; GO_STATE(RM2_RING_OP) ; break ; } /*RM13*/ else if (cmd == RM_TIMEOUT_NON_OP) { smc->r.bn_flag = FALSE ; smc->r.no_flag = TRUE ; GO_STATE(RM3_DETECT) ; break ; } break ; case ACTIONS(RM2_RING_OP) : stop_rmt_timer0(smc) ; stop_rmt_timer1(smc) ; stop_rmt_timer2(smc) ; smc->r.no_flag = FALSE ; if (smc->r.rm_loop) smc->r.loop_avail = TRUE ; if (smc->r.rm_join) { smc->r.sm_ma_avail = TRUE ; if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable) smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ; else smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; } DB_RMTN(1,"RMT : RING UP\n",0,0) ; RS_CLEAR(smc,RS_NORINGOP) ; RS_SET(smc,RS_RINGOPCHANGE) ; rmt_indication(smc,1) ; smt_stat_counter(smc,0) ; ACTIONS_DONE() ; break ; case RM2_RING_OP : /*RM21*/ if (cmd == RM_RING_NON_OP) { smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; smc->r.loop_avail = FALSE ; RS_SET(smc,RS_RINGOPCHANGE) ; GO_STATE(RM1_NON_OP) ; break ; } /*RM22a*/ else if (cmd == RM_ENABLE_FLAG) { if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable) smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ; else smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; } /*RM25*/ else if (smc->r.dup_addr_test == DA_FAILED) { smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; smc->r.loop_avail = FALSE ; smc->r.da_flag = TRUE ; GO_STATE(RM5_RING_OP_DUP) ; break ; } break ; case ACTIONS(RM3_DETECT) : start_rmt_timer0(smc,smc->s.mac_d_max*2,RM_TIMEOUT_D_MAX) ; start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ; start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ; sm_mac_check_beacon_claim(smc) ; DB_RMTN(1,"RMT : RM3_DETECT\n",0,0) ; ACTIONS_DONE() ; break ; case RM3_DETECT : if (cmd == RM_TIMEOUT_POLL) { start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL); sm_mac_check_beacon_claim(smc) ; break ; } if (cmd == RM_TIMEOUT_D_MAX) { smc->r.timer0_exp = TRUE ; } /* *jd(22-Feb-1999) * We need a time ">= 2*mac_d_max" since we had finished * Claim or Beacon state. So we will restart timer0 at * every state change. */ if (cmd == RM_TX_STATE_CHANGE) { start_rmt_timer0(smc, smc->s.mac_d_max*2, RM_TIMEOUT_D_MAX) ; } /*RM32*/ if (cmd == RM_RING_OP) { GO_STATE(RM2_RING_OP) ; break ; } /*RM33a*/ else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) && smc->r.bn_flag) { smc->r.bn_flag = FALSE ; } /*RM33b*/ else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) { int tx ; /* * set bn_flag only if in state T4 or T5: * only if we're the beaconer should we start the * trace ! */ if ((tx = sm_mac_get_tx_state(smc)) == 4 || tx == 5) { DB_RMTN(2,"RMT : DETECT && TRT_EXPIRED && T4/T5\n",0,0); smc->r.bn_flag = TRUE ; /* * If one of the upstream stations beaconed * and the link to the upstream neighbor is * lost we need to restart the stuck timer to * check the "stuck beacon" condition. */ start_rmt_timer1(smc,smc->s.rmt_t_stuck, RM_TIMEOUT_T_STUCK) ; } /* * We do NOT need to clear smc->r.bn_flag in case of * not being in state T4 or T5, because the flag * must be cleared in order to get in this condition. */ DB_RMTN(2, "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)\n", tx,smc->r.bn_flag) ; } /*RM34a*/ else if (cmd == RM_MY_CLAIM && smc->r.timer0_exp) { rmt_new_dup_actions(smc) ; GO_STATE(RM4_NON_OP_DUP) ; break ; } /*RM34b*/ else if (cmd == RM_MY_BEACON && smc->r.timer0_exp) { rmt_new_dup_actions(smc) ; GO_STATE(RM4_NON_OP_DUP) ; break ; } /*RM34c*/ else if (cmd == RM_VALID_CLAIM) { rmt_new_dup_actions(smc) ; GO_STATE(RM4_NON_OP_DUP) ; break ; } /*RM36*/ else if (cmd == RM_TIMEOUT_T_STUCK && smc->r.rm_join && smc->r.bn_flag) { GO_STATE(RM6_DIRECTED) ; break ; } break ; case ACTIONS(RM4_NON_OP_DUP) : start_rmt_timer0(smc,smc->s.rmt_t_announce,RM_TIMEOUT_ANNOUNCE); start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ; start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ; sm_mac_check_beacon_claim(smc) ; DB_RMTN(1,"RMT : RM4_NON_OP_DUP\n",0,0) ; ACTIONS_DONE() ; break ; case RM4_NON_OP_DUP : if (cmd == RM_TIMEOUT_POLL) { start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL); sm_mac_check_beacon_claim(smc) ; break ; } /*RM41*/ if (!smc->r.da_flag) { GO_STATE(RM1_NON_OP) ; break ; } /*RM44a*/ else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) && smc->r.bn_flag) { smc->r.bn_flag = FALSE ; } /*RM44b*/ else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) { int tx ; /* * set bn_flag only if in state T4 or T5: * only if we're the beaconer should we start the * trace ! */ if ((tx = sm_mac_get_tx_state(smc)) == 4 || tx == 5) { DB_RMTN(2,"RMT : NOPDUP && TRT_EXPIRED && T4/T5\n",0,0); smc->r.bn_flag = TRUE ; /* * If one of the upstream stations beaconed * and the link to the upstream neighbor is * lost we need to restart the stuck timer to * check the "stuck beacon" condition. */ start_rmt_timer1(smc,smc->s.rmt_t_stuck, RM_TIMEOUT_T_STUCK) ; } /* * We do NOT need to clear smc->r.bn_flag in case of * not being in state T4 or T5, because the flag * must be cleared in order to get in this condition. */ DB_RMTN(2, "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)\n", tx,smc->r.bn_flag) ; } /*RM44c*/ else if (cmd == RM_TIMEOUT_ANNOUNCE && !smc->r.bn_flag) { rmt_dup_actions(smc) ; } /*RM45*/ else if (cmd == RM_RING_OP) { smc->r.no_flag = FALSE ; GO_STATE(RM5_RING_OP_DUP) ; break ; } /*RM46*/ else if (cmd == RM_TIMEOUT_T_STUCK && smc->r.rm_join && smc->r.bn_flag) { GO_STATE(RM6_DIRECTED) ; break ; } break ; case ACTIONS(RM5_RING_OP_DUP) : stop_rmt_timer0(smc) ; stop_rmt_timer1(smc) ; stop_rmt_timer2(smc) ; DB_RMTN(1,"RMT : RM5_RING_OP_DUP\n",0,0) ; ACTIONS_DONE() ; break; case RM5_RING_OP_DUP : /*RM52*/ if (smc->r.dup_addr_test == DA_PASSED) { smc->r.da_flag = FALSE ; GO_STATE(RM2_RING_OP) ; break ; } /*RM54*/ else if (cmd == RM_RING_NON_OP) { smc->r.jm_flag = FALSE ; smc->r.bn_flag = FALSE ; GO_STATE(RM4_NON_OP_DUP) ; break ; } break ; case ACTIONS(RM6_DIRECTED) : start_rmt_timer0(smc,smc->s.rmt_t_direct,RM_TIMEOUT_T_DIRECT) ; stop_rmt_timer1(smc) ; start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ; sm_ma_control(smc,MA_DIRECTED) ; RS_SET(smc,RS_BEACON) ; DB_RMTN(1,"RMT : RM6_DIRECTED\n",0,0) ; ACTIONS_DONE() ; break ; case RM6_DIRECTED : /*RM63*/ if (cmd == RM_TIMEOUT_POLL) { start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL); sm_mac_check_beacon_claim(smc) ; #ifndef SUPERNET_3 /* Because of problems with the Supernet II chip set * sending of Directed Beacon will stop after 165ms * therefore restart_trt_for_dbcn(smc) will be called * to prevent this. */ restart_trt_for_dbcn(smc) ; #endif /*SUPERNET_3*/ break ; } if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) && !smc->r.da_flag) { smc->r.bn_flag = FALSE ; GO_STATE(RM3_DETECT) ; break ; } /*RM64*/ else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) && smc->r.da_flag) { smc->r.bn_flag = FALSE ; GO_STATE(RM4_NON_OP_DUP) ; break ; } /*RM67*/ else if (cmd == RM_TIMEOUT_T_DIRECT) { GO_STATE(RM7_TRACE) ; break ; } break ; case ACTIONS(RM7_TRACE) : stop_rmt_timer0(smc) ; stop_rmt_timer1(smc) ; stop_rmt_timer2(smc) ; smc->e.trace_prop |= ENTITY_BIT(ENTITY_MAC) ; queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ; DB_RMTN(1,"RMT : RM7_TRACE\n",0,0) ; ACTIONS_DONE() ; break ; case RM7_TRACE : break ; default: SMT_PANIC(smc,SMT_E0122, SMT_E0122_MSG) ; break; } }
/* * PCM state machine */ static void pcm_fsm(struct s_smc *smc, struct s_phy *phy, int cmd) { int i ; int np = phy->np ; /* PHY index */ struct s_plc *plc ; struct fddi_mib_p *mib ; #ifndef MOT_ELM u_short plc_rev ; /* Revision of the plc */ #endif /* nMOT_ELM */ plc = &phy->plc ; mib = phy->mib ; /* * general transitions independent of state */ switch (cmd) { case PC_STOP : /*PC00-PC80*/ if (mib->fddiPORTPCMState != PC9_MAINT) { GO_STATE(PC0_OFF) ; AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) FDDI_PORT_EVENT, (u_long) FDDI_PORT_STOP, smt_get_port_event_word(smc)); } return ; case PC_START : /*PC01-PC81*/ if (mib->fddiPORTPCMState != PC9_MAINT) GO_STATE(PC1_BREAK) ; return ; case PC_DISABLE : /* PC09-PC99 */ GO_STATE(PC9_MAINT) ; AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) FDDI_PORT_EVENT, (u_long) FDDI_PORT_DISABLED, smt_get_port_event_word(smc)); return ; case PC_TIMEOUT_LCT : /* if long or extended LCT */ stop_pcm_timer0(smc,phy) ; CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; /* end of LCT is indicate by PCM_CODE (initiate PCM event) */ return ; } switch(mib->fddiPORTPCMState) { case ACTIONS(PC0_OFF) : stop_pcm_timer0(smc,phy) ; outpw(PLC(np,PL_CNTRL_A),0) ; CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; sm_ph_lem_stop(smc,np) ; /* disable LEM */ phy->cf_loop = FALSE ; phy->cf_join = FALSE ; queue_event(smc,EVENT_CFM,CF_JOIN+np) ; plc_go_state(smc,np,PL_PCM_STOP) ; mib->fddiPORTConnectState = PCM_DISABLED ; ACTIONS_DONE() ; break ; case PC0_OFF: /*PC09*/ if (cmd == PC_MAINT) { GO_STATE(PC9_MAINT) ; break ; } break ; case ACTIONS(PC1_BREAK) : /* Stop the LCT timer if we came from Signal state */ stop_pcm_timer0(smc,phy) ; ACTIONS_DONE() ; plc_go_state(smc,np,0) ; CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; sm_ph_lem_stop(smc,np) ; /* disable LEM */ /* * if vector is already loaded, go to OFF to clear PCM_SIGNAL */ #if 0 if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) { plc_go_state(smc,np,PL_PCM_STOP) ; /* TB_MIN ? */ } #endif /* * Go to OFF state in any case. */ plc_go_state(smc,np,PL_PCM_STOP) ; if (mib->fddiPORTPC_Withhold == PC_WH_NONE) mib->fddiPORTConnectState = PCM_CONNECTING ; phy->cf_loop = FALSE ; phy->cf_join = FALSE ; queue_event(smc,EVENT_CFM,CF_JOIN+np) ; phy->ls_flag = FALSE ; phy->pc_mode = PM_NONE ; /* needed by CFM */ phy->bitn = 0 ; /* bit signaling start bit */ for (i = 0 ; i < 3 ; i++) pc_tcode_actions(smc,i,phy) ; /* Set the non-active interrupt mask register */ outpw(PLC(np,PL_INTR_MASK),plc_imsk_na) ; /* * If the LCT was stopped. There might be a * PCM_CODE interrupt event present. * This must be cleared. */ (void)inpw(PLC(np,PL_INTR_EVENT)) ; #ifndef MOT_ELM /* Get the plc revision for revision dependent code */ plc_rev = inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK ; if (plc_rev != PLC_REV_SN3) #endif /* MOT_ELM */ { /* * No supernet III PLC, so set Xmit verctor and * length BEFORE starting the state machine. */ if (plc_send_bits(smc,phy,3)) { return ; } } /* * Now give the Start command. * - The start command shall be done before setting the bits * to be signaled. (In PLC-S description and PLCS in SN3. * - The start command shall be issued AFTER setting the * XMIT vector and the XMIT length register. * * We do it exactly according this specs for the old PLC and * the new PLCS inside the SN3. * For the usual PLCS we try it the way it is done for the * old PLC and set the XMIT registers again, if the PLC is * not in SIGNAL state. This is done according to an PLCS * errata workaround. */ plc_go_state(smc,np,PL_PCM_START) ; /* * workaround for PLC-S eng. sample errata */ #ifdef MOT_ELM if (!(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL)) #else /* nMOT_ELM */ if (((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) != PLC_REVISION_A) && !(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL)) #endif /* nMOT_ELM */ { /* * Set register again (PLCS errata) or the first time * (new SN3 PLCS). */ (void) plc_send_bits(smc,phy,3) ; } /* * end of workaround */ GO_STATE(PC5_SIGNAL) ; plc->p_state = PS_BIT3 ; plc->p_bits = 3 ; plc->p_start = 0 ; break ; case PC1_BREAK : break ; case ACTIONS(PC2_TRACE) : plc_go_state(smc,np,PL_PCM_TRACE) ; ACTIONS_DONE() ; break ; case PC2_TRACE : break ; case PC3_CONNECT : /* these states are done by hardware */ case PC4_NEXT : break ; case ACTIONS(PC5_SIGNAL) : ACTIONS_DONE() ; case PC5_SIGNAL : if ((cmd != PC_SIGNAL) && (cmd != PC_TIMEOUT_LCT)) break ; switch (plc->p_state) { case PS_BIT3 : for (i = 0 ; i <= 2 ; i++) pc_rcode_actions(smc,i,phy) ; pc_tcode_actions(smc,3,phy) ; plc->p_state = PS_BIT4 ; plc->p_bits = 1 ; plc->p_start = 3 ; phy->bitn = 3 ; if (plc_send_bits(smc,phy,1)) { return ; } break ; case PS_BIT4 : pc_rcode_actions(smc,3,phy) ; for (i = 4 ; i <= 6 ; i++) pc_tcode_actions(smc,i,phy) ; plc->p_state = PS_BIT7 ; plc->p_bits = 3 ; plc->p_start = 4 ; phy->bitn = 4 ; if (plc_send_bits(smc,phy,3)) { return ; } break ; case PS_BIT7 : for (i = 3 ; i <= 6 ; i++) pc_rcode_actions(smc,i,phy) ; plc->p_state = PS_LCT ; plc->p_bits = 0 ; plc->p_start = 7 ; phy->bitn = 7 ; sm_ph_lem_start(smc,np,(int)smc->s.lct_short) ; /* enable LEM */ /* start LCT */ i = inpw(PLC(np,PL_CNTRL_B)) & ~PL_PC_LOOP ; outpw(PLC(np,PL_CNTRL_B),i) ; /* must be cleared */ outpw(PLC(np,PL_CNTRL_B),i | PL_RLBP) ; break ; case PS_LCT : /* check for local LCT failure */ pc_tcode_actions(smc,7,phy) ; /* * set tval[7] */ plc->p_state = PS_BIT8 ; plc->p_bits = 1 ; plc->p_start = 7 ; phy->bitn = 7 ; if (plc_send_bits(smc,phy,1)) { return ; } break ; case PS_BIT8 : /* check for remote LCT failure */ pc_rcode_actions(smc,7,phy) ; if (phy->t_val[7] || phy->r_val[7]) { plc_go_state(smc,np,PL_PCM_STOP) ; GO_STATE(PC1_BREAK) ; break ; } for (i = 8 ; i <= 9 ; i++) pc_tcode_actions(smc,i,phy) ; plc->p_state = PS_JOIN ; plc->p_bits = 2 ; plc->p_start = 8 ; phy->bitn = 8 ; if (plc_send_bits(smc,phy,2)) { return ; } break ; case PS_JOIN : for (i = 8 ; i <= 9 ; i++) pc_rcode_actions(smc,i,phy) ; plc->p_state = PS_ACTIVE ; GO_STATE(PC6_JOIN) ; break ; } break ; case ACTIONS(PC6_JOIN) : /* * prevent mux error when going from WRAP_A to WRAP_B */ if (smc->s.sas == SMT_DAS && np == PB && (smc->y[PA].pc_mode == PM_TREE || smc->y[PB].pc_mode == PM_TREE)) { SETMASK(PLC(np,PL_CNTRL_A), PL_SC_REM_LOOP,PL_SC_REM_LOOP) ; SETMASK(PLC(np,PL_CNTRL_B), PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ; } SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ; SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ; ACTIONS_DONE() ; cmd = 0 ; /* fall thru */ case PC6_JOIN : switch (plc->p_state) { case PS_ACTIVE: /*PC88b*/ if (!phy->cf_join) { phy->cf_join = TRUE ; queue_event(smc,EVENT_CFM,CF_JOIN+np) ; } if (cmd == PC_JOIN) GO_STATE(PC8_ACTIVE) ; /*PC82*/ if (cmd == PC_TRACE) { GO_STATE(PC2_TRACE) ; break ; } break ; } break ; case PC7_VERIFY : break ; case ACTIONS(PC8_ACTIVE) : /* * start LEM for SMT */ sm_ph_lem_start(smc,(int)phy->np,LCT_LEM_MAX) ; phy->tr_flag = FALSE ; mib->fddiPORTConnectState = PCM_ACTIVE ; /* Set the active interrupt mask register */ outpw(PLC(np,PL_INTR_MASK),plc_imsk_act) ; ACTIONS_DONE() ; break ; case PC8_ACTIVE : /*PC81 is done by PL_TNE_EXPIRED irq */ /*PC82*/ if (cmd == PC_TRACE) { GO_STATE(PC2_TRACE) ; break ; } /*PC88c: is done by TRACE_PROP irq */ break ; case ACTIONS(PC9_MAINT) : stop_pcm_timer0(smc,phy) ; CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ; /* disable LEM int. */ sm_ph_lem_stop(smc,np) ; /* disable LEM */ phy->cf_loop = FALSE ; phy->cf_join = FALSE ; queue_event(smc,EVENT_CFM,CF_JOIN+np) ; plc_go_state(smc,np,PL_PCM_STOP) ; mib->fddiPORTConnectState = PCM_DISABLED ; SETMASK(PLC(np,PL_CNTRL_B),PL_MAINT,PL_MAINT) ; sm_ph_linestate(smc,np,(int) MIB2LS(mib->fddiPORTMaint_LS)) ; outpw(PLC(np,PL_CNTRL_A),PL_SC_BYPASS) ; ACTIONS_DONE() ; break ; case PC9_MAINT : DB_PCMN(1,"PCM %c : MAINT\n",phy->phy_name,0) ; /*PC90*/ if (cmd == PC_ENABLE) { GO_STATE(PC0_OFF) ; break ; } break ; default: SMT_PANIC(smc,SMT_E0118, SMT_E0118_MSG) ; break ; } }
/*ARGSUSED1*/ static void cfm_fsm(struct s_smc *smc, int cmd) { switch(smc->mib.fddiSMTCF_State) { case ACTIONS(SC0_ISOLATED) : smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ; smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ; smc->mib.p[PA].fddiPORTMACPlacement = 0 ; smc->mib.p[PB].fddiPORTMACPlacement = 0 ; smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_SEPA ; config_mux(smc,MUX_ISOLATE) ; /* configure PHY Mux */ smc->r.rm_loop = FALSE ; smc->r.rm_join = FALSE ; queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ /* Don't do the WC-Flag changing here */ ACTIONS_DONE() ; DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; break; case SC0_ISOLATED : /*SC07*/ /*SAS port can be PA or PB ! */ if (smc->s.sas && (smc->y[PA].cf_join || smc->y[PA].cf_loop || smc->y[PB].cf_join || smc->y[PB].cf_loop)) { GO_STATE(SC11_C_WRAP_S) ; break ; } /*SC01*/ if ((smc->y[PA].cem_pst == CEM_PST_UP && smc->y[PA].cf_join && !smc->y[PA].wc_flag) || smc->y[PA].cf_loop) { GO_STATE(SC9_C_WRAP_A) ; break ; } /*SC02*/ if ((smc->y[PB].cem_pst == CEM_PST_UP && smc->y[PB].cf_join && !smc->y[PB].wc_flag) || smc->y[PB].cf_loop) { GO_STATE(SC10_C_WRAP_B) ; break ; } break ; case ACTIONS(SC9_C_WRAP_A) : smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ; smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ; smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ; smc->mib.p[PB].fddiPORTMACPlacement = 0 ; smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ; config_mux(smc,MUX_WRAPA) ; /* configure PHY mux */ if (smc->y[PA].cf_loop) { smc->r.rm_join = FALSE ; smc->r.rm_loop = TRUE ; queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */ } if (smc->y[PA].cf_join) { smc->r.rm_loop = FALSE ; smc->r.rm_join = TRUE ; queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ } ACTIONS_DONE() ; DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; break ; case SC9_C_WRAP_A : /*SC10*/ if ( (smc->y[PA].wc_flag || !smc->y[PA].cf_join) && !smc->y[PA].cf_loop ) { GO_STATE(SC0_ISOLATED) ; break ; } /*SC12*/ else if ( (smc->y[PB].cf_loop && smc->y[PA].cf_join && smc->y[PA].cem_pst == CEM_PST_UP) || ((smc->y[PB].cf_loop || (smc->y[PB].cf_join && smc->y[PB].cem_pst == CEM_PST_UP)) && (smc->y[PA].pc_mode == PM_TREE || smc->y[PB].pc_mode == PM_TREE))) { smc->y[PA].scrub = TRUE ; GO_STATE(SC10_C_WRAP_B) ; break ; } /*SC14*/ else if (!smc->s.attach_s && smc->y[PA].cf_join && smc->y[PA].cem_pst == CEM_PST_UP && smc->y[PA].pc_mode == PM_PEER && smc->y[PB].cf_join && smc->y[PB].cem_pst == CEM_PST_UP && smc->y[PB].pc_mode == PM_PEER) { smc->y[PA].scrub = TRUE ; smc->y[PB].scrub = TRUE ; GO_STATE(SC4_THRU_A) ; break ; } /*SC15*/ else if ( smc->s.attach_s && smc->y[PA].cf_join && smc->y[PA].cem_pst == CEM_PST_UP && smc->y[PA].pc_mode == PM_PEER && smc->y[PB].cf_join && smc->y[PB].cem_pst == CEM_PST_UP && smc->y[PB].pc_mode == PM_PEER) { smc->y[PA].scrub = TRUE ; smc->y[PB].scrub = TRUE ; GO_STATE(SC5_THRU_B) ; break ; } break ; case ACTIONS(SC10_C_WRAP_B) : smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ; smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ; smc->mib.p[PA].fddiPORTMACPlacement = 0 ; smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ; smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ; config_mux(smc,MUX_WRAPB) ; /* configure PHY mux */ if (smc->y[PB].cf_loop) { smc->r.rm_join = FALSE ; smc->r.rm_loop = TRUE ; queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */ } if (smc->y[PB].cf_join) { smc->r.rm_loop = FALSE ; smc->r.rm_join = TRUE ; queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ } ACTIONS_DONE() ; DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; break ; case SC10_C_WRAP_B : /*SC20*/ if ( !smc->y[PB].cf_join && !smc->y[PB].cf_loop ) { GO_STATE(SC0_ISOLATED) ; break ; } /*SC21*/ else if ( smc->y[PA].cf_loop && smc->y[PA].pc_mode == PM_PEER && smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) { smc->y[PB].scrub = TRUE ; GO_STATE(SC9_C_WRAP_A) ; break ; } /*SC24*/ else if (!smc->s.attach_s && smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER && smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) { smc->y[PA].scrub = TRUE ; smc->y[PB].scrub = TRUE ; GO_STATE(SC4_THRU_A) ; break ; } /*SC25*/ else if ( smc->s.attach_s && smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER && smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) { smc->y[PA].scrub = TRUE ; smc->y[PB].scrub = TRUE ; GO_STATE(SC5_THRU_B) ; break ; } break ; case ACTIONS(SC4_THRU_A) : smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ; smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ; smc->mib.p[PA].fddiPORTMACPlacement = 0 ; smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ; smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ; config_mux(smc,MUX_THRUA) ; /* configure PHY mux */ smc->r.rm_loop = FALSE ; smc->r.rm_join = TRUE ; queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ ACTIONS_DONE() ; DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; break ; case SC4_THRU_A : /*SC41*/ if (smc->y[PB].wc_flag || !smc->y[PB].cf_join) { smc->y[PA].scrub = TRUE ; GO_STATE(SC9_C_WRAP_A) ; break ; } /*SC42*/ else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) { smc->y[PB].scrub = TRUE ; GO_STATE(SC10_C_WRAP_B) ; break ; } /*SC45*/ else if (smc->s.attach_s) { smc->y[PB].scrub = TRUE ; GO_STATE(SC5_THRU_B) ; break ; } break ; case ACTIONS(SC5_THRU_B) : smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ; smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ; smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ; smc->mib.p[PB].fddiPORTMACPlacement = 0 ; smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ; config_mux(smc,MUX_THRUB) ; /* configure PHY mux */ smc->r.rm_loop = FALSE ; smc->r.rm_join = TRUE ; queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ ACTIONS_DONE() ; DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; break ; case SC5_THRU_B : /*SC51*/ if (!smc->y[PB].cf_join || smc->y[PB].wc_flag) { smc->y[PA].scrub = TRUE ; GO_STATE(SC9_C_WRAP_A) ; break ; } /*SC52*/ else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) { smc->y[PB].scrub = TRUE ; GO_STATE(SC10_C_WRAP_B) ; break ; } /*SC54*/ else if (!smc->s.attach_s) { smc->y[PA].scrub = TRUE ; GO_STATE(SC4_THRU_A) ; break ; } break ; case ACTIONS(SC11_C_WRAP_S) : smc->mib.p[PS].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ; smc->mib.p[PS].fddiPORTMACPlacement = INDEX_MAC ; smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ; config_mux(smc,MUX_WRAPS) ; /* configure PHY mux */ if (smc->y[PA].cf_loop || smc->y[PB].cf_loop) { smc->r.rm_join = FALSE ; smc->r.rm_loop = TRUE ; queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */ } if (smc->y[PA].cf_join || smc->y[PB].cf_join) { smc->r.rm_loop = FALSE ; smc->r.rm_join = TRUE ; queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ } ACTIONS_DONE() ; DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; break ; case SC11_C_WRAP_S : /*SC70*/ if ( !smc->y[PA].cf_join && !smc->y[PA].cf_loop && !smc->y[PB].cf_join && !smc->y[PB].cf_loop) { GO_STATE(SC0_ISOLATED) ; break ; } break ; default: SMT_PANIC(smc,SMT_E0106, SMT_E0106_MSG) ; break; } }