Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / net / fddi / skfp / rmt.c
1 /******************************************************************************
2  *
3  *      (C)Copyright 1998,1999 SysKonnect,
4  *      a business unit of Schneider & Koch & Co. Datensysteme GmbH.
5  *
6  *      See the file "skfddi.c" for further information.
7  *
8  *      This program is free software; you can redistribute it and/or modify
9  *      it under the terms of the GNU General Public License as published by
10  *      the Free Software Foundation; either version 2 of the License, or
11  *      (at your option) any later version.
12  *
13  *      The information in this file is provided "AS IS" without warranty.
14  *
15  ******************************************************************************/
16
17 /*
18         SMT RMT
19         Ring Management
20 */
21
22 /*
23  * Hardware independent state machine implemantation
24  * The following external SMT functions are referenced :
25  *
26  *              queue_event()
27  *              smt_timer_start()
28  *              smt_timer_stop()
29  *
30  *      The following external HW dependent functions are referenced :
31  *              sm_ma_control()
32  *              sm_mac_check_beacon_claim()
33  *
34  *      The following HW dependent events are required :
35  *              RM_RING_OP
36  *              RM_RING_NON_OP
37  *              RM_MY_BEACON
38  *              RM_OTHER_BEACON
39  *              RM_MY_CLAIM
40  *              RM_TRT_EXP
41  *              RM_VALID_CLAIM
42  *
43  */
44
45 #include "h/types.h"
46 #include "h/fddi.h"
47 #include "h/smc.h"
48
49 #define KERNEL
50 #include "h/smtstate.h"
51
52 #ifndef lint
53 static const char ID_sccs[] = "@(#)rmt.c        2.13 99/07/02 (C) SK " ;
54 #endif
55
56 /*
57  * FSM Macros
58  */
59 #define AFLAG   0x10
60 #define GO_STATE(x)     (smc->mib.m[MAC0].fddiMACRMTState = (x)|AFLAG)
61 #define ACTIONS_DONE()  (smc->mib.m[MAC0].fddiMACRMTState &= ~AFLAG)
62 #define ACTIONS(x)      (x|AFLAG)
63
64 #define RM0_ISOLATED    0
65 #define RM1_NON_OP      1               /* not operational */
66 #define RM2_RING_OP     2               /* ring operational */
67 #define RM3_DETECT      3               /* detect dupl addresses */
68 #define RM4_NON_OP_DUP  4               /* dupl. addr detected */
69 #define RM5_RING_OP_DUP 5               /* ring oper. with dupl. addr */
70 #define RM6_DIRECTED    6               /* sending directed beacons */
71 #define RM7_TRACE       7               /* trace initiated */
72
73 #ifdef  DEBUG
74 /*
75  * symbolic state names
76  */
77 static const char * const rmt_states[] = {
78         "RM0_ISOLATED","RM1_NON_OP","RM2_RING_OP","RM3_DETECT",
79         "RM4_NON_OP_DUP","RM5_RING_OP_DUP","RM6_DIRECTED",
80         "RM7_TRACE"
81 } ;
82
83 /*
84  * symbolic event names
85  */
86 static const char * const rmt_events[] = {
87         "NONE","RM_RING_OP","RM_RING_NON_OP","RM_MY_BEACON",
88         "RM_OTHER_BEACON","RM_MY_CLAIM","RM_TRT_EXP","RM_VALID_CLAIM",
89         "RM_JOIN","RM_LOOP","RM_DUP_ADDR","RM_ENABLE_FLAG",
90         "RM_TIMEOUT_NON_OP","RM_TIMEOUT_T_STUCK",
91         "RM_TIMEOUT_ANNOUNCE","RM_TIMEOUT_T_DIRECT",
92         "RM_TIMEOUT_D_MAX","RM_TIMEOUT_POLL","RM_TX_STATE_CHANGE"
93 } ;
94 #endif
95
96 /*
97  * Globals
98  * in struct s_rmt
99  */
100
101
102 /*
103  * function declarations
104  */
105 static void rmt_fsm(struct s_smc *smc, int cmd);
106 static void start_rmt_timer0(struct s_smc *smc, u_long value, int event);
107 static void start_rmt_timer1(struct s_smc *smc, u_long value, int event);
108 static void start_rmt_timer2(struct s_smc *smc, u_long value, int event);
109 static void stop_rmt_timer0(struct s_smc *smc);
110 static void stop_rmt_timer1(struct s_smc *smc);
111 static void stop_rmt_timer2(struct s_smc *smc);
112 static void rmt_dup_actions(struct s_smc *smc);
113 static void rmt_reinsert_actions(struct s_smc *smc);
114 static void rmt_leave_actions(struct s_smc *smc);
115 static void rmt_new_dup_actions(struct s_smc *smc);
116
117 #ifndef SUPERNET_3
118 extern void restart_trt_for_dbcn() ;
119 #endif /*SUPERNET_3*/
120
121 /*
122         init RMT state machine
123         clear all RMT vars and flags
124 */
125 void rmt_init(struct s_smc *smc)
126 {
127         smc->mib.m[MAC0].fddiMACRMTState = ACTIONS(RM0_ISOLATED) ;
128         smc->r.dup_addr_test = DA_NONE ;
129         smc->r.da_flag = 0 ;
130         smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
131         smc->r.sm_ma_avail = FALSE ;
132         smc->r.loop_avail = 0 ;
133         smc->r.bn_flag = 0 ;
134         smc->r.jm_flag = 0 ;
135         smc->r.no_flag = TRUE ;
136 }
137
138 /*
139         RMT state machine
140         called by dispatcher
141
142         do
143                 display state change
144                 process event
145         until SM is stable
146 */
147 void rmt(struct s_smc *smc, int event)
148 {
149         int     state ;
150
151         do {
152                 DB_RMT("RMT : state %s%s",
153                         (smc->mib.m[MAC0].fddiMACRMTState & AFLAG) ? "ACTIONS " : "",
154                         rmt_states[smc->mib.m[MAC0].fddiMACRMTState & ~AFLAG]) ;
155                 DB_RMT(" event %s\n",rmt_events[event],0) ;
156                 state = smc->mib.m[MAC0].fddiMACRMTState ;
157                 rmt_fsm(smc,event) ;
158                 event = 0 ;
159         } while (state != smc->mib.m[MAC0].fddiMACRMTState) ;
160         rmt_state_change(smc,(int)smc->mib.m[MAC0].fddiMACRMTState) ;
161 }
162
163 /*
164         process RMT event
165 */
166 static void rmt_fsm(struct s_smc *smc, int cmd)
167 {
168         /*
169          * RM00-RM70 : from all states
170          */
171         if (!smc->r.rm_join && !smc->r.rm_loop &&
172                 smc->mib.m[MAC0].fddiMACRMTState != ACTIONS(RM0_ISOLATED) &&
173                 smc->mib.m[MAC0].fddiMACRMTState != RM0_ISOLATED) {
174                 RS_SET(smc,RS_NORINGOP) ;
175                 rmt_indication(smc,0) ;
176                 GO_STATE(RM0_ISOLATED) ;
177                 return ;
178         }
179
180         switch(smc->mib.m[MAC0].fddiMACRMTState) {
181         case ACTIONS(RM0_ISOLATED) :
182                 stop_rmt_timer0(smc) ;
183                 stop_rmt_timer1(smc) ;
184                 stop_rmt_timer2(smc) ;
185
186                 /*
187                  * Disable MAC.
188                  */
189                 sm_ma_control(smc,MA_OFFLINE) ;
190                 smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
191                 smc->r.loop_avail = FALSE ;
192                 smc->r.sm_ma_avail = FALSE ;
193                 smc->r.no_flag = TRUE ;
194                 DB_RMTN(1,"RMT : ISOLATED\n",0,0) ;
195                 ACTIONS_DONE() ;
196                 break ;
197         case RM0_ISOLATED :
198                 /*RM01*/
199                 if (smc->r.rm_join || smc->r.rm_loop) {
200                         /*
201                          * According to the standard the MAC must be reset
202                          * here. The FORMAC will be initialized and Claim
203                          * and Beacon Frames will be uploaded to the MAC.
204                          * So any change of Treq will take effect NOW.
205                          */
206                         sm_ma_control(smc,MA_RESET) ;
207                         GO_STATE(RM1_NON_OP) ;
208                         break ;
209                 }
210                 break ;
211         case ACTIONS(RM1_NON_OP) :
212                 start_rmt_timer0(smc,smc->s.rmt_t_non_op,RM_TIMEOUT_NON_OP) ;
213                 stop_rmt_timer1(smc) ;
214                 stop_rmt_timer2(smc) ;
215                 sm_ma_control(smc,MA_BEACON) ;
216                 DB_RMTN(1,"RMT : RING DOWN\n",0,0) ;
217                 RS_SET(smc,RS_NORINGOP) ;
218                 smc->r.sm_ma_avail = FALSE ;
219                 rmt_indication(smc,0) ;
220                 ACTIONS_DONE() ;
221                 break ;
222         case RM1_NON_OP :
223                 /*RM12*/
224                 if (cmd == RM_RING_OP) {
225                         RS_SET(smc,RS_RINGOPCHANGE) ;
226                         GO_STATE(RM2_RING_OP) ;
227                         break ;
228                 }
229                 /*RM13*/
230                 else if (cmd == RM_TIMEOUT_NON_OP) {
231                         smc->r.bn_flag = FALSE ;
232                         smc->r.no_flag = TRUE ;
233                         GO_STATE(RM3_DETECT) ;
234                         break ;
235                 }
236                 break ;
237         case ACTIONS(RM2_RING_OP) :
238                 stop_rmt_timer0(smc) ;
239                 stop_rmt_timer1(smc) ;
240                 stop_rmt_timer2(smc) ;
241                 smc->r.no_flag = FALSE ;
242                 if (smc->r.rm_loop)
243                         smc->r.loop_avail = TRUE ;
244                 if (smc->r.rm_join) {
245                         smc->r.sm_ma_avail = TRUE ;
246                         if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable)
247                         smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ;
248                                 else
249                         smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
250                 }
251                 DB_RMTN(1,"RMT : RING UP\n",0,0) ;
252                 RS_CLEAR(smc,RS_NORINGOP) ;
253                 RS_SET(smc,RS_RINGOPCHANGE) ;
254                 rmt_indication(smc,1) ;
255                 smt_stat_counter(smc,0) ;
256                 ACTIONS_DONE() ;
257                 break ;
258         case RM2_RING_OP :
259                 /*RM21*/
260                 if (cmd == RM_RING_NON_OP) {
261                         smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
262                         smc->r.loop_avail = FALSE ;
263                         RS_SET(smc,RS_RINGOPCHANGE) ;
264                         GO_STATE(RM1_NON_OP) ;
265                         break ;
266                 }
267                 /*RM22a*/
268                 else if (cmd == RM_ENABLE_FLAG) {
269                         if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable)
270                         smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ;
271                                 else
272                         smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
273                 }
274                 /*RM25*/
275                 else if (smc->r.dup_addr_test == DA_FAILED) {
276                         smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
277                         smc->r.loop_avail = FALSE ;
278                         smc->r.da_flag = TRUE ;
279                         GO_STATE(RM5_RING_OP_DUP) ;
280                         break ;
281                 }
282                 break ;
283         case ACTIONS(RM3_DETECT) :
284                 start_rmt_timer0(smc,smc->s.mac_d_max*2,RM_TIMEOUT_D_MAX) ;
285                 start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ;
286                 start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
287                 sm_mac_check_beacon_claim(smc) ;
288                 DB_RMTN(1,"RMT : RM3_DETECT\n",0,0) ;
289                 ACTIONS_DONE() ;
290                 break ;
291         case RM3_DETECT :
292                 if (cmd == RM_TIMEOUT_POLL) {
293                         start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
294                         sm_mac_check_beacon_claim(smc) ;
295                         break ;
296                 }
297                 if (cmd == RM_TIMEOUT_D_MAX) {
298                         smc->r.timer0_exp = TRUE ;
299                 }
300                 /*
301                  *jd(22-Feb-1999)
302                  * We need a time ">= 2*mac_d_max" since we had finished
303                  * Claim or Beacon state. So we will restart timer0 at
304                  * every state change.
305                  */
306                 if (cmd == RM_TX_STATE_CHANGE) {
307                         start_rmt_timer0(smc,
308                                          smc->s.mac_d_max*2,
309                                          RM_TIMEOUT_D_MAX) ;
310                 }
311                 /*RM32*/
312                 if (cmd == RM_RING_OP) {
313                         GO_STATE(RM2_RING_OP) ;
314                         break ;
315                 }
316                 /*RM33a*/
317                 else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON)
318                         && smc->r.bn_flag) {
319                         smc->r.bn_flag = FALSE ;
320                 }
321                 /*RM33b*/
322                 else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) {
323                         int     tx ;
324                         /*
325                          * set bn_flag only if in state T4 or T5:
326                          * only if we're the beaconer should we start the
327                          * trace !
328                          */
329                         if ((tx =  sm_mac_get_tx_state(smc)) == 4 || tx == 5) {
330                         DB_RMTN(2,"RMT : DETECT && TRT_EXPIRED && T4/T5\n",0,0);
331                                 smc->r.bn_flag = TRUE ;
332                                 /*
333                                  * If one of the upstream stations beaconed
334                                  * and the link to the upstream neighbor is
335                                  * lost we need to restart the stuck timer to
336                                  * check the "stuck beacon" condition.
337                                  */
338                                 start_rmt_timer1(smc,smc->s.rmt_t_stuck,
339                                         RM_TIMEOUT_T_STUCK) ;
340                         }
341                         /*
342                          * We do NOT need to clear smc->r.bn_flag in case of
343                          * not being in state T4 or T5, because the flag
344                          * must be cleared in order to get in this condition.
345                          */
346
347                         DB_RMTN(2,
348                         "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)\n",
349                         tx,smc->r.bn_flag) ;
350                 }
351                 /*RM34a*/
352                 else if (cmd == RM_MY_CLAIM && smc->r.timer0_exp) {
353                         rmt_new_dup_actions(smc) ;
354                         GO_STATE(RM4_NON_OP_DUP) ;
355                         break ;
356                 }
357                 /*RM34b*/
358                 else if (cmd == RM_MY_BEACON && smc->r.timer0_exp) {
359                         rmt_new_dup_actions(smc) ;
360                         GO_STATE(RM4_NON_OP_DUP) ;
361                         break ;
362                 }
363                 /*RM34c*/
364                 else if (cmd == RM_VALID_CLAIM) {
365                         rmt_new_dup_actions(smc) ;
366                         GO_STATE(RM4_NON_OP_DUP) ;
367                         break ;
368                 }
369                 /*RM36*/
370                 else if (cmd == RM_TIMEOUT_T_STUCK &&
371                         smc->r.rm_join && smc->r.bn_flag) {
372                         GO_STATE(RM6_DIRECTED) ;
373                         break ;
374                 }
375                 break ;
376         case ACTIONS(RM4_NON_OP_DUP) :
377                 start_rmt_timer0(smc,smc->s.rmt_t_announce,RM_TIMEOUT_ANNOUNCE);
378                 start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ;
379                 start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
380                 sm_mac_check_beacon_claim(smc) ;
381                 DB_RMTN(1,"RMT : RM4_NON_OP_DUP\n",0,0) ;
382                 ACTIONS_DONE() ;
383                 break ;
384         case RM4_NON_OP_DUP :
385                 if (cmd == RM_TIMEOUT_POLL) {
386                         start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
387                         sm_mac_check_beacon_claim(smc) ;
388                         break ;
389                 }
390                 /*RM41*/
391                 if (!smc->r.da_flag) {
392                         GO_STATE(RM1_NON_OP) ;
393                         break ;
394                 }
395                 /*RM44a*/
396                 else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
397                         smc->r.bn_flag) {
398                         smc->r.bn_flag = FALSE ;
399                 }
400                 /*RM44b*/
401                 else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) {
402                         int     tx ;
403                         /*
404                          * set bn_flag only if in state T4 or T5:
405                          * only if we're the beaconer should we start the
406                          * trace !
407                          */
408                         if ((tx =  sm_mac_get_tx_state(smc)) == 4 || tx == 5) {
409                         DB_RMTN(2,"RMT : NOPDUP && TRT_EXPIRED && T4/T5\n",0,0);
410                                 smc->r.bn_flag = TRUE ;
411                                 /*
412                                  * If one of the upstream stations beaconed
413                                  * and the link to the upstream neighbor is
414                                  * lost we need to restart the stuck timer to
415                                  * check the "stuck beacon" condition.
416                                  */
417                                 start_rmt_timer1(smc,smc->s.rmt_t_stuck,
418                                         RM_TIMEOUT_T_STUCK) ;
419                         }
420                         /*
421                          * We do NOT need to clear smc->r.bn_flag in case of
422                          * not being in state T4 or T5, because the flag
423                          * must be cleared in order to get in this condition.
424                          */
425
426                         DB_RMTN(2,
427                         "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)\n",
428                         tx,smc->r.bn_flag) ;
429                 }
430                 /*RM44c*/
431                 else if (cmd == RM_TIMEOUT_ANNOUNCE && !smc->r.bn_flag) {
432                         rmt_dup_actions(smc) ;
433                 }
434                 /*RM45*/
435                 else if (cmd == RM_RING_OP) {
436                         smc->r.no_flag = FALSE ;
437                         GO_STATE(RM5_RING_OP_DUP) ;
438                         break ;
439                 }
440                 /*RM46*/
441                 else if (cmd == RM_TIMEOUT_T_STUCK &&
442                         smc->r.rm_join && smc->r.bn_flag) {
443                         GO_STATE(RM6_DIRECTED) ;
444                         break ;
445                 }
446                 break ;
447         case ACTIONS(RM5_RING_OP_DUP) :
448                 stop_rmt_timer0(smc) ;
449                 stop_rmt_timer1(smc) ;
450                 stop_rmt_timer2(smc) ;
451                 DB_RMTN(1,"RMT : RM5_RING_OP_DUP\n",0,0) ;
452                 ACTIONS_DONE() ;
453                 break;
454         case RM5_RING_OP_DUP :
455                 /*RM52*/
456                 if (smc->r.dup_addr_test == DA_PASSED) {
457                         smc->r.da_flag = FALSE ;
458                         GO_STATE(RM2_RING_OP) ;
459                         break ;
460                 }
461                 /*RM54*/
462                 else if (cmd == RM_RING_NON_OP) {
463                         smc->r.jm_flag = FALSE ;
464                         smc->r.bn_flag = FALSE ;
465                         GO_STATE(RM4_NON_OP_DUP) ;
466                         break ;
467                 }
468                 break ;
469         case ACTIONS(RM6_DIRECTED) :
470                 start_rmt_timer0(smc,smc->s.rmt_t_direct,RM_TIMEOUT_T_DIRECT) ;
471                 stop_rmt_timer1(smc) ;
472                 start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
473                 sm_ma_control(smc,MA_DIRECTED) ;
474                 RS_SET(smc,RS_BEACON) ;
475                 DB_RMTN(1,"RMT : RM6_DIRECTED\n",0,0) ;
476                 ACTIONS_DONE() ;
477                 break ;
478         case RM6_DIRECTED :
479                 /*RM63*/
480                 if (cmd == RM_TIMEOUT_POLL) {
481                         start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
482                         sm_mac_check_beacon_claim(smc) ;
483 #ifndef SUPERNET_3
484                         /* Because of problems with the Supernet II chip set
485                          * sending of Directed Beacon will stop after 165ms
486                          * therefore restart_trt_for_dbcn(smc) will be called
487                          * to prevent this.
488                          */
489                         restart_trt_for_dbcn(smc) ;
490 #endif /*SUPERNET_3*/
491                         break ;
492                 }
493                 if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
494                         !smc->r.da_flag) {
495                         smc->r.bn_flag = FALSE ;
496                         GO_STATE(RM3_DETECT) ;
497                         break ;
498                 }
499                 /*RM64*/
500                 else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
501                         smc->r.da_flag) {
502                         smc->r.bn_flag = FALSE ;
503                         GO_STATE(RM4_NON_OP_DUP) ;
504                         break ;
505                 }
506                 /*RM67*/
507                 else if (cmd == RM_TIMEOUT_T_DIRECT) {
508                         GO_STATE(RM7_TRACE) ;
509                         break ;
510                 }
511                 break ;
512         case ACTIONS(RM7_TRACE) :
513                 stop_rmt_timer0(smc) ;
514                 stop_rmt_timer1(smc) ;
515                 stop_rmt_timer2(smc) ;
516                 smc->e.trace_prop |= ENTITY_BIT(ENTITY_MAC) ;
517                 queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ;
518                 DB_RMTN(1,"RMT : RM7_TRACE\n",0,0) ;
519                 ACTIONS_DONE() ;
520                 break ;
521         case RM7_TRACE :
522                 break ;
523         default:
524                 SMT_PANIC(smc,SMT_E0122, SMT_E0122_MSG) ;
525                 break;
526         }
527 }
528
529 /*
530  * (jd) RMT duplicate address actions
531  * leave the ring or reinsert just as configured
532  */
533 static void rmt_dup_actions(struct s_smc *smc)
534 {
535         if (smc->r.jm_flag) {
536         }
537         else {
538                 if (smc->s.rmt_dup_mac_behavior) {
539                         SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;
540                         rmt_reinsert_actions(smc) ;
541                 }
542                 else {
543                         SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;
544                         rmt_leave_actions(smc) ;
545                 }
546         }
547 }
548
549 /*
550  * Reconnect to the Ring
551  */
552 static void rmt_reinsert_actions(struct s_smc *smc)
553 {
554         queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
555         queue_event(smc,EVENT_ECM,EC_CONNECT) ;
556 }
557
558 /*
559  * duplicate address detected
560  */
561 static void rmt_new_dup_actions(struct s_smc *smc)
562 {
563         smc->r.da_flag = TRUE ;
564         smc->r.bn_flag = FALSE ;
565         smc->r.jm_flag = FALSE ;
566         /*
567          * we have three options : change address, jam or leave
568          * we leave the ring as default 
569          * Optionally it's possible to reinsert after leaving the Ring
570          * but this will not conform with SMT Spec.
571          */
572         if (smc->s.rmt_dup_mac_behavior) {
573                 SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;
574                 rmt_reinsert_actions(smc) ;
575         }
576         else {
577                 SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;
578                 rmt_leave_actions(smc) ;
579         }
580 }
581
582
583 /*
584  * leave the ring
585  */
586 static void rmt_leave_actions(struct s_smc *smc)
587 {
588         queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
589         /*
590          * Note: Do NOT try again later. (with please reconnect)
591          * The station must be left from the ring!
592          */
593 }
594
595 /*
596  * SMT timer interface
597  *      start RMT timer 0
598  */
599 static void start_rmt_timer0(struct s_smc *smc, u_long value, int event)
600 {
601         smc->r.timer0_exp = FALSE ;             /* clear timer event flag */
602         smt_timer_start(smc,&smc->r.rmt_timer0,value,EV_TOKEN(EVENT_RMT,event));
603 }
604
605 /*
606  * SMT timer interface
607  *      start RMT timer 1
608  */
609 static void start_rmt_timer1(struct s_smc *smc, u_long value, int event)
610 {
611         smc->r.timer1_exp = FALSE ;     /* clear timer event flag */
612         smt_timer_start(smc,&smc->r.rmt_timer1,value,EV_TOKEN(EVENT_RMT,event));
613 }
614
615 /*
616  * SMT timer interface
617  *      start RMT timer 2
618  */
619 static void start_rmt_timer2(struct s_smc *smc, u_long value, int event)
620 {
621         smc->r.timer2_exp = FALSE ;             /* clear timer event flag */
622         smt_timer_start(smc,&smc->r.rmt_timer2,value,EV_TOKEN(EVENT_RMT,event));
623 }
624
625 /*
626  * SMT timer interface
627  *      stop RMT timer 0
628  */
629 static void stop_rmt_timer0(struct s_smc *smc)
630 {
631         if (smc->r.rmt_timer0.tm_active)
632                 smt_timer_stop(smc,&smc->r.rmt_timer0) ;
633 }
634
635 /*
636  * SMT timer interface
637  *      stop RMT timer 1
638  */
639 static void stop_rmt_timer1(struct s_smc *smc)
640 {
641         if (smc->r.rmt_timer1.tm_active)
642                 smt_timer_stop(smc,&smc->r.rmt_timer1) ;
643 }
644
645 /*
646  * SMT timer interface
647  *      stop RMT timer 2
648  */
649 static void stop_rmt_timer2(struct s_smc *smc)
650 {
651         if (smc->r.rmt_timer2.tm_active)
652                 smt_timer_stop(smc,&smc->r.rmt_timer2) ;
653 }
654