Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rmt.c
Go to the documentation of this file.
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) ;
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  */
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) ;
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) ;
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 ;
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) ;
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 ;
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) ;
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);
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,
310  }
311  /*RM32*/
312  if (cmd == RM_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,
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) ;
355  break ;
356  }
357  /*RM34b*/
358  else if (cmd == RM_MY_BEACON && smc->r.timer0_exp) {
359  rmt_new_dup_actions(smc) ;
361  break ;
362  }
363  /*RM34c*/
364  else if (cmd == RM_VALID_CLAIM) {
365  rmt_new_dup_actions(smc) ;
367  break ;
368  }
369  /*RM36*/
370  else if (cmd == RM_TIMEOUT_T_STUCK &&
371  smc->r.rm_join && smc->r.bn_flag) {
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) ;
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);
388  break ;
389  }
390  /*RM41*/
391  if (!smc->r.da_flag) {
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,
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 ;
438  break ;
439  }
440  /*RM46*/
441  else if (cmd == RM_TIMEOUT_T_STUCK &&
442  smc->r.rm_join && smc->r.bn_flag) {
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 ;
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 ;
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) ;
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);
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 ;
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 ;
504  break ;
505  }
506  /*RM67*/
507  else if (cmd == RM_TIMEOUT_T_DIRECT) {
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) ;
518  DB_RMTN(1,"RMT : RM7_TRACE\n",0,0) ;
519  ACTIONS_DONE() ;
520  break ;
521  case RM7_TRACE :
522  break ;
523  default:
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) {
540  rmt_reinsert_actions(smc) ;
541  }
542  else {
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 {
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) {
574  rmt_reinsert_actions(smc) ;
575  }
576  else {
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 {
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