Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

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