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