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