pcmplc.c 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013
  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. PCM
  18. Physical Connection Management
  19. */
  20. /*
  21. * Hardware independent state machine implemantation
  22. * The following external SMT functions are referenced :
  23. *
  24. * queue_event()
  25. * smt_timer_start()
  26. * smt_timer_stop()
  27. *
  28. * The following external HW dependent functions are referenced :
  29. * sm_pm_control()
  30. * sm_ph_linestate()
  31. * sm_pm_ls_latch()
  32. *
  33. * The following HW dependent events are required :
  34. * PC_QLS
  35. * PC_ILS
  36. * PC_HLS
  37. * PC_MLS
  38. * PC_NSE
  39. * PC_LEM
  40. *
  41. */
  42. #include "h/types.h"
  43. #include "h/fddi.h"
  44. #include "h/smc.h"
  45. #include "h/supern_2.h"
  46. #define KERNEL
  47. #include "h/smtstate.h"
  48. #ifndef lint
  49. static const char ID_sccs[] = "@(#)pcmplc.c 2.55 99/08/05 (C) SK " ;
  50. #endif
  51. #ifdef FDDI_MIB
  52. extern int snmp_fddi_trap(
  53. #ifdef ANSIC
  54. struct s_smc * smc, int type, int index
  55. #endif
  56. );
  57. #endif
  58. #ifdef CONCENTRATOR
  59. extern int plc_is_installed(
  60. #ifdef ANSIC
  61. struct s_smc *smc ,
  62. int p
  63. #endif
  64. ) ;
  65. #endif
  66. /*
  67. * FSM Macros
  68. */
  69. #define AFLAG (0x20)
  70. #define GO_STATE(x) (mib->fddiPORTPCMState = (x)|AFLAG)
  71. #define ACTIONS_DONE() (mib->fddiPORTPCMState &= ~AFLAG)
  72. #define ACTIONS(x) (x|AFLAG)
  73. /*
  74. * PCM states
  75. */
  76. #define PC0_OFF 0
  77. #define PC1_BREAK 1
  78. #define PC2_TRACE 2
  79. #define PC3_CONNECT 3
  80. #define PC4_NEXT 4
  81. #define PC5_SIGNAL 5
  82. #define PC6_JOIN 6
  83. #define PC7_VERIFY 7
  84. #define PC8_ACTIVE 8
  85. #define PC9_MAINT 9
  86. /*
  87. * symbolic state names
  88. */
  89. static const char * const pcm_states[] = {
  90. "PC0_OFF","PC1_BREAK","PC2_TRACE","PC3_CONNECT","PC4_NEXT",
  91. "PC5_SIGNAL","PC6_JOIN","PC7_VERIFY","PC8_ACTIVE","PC9_MAINT"
  92. } ;
  93. /*
  94. * symbolic event names
  95. */
  96. static const char * const pcm_events[] = {
  97. "NONE","PC_START","PC_STOP","PC_LOOP","PC_JOIN","PC_SIGNAL",
  98. "PC_REJECT","PC_MAINT","PC_TRACE","PC_PDR",
  99. "PC_ENABLE","PC_DISABLE",
  100. "PC_QLS","PC_ILS","PC_MLS","PC_HLS","PC_LS_PDR","PC_LS_NONE",
  101. "PC_TIMEOUT_TB_MAX","PC_TIMEOUT_TB_MIN",
  102. "PC_TIMEOUT_C_MIN","PC_TIMEOUT_T_OUT",
  103. "PC_TIMEOUT_TL_MIN","PC_TIMEOUT_T_NEXT","PC_TIMEOUT_LCT",
  104. "PC_NSE","PC_LEM"
  105. } ;
  106. #ifdef MOT_ELM
  107. /*
  108. * PCL-S control register
  109. * this register in the PLC-S controls the scrambling parameters
  110. */
  111. #define PLCS_CONTROL_C_U 0
  112. #define PLCS_CONTROL_C_S (PL_C_SDOFF_ENABLE | PL_C_SDON_ENABLE | \
  113. PL_C_CIPHER_ENABLE)
  114. #define PLCS_FASSERT_U 0
  115. #define PLCS_FASSERT_S 0xFd76 /* 52.0 us */
  116. #define PLCS_FDEASSERT_U 0
  117. #define PLCS_FDEASSERT_S 0
  118. #else /* nMOT_ELM */
  119. /*
  120. * PCL-S control register
  121. * this register in the PLC-S controls the scrambling parameters
  122. * can be patched for ANSI compliance if standard changes
  123. */
  124. static const u_char plcs_control_c_u[17] = "PLC_CNTRL_C_U=\0\0" ;
  125. static const u_char plcs_control_c_s[17] = "PLC_CNTRL_C_S=\01\02" ;
  126. #define PLCS_CONTROL_C_U (plcs_control_c_u[14] | (plcs_control_c_u[15]<<8))
  127. #define PLCS_CONTROL_C_S (plcs_control_c_s[14] | (plcs_control_c_s[15]<<8))
  128. #endif /* nMOT_ELM */
  129. /*
  130. * external vars
  131. */
  132. /* struct definition see 'cmtdef.h' (also used by CFM) */
  133. #define PS_OFF 0
  134. #define PS_BIT3 1
  135. #define PS_BIT4 2
  136. #define PS_BIT7 3
  137. #define PS_LCT 4
  138. #define PS_BIT8 5
  139. #define PS_JOIN 6
  140. #define PS_ACTIVE 7
  141. #define LCT_LEM_MAX 255
  142. /*
  143. * PLC timing parameter
  144. */
  145. #define PLC_MS(m) ((int)((0x10000L-(m*100000L/2048))))
  146. #define SLOW_TL_MIN PLC_MS(6)
  147. #define SLOW_C_MIN PLC_MS(10)
  148. static const struct plt {
  149. int timer ; /* relative plc timer address */
  150. int para ; /* default timing parameters */
  151. } pltm[] = {
  152. { PL_C_MIN, SLOW_C_MIN }, /* min t. to remain Connect State */
  153. { PL_TL_MIN, SLOW_TL_MIN }, /* min t. to transmit a Line State */
  154. { PL_TB_MIN, TP_TB_MIN }, /* min break time */
  155. { PL_T_OUT, TP_T_OUT }, /* Signaling timeout */
  156. { PL_LC_LENGTH, TP_LC_LENGTH }, /* Link Confidence Test Time */
  157. { PL_T_SCRUB, TP_T_SCRUB }, /* Scrub Time == MAC TVX time ! */
  158. { PL_NS_MAX, TP_NS_MAX }, /* max t. that noise is tolerated */
  159. { 0,0 }
  160. } ;
  161. /*
  162. * interrupt mask
  163. */
  164. #ifdef SUPERNET_3
  165. /*
  166. * Do we need the EBUF error during signaling, too, to detect SUPERNET_3
  167. * PLL bug?
  168. */
  169. static const int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
  170. PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR;
  171. #else /* SUPERNET_3 */
  172. /*
  173. * We do NOT need the elasticity buffer error during signaling.
  174. */
  175. static int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
  176. PL_PCM_ENABLED | PL_SELF_TEST ;
  177. #endif /* SUPERNET_3 */
  178. static const int plc_imsk_act = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
  179. PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR;
  180. /* internal functions */
  181. static void pcm_fsm(struct s_smc *smc, struct s_phy *phy, int cmd);
  182. static void pc_rcode_actions(struct s_smc *smc, int bit, struct s_phy *phy);
  183. static void pc_tcode_actions(struct s_smc *smc, const int bit, struct s_phy *phy);
  184. static void reset_lem_struct(struct s_phy *phy);
  185. static void plc_init(struct s_smc *smc, int p);
  186. static void sm_ph_lem_start(struct s_smc *smc, int np, int threshold);
  187. static void sm_ph_lem_stop(struct s_smc *smc, int np);
  188. static void sm_ph_linestate(struct s_smc *smc, int phy, int ls);
  189. static void real_init_plc(struct s_smc *smc);
  190. /*
  191. * SMT timer interface
  192. * start PCM timer 0
  193. */
  194. static void start_pcm_timer0(struct s_smc *smc, u_long value, int event,
  195. struct s_phy *phy)
  196. {
  197. phy->timer0_exp = FALSE ; /* clear timer event flag */
  198. smt_timer_start(smc,&phy->pcm_timer0,value,
  199. EV_TOKEN(EVENT_PCM+phy->np,event)) ;
  200. }
  201. /*
  202. * SMT timer interface
  203. * stop PCM timer 0
  204. */
  205. static void stop_pcm_timer0(struct s_smc *smc, struct s_phy *phy)
  206. {
  207. if (phy->pcm_timer0.tm_active)
  208. smt_timer_stop(smc,&phy->pcm_timer0) ;
  209. }
  210. /*
  211. init PCM state machine (called by driver)
  212. clear all PCM vars and flags
  213. */
  214. void pcm_init(struct s_smc *smc)
  215. {
  216. int i ;
  217. int np ;
  218. struct s_phy *phy ;
  219. struct fddi_mib_p *mib ;
  220. for (np = 0,phy = smc->y ; np < NUMPHYS ; np++,phy++) {
  221. /* Indicates the type of PHY being used */
  222. mib = phy->mib ;
  223. mib->fddiPORTPCMState = ACTIONS(PC0_OFF) ;
  224. phy->np = np ;
  225. switch (smc->s.sas) {
  226. #ifdef CONCENTRATOR
  227. case SMT_SAS :
  228. mib->fddiPORTMy_Type = (np == PS) ? TS : TM ;
  229. break ;
  230. case SMT_DAS :
  231. mib->fddiPORTMy_Type = (np == PA) ? TA :
  232. (np == PB) ? TB : TM ;
  233. break ;
  234. case SMT_NAC :
  235. mib->fddiPORTMy_Type = TM ;
  236. break;
  237. #else
  238. case SMT_SAS :
  239. mib->fddiPORTMy_Type = (np == PS) ? TS : TNONE ;
  240. mib->fddiPORTHardwarePresent = (np == PS) ? TRUE :
  241. FALSE ;
  242. #ifndef SUPERNET_3
  243. smc->y[PA].mib->fddiPORTPCMState = PC0_OFF ;
  244. #else
  245. smc->y[PB].mib->fddiPORTPCMState = PC0_OFF ;
  246. #endif
  247. break ;
  248. case SMT_DAS :
  249. mib->fddiPORTMy_Type = (np == PB) ? TB : TA ;
  250. break ;
  251. #endif
  252. }
  253. /*
  254. * set PMD-type
  255. */
  256. phy->pmd_scramble = 0 ;
  257. switch (phy->pmd_type[PMD_SK_PMD]) {
  258. case 'P' :
  259. mib->fddiPORTPMDClass = MIB_PMDCLASS_MULTI ;
  260. break ;
  261. case 'L' :
  262. mib->fddiPORTPMDClass = MIB_PMDCLASS_LCF ;
  263. break ;
  264. case 'D' :
  265. mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
  266. break ;
  267. case 'S' :
  268. mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
  269. phy->pmd_scramble = TRUE ;
  270. break ;
  271. case 'U' :
  272. mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
  273. phy->pmd_scramble = TRUE ;
  274. break ;
  275. case '1' :
  276. mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ;
  277. break ;
  278. case '2' :
  279. mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ;
  280. break ;
  281. case '3' :
  282. mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ;
  283. break ;
  284. case '4' :
  285. mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ;
  286. break ;
  287. case 'H' :
  288. mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ;
  289. break ;
  290. case 'I' :
  291. mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
  292. break ;
  293. case 'G' :
  294. mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
  295. break ;
  296. default:
  297. mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ;
  298. break ;
  299. }
  300. /*
  301. * A and B port can be on primary and secondary path
  302. */
  303. switch (mib->fddiPORTMy_Type) {
  304. case TA :
  305. mib->fddiPORTAvailablePaths |= MIB_PATH_S ;
  306. mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
  307. mib->fddiPORTRequestedPaths[2] =
  308. MIB_P_PATH_LOCAL |
  309. MIB_P_PATH_CON_ALTER |
  310. MIB_P_PATH_SEC_PREFER ;
  311. mib->fddiPORTRequestedPaths[3] =
  312. MIB_P_PATH_LOCAL |
  313. MIB_P_PATH_CON_ALTER |
  314. MIB_P_PATH_SEC_PREFER |
  315. MIB_P_PATH_THRU ;
  316. break ;
  317. case TB :
  318. mib->fddiPORTAvailablePaths |= MIB_PATH_S ;
  319. mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
  320. mib->fddiPORTRequestedPaths[2] =
  321. MIB_P_PATH_LOCAL |
  322. MIB_P_PATH_PRIM_PREFER ;
  323. mib->fddiPORTRequestedPaths[3] =
  324. MIB_P_PATH_LOCAL |
  325. MIB_P_PATH_PRIM_PREFER |
  326. MIB_P_PATH_CON_PREFER |
  327. MIB_P_PATH_THRU ;
  328. break ;
  329. case TS :
  330. mib->fddiPORTAvailablePaths |= MIB_PATH_S ;
  331. mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
  332. mib->fddiPORTRequestedPaths[2] =
  333. MIB_P_PATH_LOCAL |
  334. MIB_P_PATH_CON_ALTER |
  335. MIB_P_PATH_PRIM_PREFER ;
  336. mib->fddiPORTRequestedPaths[3] =
  337. MIB_P_PATH_LOCAL |
  338. MIB_P_PATH_CON_ALTER |
  339. MIB_P_PATH_PRIM_PREFER ;
  340. break ;
  341. case TM :
  342. mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
  343. mib->fddiPORTRequestedPaths[2] =
  344. MIB_P_PATH_LOCAL |
  345. MIB_P_PATH_SEC_ALTER |
  346. MIB_P_PATH_PRIM_ALTER ;
  347. mib->fddiPORTRequestedPaths[3] = 0 ;
  348. break ;
  349. }
  350. phy->pc_lem_fail = FALSE ;
  351. mib->fddiPORTPCMStateX = mib->fddiPORTPCMState ;
  352. mib->fddiPORTLCTFail_Ct = 0 ;
  353. mib->fddiPORTBS_Flag = 0 ;
  354. mib->fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
  355. mib->fddiPORTNeighborType = TNONE ;
  356. phy->ls_flag = 0 ;
  357. phy->rc_flag = 0 ;
  358. phy->tc_flag = 0 ;
  359. phy->td_flag = 0 ;
  360. if (np >= PM)
  361. phy->phy_name = '0' + np - PM ;
  362. else
  363. phy->phy_name = 'A' + np ;
  364. phy->wc_flag = FALSE ; /* set by SMT */
  365. memset((char *)&phy->lem,0,sizeof(struct lem_counter)) ;
  366. reset_lem_struct(phy) ;
  367. memset((char *)&phy->plc,0,sizeof(struct s_plc)) ;
  368. phy->plc.p_state = PS_OFF ;
  369. for (i = 0 ; i < NUMBITS ; i++) {
  370. phy->t_next[i] = 0 ;
  371. }
  372. }
  373. real_init_plc(smc) ;
  374. }
  375. void init_plc(struct s_smc *smc)
  376. {
  377. SK_UNUSED(smc) ;
  378. /*
  379. * dummy
  380. * this is an obsolete public entry point that has to remain
  381. * for compat. It is used by various drivers.
  382. * the work is now done in real_init_plc()
  383. * which is called from pcm_init() ;
  384. */
  385. }
  386. static void real_init_plc(struct s_smc *smc)
  387. {
  388. int p ;
  389. for (p = 0 ; p < NUMPHYS ; p++)
  390. plc_init(smc,p) ;
  391. }
  392. static void plc_init(struct s_smc *smc, int p)
  393. {
  394. int i ;
  395. #ifndef MOT_ELM
  396. int rev ; /* Revision of PLC-x */
  397. #endif /* MOT_ELM */
  398. /* transit PCM state machine to MAINT state */
  399. outpw(PLC(p,PL_CNTRL_B),0) ;
  400. outpw(PLC(p,PL_CNTRL_B),PL_PCM_STOP) ;
  401. outpw(PLC(p,PL_CNTRL_A),0) ;
  402. /*
  403. * if PLC-S then set control register C
  404. */
  405. #ifndef MOT_ELM
  406. rev = inpw(PLC(p,PL_STATUS_A)) & PLC_REV_MASK ;
  407. if (rev != PLC_REVISION_A)
  408. #endif /* MOT_ELM */
  409. {
  410. if (smc->y[p].pmd_scramble) {
  411. outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_S) ;
  412. #ifdef MOT_ELM
  413. outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_S) ;
  414. outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_S) ;
  415. #endif /* MOT_ELM */
  416. }
  417. else {
  418. outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_U) ;
  419. #ifdef MOT_ELM
  420. outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_U) ;
  421. outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_U) ;
  422. #endif /* MOT_ELM */
  423. }
  424. }
  425. /*
  426. * set timer register
  427. */
  428. for ( i = 0 ; pltm[i].timer; i++) /* set timer parameter reg */
  429. outpw(PLC(p,pltm[i].timer),pltm[i].para) ;
  430. (void)inpw(PLC(p,PL_INTR_EVENT)) ; /* clear interrupt event reg */
  431. plc_clear_irq(smc,p) ;
  432. outpw(PLC(p,PL_INTR_MASK),plc_imsk_na); /* enable non active irq's */
  433. /*
  434. * if PCM is configured for class s, it will NOT go to the
  435. * REMOVE state if offline (page 3-36;)
  436. * in the concentrator, all inactive PHYS always must be in
  437. * the remove state
  438. * there's no real need to use this feature at all ..
  439. */
  440. #ifndef CONCENTRATOR
  441. if ((smc->s.sas == SMT_SAS) && (p == PS)) {
  442. outpw(PLC(p,PL_CNTRL_B),PL_CLASS_S) ;
  443. }
  444. #endif
  445. }
  446. /*
  447. * control PCM state machine
  448. */
  449. static void plc_go_state(struct s_smc *smc, int p, int state)
  450. {
  451. HW_PTR port ;
  452. int val ;
  453. SK_UNUSED(smc) ;
  454. port = (HW_PTR) (PLC(p,PL_CNTRL_B)) ;
  455. val = inpw(port) & ~(PL_PCM_CNTRL | PL_MAINT) ;
  456. outpw(port,val) ;
  457. outpw(port,val | state) ;
  458. }
  459. /*
  460. * read current line state (called by ECM & PCM)
  461. */
  462. int sm_pm_get_ls(struct s_smc *smc, int phy)
  463. {
  464. int state ;
  465. #ifdef CONCENTRATOR
  466. if (!plc_is_installed(smc,phy))
  467. return PC_QLS;
  468. #endif
  469. state = inpw(PLC(phy,PL_STATUS_A)) & PL_LINE_ST ;
  470. switch(state) {
  471. case PL_L_QLS:
  472. state = PC_QLS ;
  473. break ;
  474. case PL_L_MLS:
  475. state = PC_MLS ;
  476. break ;
  477. case PL_L_HLS:
  478. state = PC_HLS ;
  479. break ;
  480. case PL_L_ILS4:
  481. case PL_L_ILS16:
  482. state = PC_ILS ;
  483. break ;
  484. case PL_L_ALS:
  485. state = PC_LS_PDR ;
  486. break ;
  487. default :
  488. state = PC_LS_NONE ;
  489. }
  490. return state;
  491. }
  492. static int plc_send_bits(struct s_smc *smc, struct s_phy *phy, int len)
  493. {
  494. int np = phy->np ; /* PHY index */
  495. int n ;
  496. int i ;
  497. SK_UNUSED(smc) ;
  498. /* create bit vector */
  499. for (i = len-1,n = 0 ; i >= 0 ; i--) {
  500. n = (n<<1) | phy->t_val[phy->bitn+i] ;
  501. }
  502. if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) {
  503. #if 0
  504. printf("PL_PCM_SIGNAL is set\n") ;
  505. #endif
  506. return 1;
  507. }
  508. /* write bit[n] & length = 1 to regs */
  509. outpw(PLC(np,PL_VECTOR_LEN),len-1) ; /* len=nr-1 */
  510. outpw(PLC(np,PL_XMIT_VECTOR),n) ;
  511. #ifdef DEBUG
  512. #if 1
  513. #ifdef DEBUG_BRD
  514. if (smc->debug.d_plc & 0x80)
  515. #else
  516. if (debug.d_plc & 0x80)
  517. #endif
  518. printf("SIGNALING bit %d .. %d\n",phy->bitn,phy->bitn+len-1) ;
  519. #endif
  520. #endif
  521. return 0;
  522. }
  523. /*
  524. * config plc muxes
  525. */
  526. void plc_config_mux(struct s_smc *smc, int mux)
  527. {
  528. if (smc->s.sas != SMT_DAS)
  529. return ;
  530. if (mux == MUX_WRAPB) {
  531. SETMASK(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ;
  532. SETMASK(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP,PL_SC_REM_LOOP) ;
  533. }
  534. else {
  535. CLEAR(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL) ;
  536. CLEAR(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP) ;
  537. }
  538. CLEAR(PLC(PB,PL_CNTRL_B),PL_CONFIG_CNTRL) ;
  539. CLEAR(PLC(PB,PL_CNTRL_A),PL_SC_REM_LOOP) ;
  540. }
  541. /*
  542. PCM state machine
  543. called by dispatcher & fddi_init() (driver)
  544. do
  545. display state change
  546. process event
  547. until SM is stable
  548. */
  549. void pcm(struct s_smc *smc, const int np, int event)
  550. {
  551. int state ;
  552. int oldstate ;
  553. struct s_phy *phy ;
  554. struct fddi_mib_p *mib ;
  555. #ifndef CONCENTRATOR
  556. /*
  557. * ignore 2nd PHY if SAS
  558. */
  559. if ((np != PS) && (smc->s.sas == SMT_SAS))
  560. return ;
  561. #endif
  562. phy = &smc->y[np] ;
  563. mib = phy->mib ;
  564. oldstate = mib->fddiPORTPCMState ;
  565. do {
  566. DB_PCM("PCM %c: state %s%s, event %s",
  567. phy->phy_name,
  568. mib->fddiPORTPCMState & AFLAG ? "ACTIONS " : "",
  569. pcm_states[mib->fddiPORTPCMState & ~AFLAG],
  570. pcm_events[event]);
  571. state = mib->fddiPORTPCMState ;
  572. pcm_fsm(smc,phy,event) ;
  573. event = 0 ;
  574. } while (state != mib->fddiPORTPCMState) ;
  575. /*
  576. * because the PLC does the bit signaling for us,
  577. * we're always in SIGNAL state
  578. * the MIB want's to see CONNECT
  579. * we therefore fake an entry in the MIB
  580. */
  581. if (state == PC5_SIGNAL)
  582. mib->fddiPORTPCMStateX = PC3_CONNECT ;
  583. else
  584. mib->fddiPORTPCMStateX = state ;
  585. #ifndef SLIM_SMT
  586. /*
  587. * path change
  588. */
  589. if ( mib->fddiPORTPCMState != oldstate &&
  590. ((oldstate == PC8_ACTIVE) || (mib->fddiPORTPCMState == PC8_ACTIVE))) {
  591. smt_srf_event(smc,SMT_EVENT_PORT_PATH_CHANGE,
  592. (int) (INDEX_PORT+ phy->np),0) ;
  593. }
  594. #endif
  595. #ifdef FDDI_MIB
  596. /* check whether a snmp-trap has to be sent */
  597. if ( mib->fddiPORTPCMState != oldstate ) {
  598. /* a real state change took place */
  599. DB_SNMP ("PCM from %d to %d\n", oldstate, mib->fddiPORTPCMState);
  600. if ( mib->fddiPORTPCMState == PC0_OFF ) {
  601. /* send first trap */
  602. snmp_fddi_trap (smc, 1, (int) mib->fddiPORTIndex );
  603. } else if ( oldstate == PC0_OFF ) {
  604. /* send second trap */
  605. snmp_fddi_trap (smc, 2, (int) mib->fddiPORTIndex );
  606. } else if ( mib->fddiPORTPCMState != PC2_TRACE &&
  607. oldstate == PC8_ACTIVE ) {
  608. /* send third trap */
  609. snmp_fddi_trap (smc, 3, (int) mib->fddiPORTIndex );
  610. } else if ( mib->fddiPORTPCMState == PC8_ACTIVE ) {
  611. /* send fourth trap */
  612. snmp_fddi_trap (smc, 4, (int) mib->fddiPORTIndex );
  613. }
  614. }
  615. #endif
  616. pcm_state_change(smc,np,state) ;
  617. }
  618. /*
  619. * PCM state machine
  620. */
  621. static void pcm_fsm(struct s_smc *smc, struct s_phy *phy, int cmd)
  622. {
  623. int i ;
  624. int np = phy->np ; /* PHY index */
  625. struct s_plc *plc ;
  626. struct fddi_mib_p *mib ;
  627. #ifndef MOT_ELM
  628. u_short plc_rev ; /* Revision of the plc */
  629. #endif /* nMOT_ELM */
  630. plc = &phy->plc ;
  631. mib = phy->mib ;
  632. /*
  633. * general transitions independent of state
  634. */
  635. switch (cmd) {
  636. case PC_STOP :
  637. /*PC00-PC80*/
  638. if (mib->fddiPORTPCMState != PC9_MAINT) {
  639. GO_STATE(PC0_OFF) ;
  640. AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
  641. FDDI_PORT_EVENT, (u_long) FDDI_PORT_STOP,
  642. smt_get_port_event_word(smc));
  643. }
  644. return ;
  645. case PC_START :
  646. /*PC01-PC81*/
  647. if (mib->fddiPORTPCMState != PC9_MAINT)
  648. GO_STATE(PC1_BREAK) ;
  649. return ;
  650. case PC_DISABLE :
  651. /* PC09-PC99 */
  652. GO_STATE(PC9_MAINT) ;
  653. AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
  654. FDDI_PORT_EVENT, (u_long) FDDI_PORT_DISABLED,
  655. smt_get_port_event_word(smc));
  656. return ;
  657. case PC_TIMEOUT_LCT :
  658. /* if long or extended LCT */
  659. stop_pcm_timer0(smc,phy) ;
  660. CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
  661. /* end of LCT is indicate by PCM_CODE (initiate PCM event) */
  662. return ;
  663. }
  664. switch(mib->fddiPORTPCMState) {
  665. case ACTIONS(PC0_OFF) :
  666. stop_pcm_timer0(smc,phy) ;
  667. outpw(PLC(np,PL_CNTRL_A),0) ;
  668. CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ;
  669. CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
  670. sm_ph_lem_stop(smc,np) ; /* disable LEM */
  671. phy->cf_loop = FALSE ;
  672. phy->cf_join = FALSE ;
  673. queue_event(smc,EVENT_CFM,CF_JOIN+np) ;
  674. plc_go_state(smc,np,PL_PCM_STOP) ;
  675. mib->fddiPORTConnectState = PCM_DISABLED ;
  676. ACTIONS_DONE() ;
  677. break ;
  678. case PC0_OFF:
  679. /*PC09*/
  680. if (cmd == PC_MAINT) {
  681. GO_STATE(PC9_MAINT) ;
  682. break ;
  683. }
  684. break ;
  685. case ACTIONS(PC1_BREAK) :
  686. /* Stop the LCT timer if we came from Signal state */
  687. stop_pcm_timer0(smc,phy) ;
  688. ACTIONS_DONE() ;
  689. plc_go_state(smc,np,0) ;
  690. CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ;
  691. CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
  692. sm_ph_lem_stop(smc,np) ; /* disable LEM */
  693. /*
  694. * if vector is already loaded, go to OFF to clear PCM_SIGNAL
  695. */
  696. #if 0
  697. if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) {
  698. plc_go_state(smc,np,PL_PCM_STOP) ;
  699. /* TB_MIN ? */
  700. }
  701. #endif
  702. /*
  703. * Go to OFF state in any case.
  704. */
  705. plc_go_state(smc,np,PL_PCM_STOP) ;
  706. if (mib->fddiPORTPC_Withhold == PC_WH_NONE)
  707. mib->fddiPORTConnectState = PCM_CONNECTING ;
  708. phy->cf_loop = FALSE ;
  709. phy->cf_join = FALSE ;
  710. queue_event(smc,EVENT_CFM,CF_JOIN+np) ;
  711. phy->ls_flag = FALSE ;
  712. phy->pc_mode = PM_NONE ; /* needed by CFM */
  713. phy->bitn = 0 ; /* bit signaling start bit */
  714. for (i = 0 ; i < 3 ; i++)
  715. pc_tcode_actions(smc,i,phy) ;
  716. /* Set the non-active interrupt mask register */
  717. outpw(PLC(np,PL_INTR_MASK),plc_imsk_na) ;
  718. /*
  719. * If the LCT was stopped. There might be a
  720. * PCM_CODE interrupt event present.
  721. * This must be cleared.
  722. */
  723. (void)inpw(PLC(np,PL_INTR_EVENT)) ;
  724. #ifndef MOT_ELM
  725. /* Get the plc revision for revision dependent code */
  726. plc_rev = inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK ;
  727. if (plc_rev != PLC_REV_SN3)
  728. #endif /* MOT_ELM */
  729. {
  730. /*
  731. * No supernet III PLC, so set Xmit verctor and
  732. * length BEFORE starting the state machine.
  733. */
  734. if (plc_send_bits(smc,phy,3)) {
  735. return ;
  736. }
  737. }
  738. /*
  739. * Now give the Start command.
  740. * - The start command shall be done before setting the bits
  741. * to be signaled. (In PLC-S description and PLCS in SN3.
  742. * - The start command shall be issued AFTER setting the
  743. * XMIT vector and the XMIT length register.
  744. *
  745. * We do it exactly according this specs for the old PLC and
  746. * the new PLCS inside the SN3.
  747. * For the usual PLCS we try it the way it is done for the
  748. * old PLC and set the XMIT registers again, if the PLC is
  749. * not in SIGNAL state. This is done according to an PLCS
  750. * errata workaround.
  751. */
  752. plc_go_state(smc,np,PL_PCM_START) ;
  753. /*
  754. * workaround for PLC-S eng. sample errata
  755. */
  756. #ifdef MOT_ELM
  757. if (!(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL))
  758. #else /* nMOT_ELM */
  759. if (((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) !=
  760. PLC_REVISION_A) &&
  761. !(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL))
  762. #endif /* nMOT_ELM */
  763. {
  764. /*
  765. * Set register again (PLCS errata) or the first time
  766. * (new SN3 PLCS).
  767. */
  768. (void) plc_send_bits(smc,phy,3) ;
  769. }
  770. /*
  771. * end of workaround
  772. */
  773. GO_STATE(PC5_SIGNAL) ;
  774. plc->p_state = PS_BIT3 ;
  775. plc->p_bits = 3 ;
  776. plc->p_start = 0 ;
  777. break ;
  778. case PC1_BREAK :
  779. break ;
  780. case ACTIONS(PC2_TRACE) :
  781. plc_go_state(smc,np,PL_PCM_TRACE) ;
  782. ACTIONS_DONE() ;
  783. break ;
  784. case PC2_TRACE :
  785. break ;
  786. case PC3_CONNECT : /* these states are done by hardware */
  787. case PC4_NEXT :
  788. break ;
  789. case ACTIONS(PC5_SIGNAL) :
  790. ACTIONS_DONE() ;
  791. case PC5_SIGNAL :
  792. if ((cmd != PC_SIGNAL) && (cmd != PC_TIMEOUT_LCT))
  793. break ;
  794. switch (plc->p_state) {
  795. case PS_BIT3 :
  796. for (i = 0 ; i <= 2 ; i++)
  797. pc_rcode_actions(smc,i,phy) ;
  798. pc_tcode_actions(smc,3,phy) ;
  799. plc->p_state = PS_BIT4 ;
  800. plc->p_bits = 1 ;
  801. plc->p_start = 3 ;
  802. phy->bitn = 3 ;
  803. if (plc_send_bits(smc,phy,1)) {
  804. return ;
  805. }
  806. break ;
  807. case PS_BIT4 :
  808. pc_rcode_actions(smc,3,phy) ;
  809. for (i = 4 ; i <= 6 ; i++)
  810. pc_tcode_actions(smc,i,phy) ;
  811. plc->p_state = PS_BIT7 ;
  812. plc->p_bits = 3 ;
  813. plc->p_start = 4 ;
  814. phy->bitn = 4 ;
  815. if (plc_send_bits(smc,phy,3)) {
  816. return ;
  817. }
  818. break ;
  819. case PS_BIT7 :
  820. for (i = 3 ; i <= 6 ; i++)
  821. pc_rcode_actions(smc,i,phy) ;
  822. plc->p_state = PS_LCT ;
  823. plc->p_bits = 0 ;
  824. plc->p_start = 7 ;
  825. phy->bitn = 7 ;
  826. sm_ph_lem_start(smc,np,(int)smc->s.lct_short) ; /* enable LEM */
  827. /* start LCT */
  828. i = inpw(PLC(np,PL_CNTRL_B)) & ~PL_PC_LOOP ;
  829. outpw(PLC(np,PL_CNTRL_B),i) ; /* must be cleared */
  830. outpw(PLC(np,PL_CNTRL_B),i | PL_RLBP) ;
  831. break ;
  832. case PS_LCT :
  833. /* check for local LCT failure */
  834. pc_tcode_actions(smc,7,phy) ;
  835. /*
  836. * set tval[7]
  837. */
  838. plc->p_state = PS_BIT8 ;
  839. plc->p_bits = 1 ;
  840. plc->p_start = 7 ;
  841. phy->bitn = 7 ;
  842. if (plc_send_bits(smc,phy,1)) {
  843. return ;
  844. }
  845. break ;
  846. case PS_BIT8 :
  847. /* check for remote LCT failure */
  848. pc_rcode_actions(smc,7,phy) ;
  849. if (phy->t_val[7] || phy->r_val[7]) {
  850. plc_go_state(smc,np,PL_PCM_STOP) ;
  851. GO_STATE(PC1_BREAK) ;
  852. break ;
  853. }
  854. for (i = 8 ; i <= 9 ; i++)
  855. pc_tcode_actions(smc,i,phy) ;
  856. plc->p_state = PS_JOIN ;
  857. plc->p_bits = 2 ;
  858. plc->p_start = 8 ;
  859. phy->bitn = 8 ;
  860. if (plc_send_bits(smc,phy,2)) {
  861. return ;
  862. }
  863. break ;
  864. case PS_JOIN :
  865. for (i = 8 ; i <= 9 ; i++)
  866. pc_rcode_actions(smc,i,phy) ;
  867. plc->p_state = PS_ACTIVE ;
  868. GO_STATE(PC6_JOIN) ;
  869. break ;
  870. }
  871. break ;
  872. case ACTIONS(PC6_JOIN) :
  873. /*
  874. * prevent mux error when going from WRAP_A to WRAP_B
  875. */
  876. if (smc->s.sas == SMT_DAS && np == PB &&
  877. (smc->y[PA].pc_mode == PM_TREE ||
  878. smc->y[PB].pc_mode == PM_TREE)) {
  879. SETMASK(PLC(np,PL_CNTRL_A),
  880. PL_SC_REM_LOOP,PL_SC_REM_LOOP) ;
  881. SETMASK(PLC(np,PL_CNTRL_B),
  882. PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ;
  883. }
  884. SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ;
  885. SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ;
  886. ACTIONS_DONE() ;
  887. cmd = 0 ;
  888. /* fall thru */
  889. case PC6_JOIN :
  890. switch (plc->p_state) {
  891. case PS_ACTIVE:
  892. /*PC88b*/
  893. if (!phy->cf_join) {
  894. phy->cf_join = TRUE ;
  895. queue_event(smc,EVENT_CFM,CF_JOIN+np) ;
  896. }
  897. if (cmd == PC_JOIN)
  898. GO_STATE(PC8_ACTIVE) ;
  899. /*PC82*/
  900. if (cmd == PC_TRACE) {
  901. GO_STATE(PC2_TRACE) ;
  902. break ;
  903. }
  904. break ;
  905. }
  906. break ;
  907. case PC7_VERIFY :
  908. break ;
  909. case ACTIONS(PC8_ACTIVE) :
  910. /*
  911. * start LEM for SMT
  912. */
  913. sm_ph_lem_start(smc,(int)phy->np,LCT_LEM_MAX) ;
  914. phy->tr_flag = FALSE ;
  915. mib->fddiPORTConnectState = PCM_ACTIVE ;
  916. /* Set the active interrupt mask register */
  917. outpw(PLC(np,PL_INTR_MASK),plc_imsk_act) ;
  918. ACTIONS_DONE() ;
  919. break ;
  920. case PC8_ACTIVE :
  921. /*PC81 is done by PL_TNE_EXPIRED irq */
  922. /*PC82*/
  923. if (cmd == PC_TRACE) {
  924. GO_STATE(PC2_TRACE) ;
  925. break ;
  926. }
  927. /*PC88c: is done by TRACE_PROP irq */
  928. break ;
  929. case ACTIONS(PC9_MAINT) :
  930. stop_pcm_timer0(smc,phy) ;
  931. CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ;
  932. CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
  933. CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ; /* disable LEM int. */
  934. sm_ph_lem_stop(smc,np) ; /* disable LEM */
  935. phy->cf_loop = FALSE ;
  936. phy->cf_join = FALSE ;
  937. queue_event(smc,EVENT_CFM,CF_JOIN+np) ;
  938. plc_go_state(smc,np,PL_PCM_STOP) ;
  939. mib->fddiPORTConnectState = PCM_DISABLED ;
  940. SETMASK(PLC(np,PL_CNTRL_B),PL_MAINT,PL_MAINT) ;
  941. sm_ph_linestate(smc,np,(int) MIB2LS(mib->fddiPORTMaint_LS)) ;
  942. outpw(PLC(np,PL_CNTRL_A),PL_SC_BYPASS) ;
  943. ACTIONS_DONE() ;
  944. break ;
  945. case PC9_MAINT :
  946. DB_PCMN(1, "PCM %c : MAINT", phy->phy_name);
  947. /*PC90*/
  948. if (cmd == PC_ENABLE) {
  949. GO_STATE(PC0_OFF) ;
  950. break ;
  951. }
  952. break ;
  953. default:
  954. SMT_PANIC(smc,SMT_E0118, SMT_E0118_MSG) ;
  955. break ;
  956. }
  957. }
  958. /*
  959. * force line state on a PHY output (only in MAINT state)
  960. */
  961. static void sm_ph_linestate(struct s_smc *smc, int phy, int ls)
  962. {
  963. int cntrl ;
  964. SK_UNUSED(smc) ;
  965. cntrl = (inpw(PLC(phy,PL_CNTRL_B)) & ~PL_MAINT_LS) |
  966. PL_PCM_STOP | PL_MAINT ;
  967. switch(ls) {
  968. case PC_QLS: /* Force Quiet */
  969. cntrl |= PL_M_QUI0 ;
  970. break ;
  971. case PC_MLS: /* Force Master */
  972. cntrl |= PL_M_MASTR ;
  973. break ;
  974. case PC_HLS: /* Force Halt */
  975. cntrl |= PL_M_HALT ;
  976. break ;
  977. default :
  978. case PC_ILS: /* Force Idle */
  979. cntrl |= PL_M_IDLE ;
  980. break ;
  981. case PC_LS_PDR: /* Enable repeat filter */
  982. cntrl |= PL_M_TPDR ;
  983. break ;
  984. }
  985. outpw(PLC(phy,PL_CNTRL_B),cntrl) ;
  986. }
  987. static void reset_lem_struct(struct s_phy *phy)
  988. {
  989. struct lem_counter *lem = &phy->lem ;
  990. phy->mib->fddiPORTLer_Estimate = 15 ;
  991. lem->lem_float_ber = 15 * 100 ;
  992. }
  993. /*
  994. * link error monitor
  995. */
  996. static void lem_evaluate(struct s_smc *smc, struct s_phy *phy)
  997. {
  998. int ber ;
  999. u_long errors ;
  1000. struct lem_counter *lem = &phy->lem ;
  1001. struct fddi_mib_p *mib ;
  1002. int cond ;
  1003. mib = phy->mib ;
  1004. if (!lem->lem_on)
  1005. return ;
  1006. errors = inpw(PLC(((int) phy->np),PL_LINK_ERR_CTR)) ;
  1007. lem->lem_errors += errors ;
  1008. mib->fddiPORTLem_Ct += errors ;
  1009. errors = lem->lem_errors ;
  1010. /*
  1011. * calculation is called on a intervall of 8 seconds
  1012. * -> this means, that one error in 8 sec. is one of 8*125*10E6
  1013. * the same as BER = 10E-9
  1014. * Please note:
  1015. * -> 9 errors in 8 seconds mean:
  1016. * BER = 9 * 10E-9 and this is
  1017. * < 10E-8, so the limit of 10E-8 is not reached!
  1018. */
  1019. if (!errors) ber = 15 ;
  1020. else if (errors <= 9) ber = 9 ;
  1021. else if (errors <= 99) ber = 8 ;
  1022. else if (errors <= 999) ber = 7 ;
  1023. else if (errors <= 9999) ber = 6 ;
  1024. else if (errors <= 99999) ber = 5 ;
  1025. else if (errors <= 999999) ber = 4 ;
  1026. else if (errors <= 9999999) ber = 3 ;
  1027. else if (errors <= 99999999) ber = 2 ;
  1028. else if (errors <= 999999999) ber = 1 ;
  1029. else ber = 0 ;
  1030. /*
  1031. * weighted average
  1032. */
  1033. ber *= 100 ;
  1034. lem->lem_float_ber = lem->lem_float_ber * 7 + ber * 3 ;
  1035. lem->lem_float_ber /= 10 ;
  1036. mib->fddiPORTLer_Estimate = lem->lem_float_ber / 100 ;
  1037. if (mib->fddiPORTLer_Estimate < 4) {
  1038. mib->fddiPORTLer_Estimate = 4 ;
  1039. }
  1040. if (lem->lem_errors) {
  1041. DB_PCMN(1, "LEM %c :", phy->np == PB ? 'B' : 'A');
  1042. DB_PCMN(1, "errors : %ld", lem->lem_errors);
  1043. DB_PCMN(1, "sum_errors : %ld", mib->fddiPORTLem_Ct);
  1044. DB_PCMN(1, "current BER : 10E-%d", ber / 100);
  1045. DB_PCMN(1, "float BER : 10E-(%d/100)", lem->lem_float_ber);
  1046. DB_PCMN(1, "avg. BER : 10E-%d", mib->fddiPORTLer_Estimate);
  1047. }
  1048. lem->lem_errors = 0L ;
  1049. #ifndef SLIM_SMT
  1050. cond = (mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Alarm) ?
  1051. TRUE : FALSE ;
  1052. #ifdef SMT_EXT_CUTOFF
  1053. smt_ler_alarm_check(smc,phy,cond) ;
  1054. #endif /* nSMT_EXT_CUTOFF */
  1055. if (cond != mib->fddiPORTLerFlag) {
  1056. smt_srf_event(smc,SMT_COND_PORT_LER,
  1057. (int) (INDEX_PORT+ phy->np) ,cond) ;
  1058. }
  1059. #endif
  1060. if ( mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Cutoff) {
  1061. phy->pc_lem_fail = TRUE ; /* flag */
  1062. mib->fddiPORTLem_Reject_Ct++ ;
  1063. /*
  1064. * "forgive 10e-2" if we cutoff so we can come
  1065. * up again ..
  1066. */
  1067. lem->lem_float_ber += 2*100 ;
  1068. /*PC81b*/
  1069. #ifdef CONCENTRATOR
  1070. DB_PCMN(1, "PCM: LER cutoff on port %d cutoff %d",
  1071. phy->np, mib->fddiPORTLer_Cutoff);
  1072. #endif
  1073. #ifdef SMT_EXT_CUTOFF
  1074. smt_port_off_event(smc,phy->np);
  1075. #else /* nSMT_EXT_CUTOFF */
  1076. queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ;
  1077. #endif /* nSMT_EXT_CUTOFF */
  1078. }
  1079. }
  1080. /*
  1081. * called by SMT to calculate LEM bit error rate
  1082. */
  1083. void sm_lem_evaluate(struct s_smc *smc)
  1084. {
  1085. int np ;
  1086. for (np = 0 ; np < NUMPHYS ; np++)
  1087. lem_evaluate(smc,&smc->y[np]) ;
  1088. }
  1089. static void lem_check_lct(struct s_smc *smc, struct s_phy *phy)
  1090. {
  1091. struct lem_counter *lem = &phy->lem ;
  1092. struct fddi_mib_p *mib ;
  1093. int errors ;
  1094. mib = phy->mib ;
  1095. phy->pc_lem_fail = FALSE ; /* flag */
  1096. errors = inpw(PLC(((int)phy->np),PL_LINK_ERR_CTR)) ;
  1097. lem->lem_errors += errors ;
  1098. mib->fddiPORTLem_Ct += errors ;
  1099. if (lem->lem_errors) {
  1100. switch(phy->lc_test) {
  1101. case LC_SHORT:
  1102. if (lem->lem_errors >= smc->s.lct_short)
  1103. phy->pc_lem_fail = TRUE ;
  1104. break ;
  1105. case LC_MEDIUM:
  1106. if (lem->lem_errors >= smc->s.lct_medium)
  1107. phy->pc_lem_fail = TRUE ;
  1108. break ;
  1109. case LC_LONG:
  1110. if (lem->lem_errors >= smc->s.lct_long)
  1111. phy->pc_lem_fail = TRUE ;
  1112. break ;
  1113. case LC_EXTENDED:
  1114. if (lem->lem_errors >= smc->s.lct_extended)
  1115. phy->pc_lem_fail = TRUE ;
  1116. break ;
  1117. }
  1118. DB_PCMN(1, " >>errors : %lu", lem->lem_errors);
  1119. }
  1120. if (phy->pc_lem_fail) {
  1121. mib->fddiPORTLCTFail_Ct++ ;
  1122. mib->fddiPORTLem_Reject_Ct++ ;
  1123. }
  1124. else
  1125. mib->fddiPORTLCTFail_Ct = 0 ;
  1126. }
  1127. /*
  1128. * LEM functions
  1129. */
  1130. static void sm_ph_lem_start(struct s_smc *smc, int np, int threshold)
  1131. {
  1132. struct lem_counter *lem = &smc->y[np].lem ;
  1133. lem->lem_on = 1 ;
  1134. lem->lem_errors = 0L ;
  1135. /* Do NOT reset mib->fddiPORTLer_Estimate here. It is called too
  1136. * often.
  1137. */
  1138. outpw(PLC(np,PL_LE_THRESHOLD),threshold) ;
  1139. (void)inpw(PLC(np,PL_LINK_ERR_CTR)) ; /* clear error counter */
  1140. /* enable LE INT */
  1141. SETMASK(PLC(np,PL_INTR_MASK),PL_LE_CTR,PL_LE_CTR) ;
  1142. }
  1143. static void sm_ph_lem_stop(struct s_smc *smc, int np)
  1144. {
  1145. struct lem_counter *lem = &smc->y[np].lem ;
  1146. lem->lem_on = 0 ;
  1147. CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ;
  1148. }
  1149. /* ARGSUSED */
  1150. void sm_pm_ls_latch(struct s_smc *smc, int phy, int on_off)
  1151. /* int on_off; en- or disable ident. ls */
  1152. {
  1153. SK_UNUSED(smc) ;
  1154. phy = phy ; on_off = on_off ;
  1155. }
  1156. /*
  1157. * PCM pseudo code
  1158. * receive actions are called AFTER the bit n is received,
  1159. * i.e. if pc_rcode_actions(5) is called, bit 6 is the next bit to be received
  1160. */
  1161. /*
  1162. * PCM pseudo code 5.1 .. 6.1
  1163. */
  1164. static void pc_rcode_actions(struct s_smc *smc, int bit, struct s_phy *phy)
  1165. {
  1166. struct fddi_mib_p *mib ;
  1167. mib = phy->mib ;
  1168. DB_PCMN(1, "SIG rec %x %x:", bit, phy->r_val[bit]);
  1169. bit++ ;
  1170. switch(bit) {
  1171. case 0:
  1172. case 1:
  1173. case 2:
  1174. break ;
  1175. case 3 :
  1176. if (phy->r_val[1] == 0 && phy->r_val[2] == 0)
  1177. mib->fddiPORTNeighborType = TA ;
  1178. else if (phy->r_val[1] == 0 && phy->r_val[2] == 1)
  1179. mib->fddiPORTNeighborType = TB ;
  1180. else if (phy->r_val[1] == 1 && phy->r_val[2] == 0)
  1181. mib->fddiPORTNeighborType = TS ;
  1182. else if (phy->r_val[1] == 1 && phy->r_val[2] == 1)
  1183. mib->fddiPORTNeighborType = TM ;
  1184. break ;
  1185. case 4:
  1186. if (mib->fddiPORTMy_Type == TM &&
  1187. mib->fddiPORTNeighborType == TM) {
  1188. DB_PCMN(1, "PCM %c : E100 withhold M-M",
  1189. phy->phy_name);
  1190. mib->fddiPORTPC_Withhold = PC_WH_M_M ;
  1191. RS_SET(smc,RS_EVENT) ;
  1192. }
  1193. else if (phy->t_val[3] || phy->r_val[3]) {
  1194. mib->fddiPORTPC_Withhold = PC_WH_NONE ;
  1195. if (mib->fddiPORTMy_Type == TM ||
  1196. mib->fddiPORTNeighborType == TM)
  1197. phy->pc_mode = PM_TREE ;
  1198. else
  1199. phy->pc_mode = PM_PEER ;
  1200. /* reevaluate the selection criteria (wc_flag) */
  1201. all_selection_criteria (smc);
  1202. if (phy->wc_flag) {
  1203. mib->fddiPORTPC_Withhold = PC_WH_PATH ;
  1204. }
  1205. }
  1206. else {
  1207. mib->fddiPORTPC_Withhold = PC_WH_OTHER ;
  1208. RS_SET(smc,RS_EVENT) ;
  1209. DB_PCMN(1, "PCM %c : E101 withhold other",
  1210. phy->phy_name);
  1211. }
  1212. phy->twisted = ((mib->fddiPORTMy_Type != TS) &&
  1213. (mib->fddiPORTMy_Type != TM) &&
  1214. (mib->fddiPORTNeighborType ==
  1215. mib->fddiPORTMy_Type)) ;
  1216. if (phy->twisted) {
  1217. DB_PCMN(1, "PCM %c : E102 !!! TWISTED !!!",
  1218. phy->phy_name);
  1219. }
  1220. break ;
  1221. case 5 :
  1222. break ;
  1223. case 6:
  1224. if (phy->t_val[4] || phy->r_val[4]) {
  1225. if ((phy->t_val[4] && phy->t_val[5]) ||
  1226. (phy->r_val[4] && phy->r_val[5]) )
  1227. phy->lc_test = LC_EXTENDED ;
  1228. else
  1229. phy->lc_test = LC_LONG ;
  1230. }
  1231. else if (phy->t_val[5] || phy->r_val[5])
  1232. phy->lc_test = LC_MEDIUM ;
  1233. else
  1234. phy->lc_test = LC_SHORT ;
  1235. switch (phy->lc_test) {
  1236. case LC_SHORT : /* 50ms */
  1237. outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LENGTH ) ;
  1238. phy->t_next[7] = smc->s.pcm_lc_short ;
  1239. break ;
  1240. case LC_MEDIUM : /* 500ms */
  1241. outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LONGLN ) ;
  1242. phy->t_next[7] = smc->s.pcm_lc_medium ;
  1243. break ;
  1244. case LC_LONG :
  1245. SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ;
  1246. phy->t_next[7] = smc->s.pcm_lc_long ;
  1247. break ;
  1248. case LC_EXTENDED :
  1249. SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ;
  1250. phy->t_next[7] = smc->s.pcm_lc_extended ;
  1251. break ;
  1252. }
  1253. if (phy->t_next[7] > smc->s.pcm_lc_medium) {
  1254. start_pcm_timer0(smc,phy->t_next[7],PC_TIMEOUT_LCT,phy);
  1255. }
  1256. DB_PCMN(1, "LCT timer = %ld us", phy->t_next[7]);
  1257. phy->t_next[9] = smc->s.pcm_t_next_9 ;
  1258. break ;
  1259. case 7:
  1260. if (phy->t_val[6]) {
  1261. phy->cf_loop = TRUE ;
  1262. }
  1263. phy->td_flag = TRUE ;
  1264. break ;
  1265. case 8:
  1266. if (phy->t_val[7] || phy->r_val[7]) {
  1267. DB_PCMN(1, "PCM %c : E103 LCT fail %s",
  1268. phy->phy_name,
  1269. phy->t_val[7] ? "local" : "remote");
  1270. queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ;
  1271. }
  1272. break ;
  1273. case 9:
  1274. if (phy->t_val[8] || phy->r_val[8]) {
  1275. if (phy->t_val[8])
  1276. phy->cf_loop = TRUE ;
  1277. phy->td_flag = TRUE ;
  1278. }
  1279. break ;
  1280. case 10:
  1281. if (phy->r_val[9]) {
  1282. /* neighbor intends to have MAC on output */ ;
  1283. mib->fddiPORTMacIndicated.R_val = TRUE ;
  1284. }
  1285. else {
  1286. /* neighbor does not intend to have MAC on output */ ;
  1287. mib->fddiPORTMacIndicated.R_val = FALSE ;
  1288. }
  1289. break ;
  1290. }
  1291. }
  1292. /*
  1293. * PCM pseudo code 5.1 .. 6.1
  1294. */
  1295. static void pc_tcode_actions(struct s_smc *smc, const int bit, struct s_phy *phy)
  1296. {
  1297. int np = phy->np ;
  1298. struct fddi_mib_p *mib ;
  1299. mib = phy->mib ;
  1300. switch(bit) {
  1301. case 0:
  1302. phy->t_val[0] = 0 ; /* no escape used */
  1303. break ;
  1304. case 1:
  1305. if (mib->fddiPORTMy_Type == TS || mib->fddiPORTMy_Type == TM)
  1306. phy->t_val[1] = 1 ;
  1307. else
  1308. phy->t_val[1] = 0 ;
  1309. break ;
  1310. case 2 :
  1311. if (mib->fddiPORTMy_Type == TB || mib->fddiPORTMy_Type == TM)
  1312. phy->t_val[2] = 1 ;
  1313. else
  1314. phy->t_val[2] = 0 ;
  1315. break ;
  1316. case 3:
  1317. {
  1318. int type,ne ;
  1319. int policy ;
  1320. type = mib->fddiPORTMy_Type ;
  1321. ne = mib->fddiPORTNeighborType ;
  1322. policy = smc->mib.fddiSMTConnectionPolicy ;
  1323. phy->t_val[3] = 1 ; /* Accept connection */
  1324. switch (type) {
  1325. case TA :
  1326. if (
  1327. ((policy & POLICY_AA) && ne == TA) ||
  1328. ((policy & POLICY_AB) && ne == TB) ||
  1329. ((policy & POLICY_AS) && ne == TS) ||
  1330. ((policy & POLICY_AM) && ne == TM) )
  1331. phy->t_val[3] = 0 ; /* Reject */
  1332. break ;
  1333. case TB :
  1334. if (
  1335. ((policy & POLICY_BA) && ne == TA) ||
  1336. ((policy & POLICY_BB) && ne == TB) ||
  1337. ((policy & POLICY_BS) && ne == TS) ||
  1338. ((policy & POLICY_BM) && ne == TM) )
  1339. phy->t_val[3] = 0 ; /* Reject */
  1340. break ;
  1341. case TS :
  1342. if (
  1343. ((policy & POLICY_SA) && ne == TA) ||
  1344. ((policy & POLICY_SB) && ne == TB) ||
  1345. ((policy & POLICY_SS) && ne == TS) ||
  1346. ((policy & POLICY_SM) && ne == TM) )
  1347. phy->t_val[3] = 0 ; /* Reject */
  1348. break ;
  1349. case TM :
  1350. if ( ne == TM ||
  1351. ((policy & POLICY_MA) && ne == TA) ||
  1352. ((policy & POLICY_MB) && ne == TB) ||
  1353. ((policy & POLICY_MS) && ne == TS) ||
  1354. ((policy & POLICY_MM) && ne == TM) )
  1355. phy->t_val[3] = 0 ; /* Reject */
  1356. break ;
  1357. }
  1358. #ifndef SLIM_SMT
  1359. /*
  1360. * detect undesirable connection attempt event
  1361. */
  1362. if ( (type == TA && ne == TA ) ||
  1363. (type == TA && ne == TS ) ||
  1364. (type == TB && ne == TB ) ||
  1365. (type == TB && ne == TS ) ||
  1366. (type == TS && ne == TA ) ||
  1367. (type == TS && ne == TB ) ) {
  1368. smt_srf_event(smc,SMT_EVENT_PORT_CONNECTION,
  1369. (int) (INDEX_PORT+ phy->np) ,0) ;
  1370. }
  1371. #endif
  1372. }
  1373. break ;
  1374. case 4:
  1375. if (mib->fddiPORTPC_Withhold == PC_WH_NONE) {
  1376. if (phy->pc_lem_fail) {
  1377. phy->t_val[4] = 1 ; /* long */
  1378. phy->t_val[5] = 0 ;
  1379. }
  1380. else {
  1381. phy->t_val[4] = 0 ;
  1382. if (mib->fddiPORTLCTFail_Ct > 0)
  1383. phy->t_val[5] = 1 ; /* medium */
  1384. else
  1385. phy->t_val[5] = 0 ; /* short */
  1386. /*
  1387. * Implementers choice: use medium
  1388. * instead of short when undesired
  1389. * connection attempt is made.
  1390. */
  1391. if (phy->wc_flag)
  1392. phy->t_val[5] = 1 ; /* medium */
  1393. }
  1394. mib->fddiPORTConnectState = PCM_CONNECTING ;
  1395. }
  1396. else {
  1397. mib->fddiPORTConnectState = PCM_STANDBY ;
  1398. phy->t_val[4] = 1 ; /* extended */
  1399. phy->t_val[5] = 1 ;
  1400. }
  1401. break ;
  1402. case 5:
  1403. break ;
  1404. case 6:
  1405. /* we do NOT have a MAC for LCT */
  1406. phy->t_val[6] = 0 ;
  1407. break ;
  1408. case 7:
  1409. phy->cf_loop = FALSE ;
  1410. lem_check_lct(smc,phy) ;
  1411. if (phy->pc_lem_fail) {
  1412. DB_PCMN(1, "PCM %c : E104 LCT failed", phy->phy_name);
  1413. phy->t_val[7] = 1 ;
  1414. }
  1415. else
  1416. phy->t_val[7] = 0 ;
  1417. break ;
  1418. case 8:
  1419. phy->t_val[8] = 0 ; /* Don't request MAC loopback */
  1420. break ;
  1421. case 9:
  1422. phy->cf_loop = 0 ;
  1423. if ((mib->fddiPORTPC_Withhold != PC_WH_NONE) ||
  1424. ((smc->s.sas == SMT_DAS) && (phy->wc_flag))) {
  1425. queue_event(smc,EVENT_PCM+np,PC_START) ;
  1426. break ;
  1427. }
  1428. phy->t_val[9] = FALSE ;
  1429. switch (smc->s.sas) {
  1430. case SMT_DAS :
  1431. /*
  1432. * MAC intended on output
  1433. */
  1434. if (phy->pc_mode == PM_TREE) {
  1435. if ((np == PB) || ((np == PA) &&
  1436. (smc->y[PB].mib->fddiPORTConnectState !=
  1437. PCM_ACTIVE)))
  1438. phy->t_val[9] = TRUE ;
  1439. }
  1440. else {
  1441. if (np == PB)
  1442. phy->t_val[9] = TRUE ;
  1443. }
  1444. break ;
  1445. case SMT_SAS :
  1446. if (np == PS)
  1447. phy->t_val[9] = TRUE ;
  1448. break ;
  1449. #ifdef CONCENTRATOR
  1450. case SMT_NAC :
  1451. /*
  1452. * MAC intended on output
  1453. */
  1454. if (np == PB)
  1455. phy->t_val[9] = TRUE ;
  1456. break ;
  1457. #endif
  1458. }
  1459. mib->fddiPORTMacIndicated.T_val = phy->t_val[9] ;
  1460. break ;
  1461. }
  1462. DB_PCMN(1, "SIG snd %x %x:", bit, phy->t_val[bit]);
  1463. }
  1464. /*
  1465. * return status twisted (called by SMT)
  1466. */
  1467. int pcm_status_twisted(struct s_smc *smc)
  1468. {
  1469. int twist = 0 ;
  1470. if (smc->s.sas != SMT_DAS)
  1471. return 0;
  1472. if (smc->y[PA].twisted && (smc->y[PA].mib->fddiPORTPCMState == PC8_ACTIVE))
  1473. twist |= 1 ;
  1474. if (smc->y[PB].twisted && (smc->y[PB].mib->fddiPORTPCMState == PC8_ACTIVE))
  1475. twist |= 2 ;
  1476. return twist;
  1477. }
  1478. /*
  1479. * return status (called by SMT)
  1480. * type
  1481. * state
  1482. * remote phy type
  1483. * remote mac yes/no
  1484. */
  1485. void pcm_status_state(struct s_smc *smc, int np, int *type, int *state,
  1486. int *remote, int *mac)
  1487. {
  1488. struct s_phy *phy = &smc->y[np] ;
  1489. struct fddi_mib_p *mib ;
  1490. mib = phy->mib ;
  1491. /* remote PHY type and MAC - set only if active */
  1492. *mac = 0 ;
  1493. *type = mib->fddiPORTMy_Type ; /* our PHY type */
  1494. *state = mib->fddiPORTConnectState ;
  1495. *remote = mib->fddiPORTNeighborType ;
  1496. switch(mib->fddiPORTPCMState) {
  1497. case PC8_ACTIVE :
  1498. *mac = mib->fddiPORTMacIndicated.R_val ;
  1499. break ;
  1500. }
  1501. }
  1502. /*
  1503. * return rooted station status (called by SMT)
  1504. */
  1505. int pcm_rooted_station(struct s_smc *smc)
  1506. {
  1507. int n ;
  1508. for (n = 0 ; n < NUMPHYS ; n++) {
  1509. if (smc->y[n].mib->fddiPORTPCMState == PC8_ACTIVE &&
  1510. smc->y[n].mib->fddiPORTNeighborType == TM)
  1511. return 0;
  1512. }
  1513. return 1;
  1514. }
  1515. /*
  1516. * Interrupt actions for PLC & PCM events
  1517. */
  1518. void plc_irq(struct s_smc *smc, int np, unsigned int cmd)
  1519. /* int np; PHY index */
  1520. {
  1521. struct s_phy *phy = &smc->y[np] ;
  1522. struct s_plc *plc = &phy->plc ;
  1523. int n ;
  1524. #ifdef SUPERNET_3
  1525. int corr_mask ;
  1526. #endif /* SUPERNET_3 */
  1527. int i ;
  1528. if (np >= smc->s.numphys) {
  1529. plc->soft_err++ ;
  1530. return ;
  1531. }
  1532. if (cmd & PL_EBUF_ERR) { /* elastic buff. det. over-|underflow*/
  1533. /*
  1534. * Check whether the SRF Condition occurred.
  1535. */
  1536. if (!plc->ebuf_cont && phy->mib->fddiPORTPCMState == PC8_ACTIVE){
  1537. /*
  1538. * This is the real Elasticity Error.
  1539. * More than one in a row are treated as a
  1540. * single one.
  1541. * Only count this in the active state.
  1542. */
  1543. phy->mib->fddiPORTEBError_Ct ++ ;
  1544. }
  1545. plc->ebuf_err++ ;
  1546. if (plc->ebuf_cont <= 1000) {
  1547. /*
  1548. * Prevent counter from being wrapped after
  1549. * hanging years in that interrupt.
  1550. */
  1551. plc->ebuf_cont++ ; /* Ebuf continuous error */
  1552. }
  1553. #ifdef SUPERNET_3
  1554. if (plc->ebuf_cont == 1000 &&
  1555. ((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) ==
  1556. PLC_REV_SN3)) {
  1557. /*
  1558. * This interrupt remeained high for at least
  1559. * 1000 consecutive interrupt calls.
  1560. *
  1561. * This is caused by a hardware error of the
  1562. * ORION part of the Supernet III chipset.
  1563. *
  1564. * Disable this bit from the mask.
  1565. */
  1566. corr_mask = (plc_imsk_na & ~PL_EBUF_ERR) ;
  1567. outpw(PLC(np,PL_INTR_MASK),corr_mask);
  1568. /*
  1569. * Disconnect from the ring.
  1570. * Call the driver with the reset indication.
  1571. */
  1572. queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
  1573. /*
  1574. * Make an error log entry.
  1575. */
  1576. SMT_ERR_LOG(smc,SMT_E0136, SMT_E0136_MSG) ;
  1577. /*
  1578. * Indicate the Reset.
  1579. */
  1580. drv_reset_indication(smc) ;
  1581. }
  1582. #endif /* SUPERNET_3 */
  1583. } else {
  1584. /* Reset the continuous error variable */
  1585. plc->ebuf_cont = 0 ; /* reset Ebuf continuous error */
  1586. }
  1587. if (cmd & PL_PHYINV) { /* physical layer invalid signal */
  1588. plc->phyinv++ ;
  1589. }
  1590. if (cmd & PL_VSYM_CTR) { /* violation symbol counter has incr.*/
  1591. plc->vsym_ctr++ ;
  1592. }
  1593. if (cmd & PL_MINI_CTR) { /* dep. on PLC_CNTRL_A's MINI_CTR_INT*/
  1594. plc->mini_ctr++ ;
  1595. }
  1596. if (cmd & PL_LE_CTR) { /* link error event counter */
  1597. int j ;
  1598. /*
  1599. * note: PL_LINK_ERR_CTR MUST be read to clear it
  1600. */
  1601. j = inpw(PLC(np,PL_LE_THRESHOLD)) ;
  1602. i = inpw(PLC(np,PL_LINK_ERR_CTR)) ;
  1603. if (i < j) {
  1604. /* wrapped around */
  1605. i += 256 ;
  1606. }
  1607. if (phy->lem.lem_on) {
  1608. /* Note: Lem errors shall only be counted when
  1609. * link is ACTIVE or LCT is active.
  1610. */
  1611. phy->lem.lem_errors += i ;
  1612. phy->mib->fddiPORTLem_Ct += i ;
  1613. }
  1614. }
  1615. if (cmd & PL_TPC_EXPIRED) { /* TPC timer reached zero */
  1616. if (plc->p_state == PS_LCT) {
  1617. /*
  1618. * end of LCT
  1619. */
  1620. ;
  1621. }
  1622. plc->tpc_exp++ ;
  1623. }
  1624. if (cmd & PL_LS_MATCH) { /* LS == LS in PLC_CNTRL_B's MATCH_LS*/
  1625. switch (inpw(PLC(np,PL_CNTRL_B)) & PL_MATCH_LS) {
  1626. case PL_I_IDLE : phy->curr_ls = PC_ILS ; break ;
  1627. case PL_I_HALT : phy->curr_ls = PC_HLS ; break ;
  1628. case PL_I_MASTR : phy->curr_ls = PC_MLS ; break ;
  1629. case PL_I_QUIET : phy->curr_ls = PC_QLS ; break ;
  1630. }
  1631. }
  1632. if (cmd & PL_PCM_BREAK) { /* PCM has entered the BREAK state */
  1633. int reason;
  1634. reason = inpw(PLC(np,PL_STATUS_B)) & PL_BREAK_REASON ;
  1635. switch (reason) {
  1636. case PL_B_PCS : plc->b_pcs++ ; break ;
  1637. case PL_B_TPC : plc->b_tpc++ ; break ;
  1638. case PL_B_TNE : plc->b_tne++ ; break ;
  1639. case PL_B_QLS : plc->b_qls++ ; break ;
  1640. case PL_B_ILS : plc->b_ils++ ; break ;
  1641. case PL_B_HLS : plc->b_hls++ ; break ;
  1642. }
  1643. /*jd 05-Aug-1999 changed: Bug #10419 */
  1644. DB_PCMN(1, "PLC %d: MDcF = %x", np, smc->e.DisconnectFlag);
  1645. if (smc->e.DisconnectFlag == FALSE) {
  1646. DB_PCMN(1, "PLC %d: restart (reason %x)", np, reason);
  1647. queue_event(smc,EVENT_PCM+np,PC_START) ;
  1648. }
  1649. else {
  1650. DB_PCMN(1, "PLC %d: NO!! restart (reason %x)",
  1651. np, reason);
  1652. }
  1653. return ;
  1654. }
  1655. /*
  1656. * If both CODE & ENABLE are set ignore enable
  1657. */
  1658. if (cmd & PL_PCM_CODE) { /* receive last sign.-bit | LCT complete */
  1659. queue_event(smc,EVENT_PCM+np,PC_SIGNAL) ;
  1660. n = inpw(PLC(np,PL_RCV_VECTOR)) ;
  1661. for (i = 0 ; i < plc->p_bits ; i++) {
  1662. phy->r_val[plc->p_start+i] = n & 1 ;
  1663. n >>= 1 ;
  1664. }
  1665. }
  1666. else if (cmd & PL_PCM_ENABLED) { /* asserted SC_JOIN, scrub.completed*/
  1667. queue_event(smc,EVENT_PCM+np,PC_JOIN) ;
  1668. }
  1669. if (cmd & PL_TRACE_PROP) { /* MLS while PC8_ACTIV || PC2_TRACE */
  1670. /*PC22b*/
  1671. if (!phy->tr_flag) {
  1672. DB_PCMN(1, "PCM : irq TRACE_PROP %d %d",
  1673. np, smc->mib.fddiSMTECMState);
  1674. phy->tr_flag = TRUE ;
  1675. smc->e.trace_prop |= ENTITY_BIT(ENTITY_PHY(np)) ;
  1676. queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ;
  1677. }
  1678. }
  1679. /*
  1680. * filter PLC glitch ???
  1681. * QLS || HLS only while in PC2_TRACE state
  1682. */
  1683. if ((cmd & PL_SELF_TEST) && (phy->mib->fddiPORTPCMState == PC2_TRACE)) {
  1684. /*PC22a*/
  1685. if (smc->e.path_test == PT_PASSED) {
  1686. DB_PCMN(1, "PCM : state = %s %d",
  1687. get_pcmstate(smc, np),
  1688. phy->mib->fddiPORTPCMState);
  1689. smc->e.path_test = PT_PENDING ;
  1690. queue_event(smc,EVENT_ECM,EC_PATH_TEST) ;
  1691. }
  1692. }
  1693. if (cmd & PL_TNE_EXPIRED) { /* TNE: length of noise events */
  1694. /* break_required (TNE > NS_Max) */
  1695. if (phy->mib->fddiPORTPCMState == PC8_ACTIVE) {
  1696. if (!phy->tr_flag) {
  1697. DB_PCMN(1, "PCM %c : PC81 %s",
  1698. phy->phy_name, "NSE");
  1699. queue_event(smc, EVENT_PCM + np, PC_START);
  1700. return;
  1701. }
  1702. }
  1703. }
  1704. #if 0
  1705. if (cmd & PL_NP_ERR) { /* NP has requested to r/w an inv reg*/
  1706. /*
  1707. * It's a bug by AMD
  1708. */
  1709. plc->np_err++ ;
  1710. }
  1711. /* pin inactiv (GND) */
  1712. if (cmd & PL_PARITY_ERR) { /* p. error dedected on TX9-0 inp */
  1713. plc->parity_err++ ;
  1714. }
  1715. if (cmd & PL_LSDO) { /* carrier detected */
  1716. ;
  1717. }
  1718. #endif
  1719. }
  1720. #ifdef DEBUG
  1721. /*
  1722. * fill state struct
  1723. */
  1724. void pcm_get_state(struct s_smc *smc, struct smt_state *state)
  1725. {
  1726. struct s_phy *phy ;
  1727. struct pcm_state *pcs ;
  1728. int i ;
  1729. int ii ;
  1730. short rbits ;
  1731. short tbits ;
  1732. struct fddi_mib_p *mib ;
  1733. for (i = 0, phy = smc->y, pcs = state->pcm_state ; i < NUMPHYS ;
  1734. i++ , phy++, pcs++ ) {
  1735. mib = phy->mib ;
  1736. pcs->pcm_type = (u_char) mib->fddiPORTMy_Type ;
  1737. pcs->pcm_state = (u_char) mib->fddiPORTPCMState ;
  1738. pcs->pcm_mode = phy->pc_mode ;
  1739. pcs->pcm_neighbor = (u_char) mib->fddiPORTNeighborType ;
  1740. pcs->pcm_bsf = mib->fddiPORTBS_Flag ;
  1741. pcs->pcm_lsf = phy->ls_flag ;
  1742. pcs->pcm_lct_fail = (u_char) mib->fddiPORTLCTFail_Ct ;
  1743. pcs->pcm_ls_rx = LS2MIB(sm_pm_get_ls(smc,i)) ;
  1744. for (ii = 0, rbits = tbits = 0 ; ii < NUMBITS ; ii++) {
  1745. rbits <<= 1 ;
  1746. tbits <<= 1 ;
  1747. if (phy->r_val[NUMBITS-1-ii])
  1748. rbits |= 1 ;
  1749. if (phy->t_val[NUMBITS-1-ii])
  1750. tbits |= 1 ;
  1751. }
  1752. pcs->pcm_r_val = rbits ;
  1753. pcs->pcm_t_val = tbits ;
  1754. }
  1755. }
  1756. int get_pcm_state(struct s_smc *smc, int np)
  1757. {
  1758. int pcs ;
  1759. SK_UNUSED(smc) ;
  1760. switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) {
  1761. case PL_PC0 : pcs = PC_STOP ; break ;
  1762. case PL_PC1 : pcs = PC_START ; break ;
  1763. case PL_PC2 : pcs = PC_TRACE ; break ;
  1764. case PL_PC3 : pcs = PC_SIGNAL ; break ;
  1765. case PL_PC4 : pcs = PC_SIGNAL ; break ;
  1766. case PL_PC5 : pcs = PC_SIGNAL ; break ;
  1767. case PL_PC6 : pcs = PC_JOIN ; break ;
  1768. case PL_PC7 : pcs = PC_JOIN ; break ;
  1769. case PL_PC8 : pcs = PC_ENABLE ; break ;
  1770. case PL_PC9 : pcs = PC_MAINT ; break ;
  1771. default : pcs = PC_DISABLE ; break ;
  1772. }
  1773. return pcs;
  1774. }
  1775. char *get_linestate(struct s_smc *smc, int np)
  1776. {
  1777. char *ls = "" ;
  1778. SK_UNUSED(smc) ;
  1779. switch (inpw(PLC(np,PL_STATUS_A)) & PL_LINE_ST) {
  1780. case PL_L_NLS : ls = "NOISE" ; break ;
  1781. case PL_L_ALS : ls = "ACTIV" ; break ;
  1782. case PL_L_UND : ls = "UNDEF" ; break ;
  1783. case PL_L_ILS4: ls = "ILS 4" ; break ;
  1784. case PL_L_QLS : ls = "QLS" ; break ;
  1785. case PL_L_MLS : ls = "MLS" ; break ;
  1786. case PL_L_HLS : ls = "HLS" ; break ;
  1787. case PL_L_ILS16:ls = "ILS16" ; break ;
  1788. #ifdef lint
  1789. default: ls = "unknown" ; break ;
  1790. #endif
  1791. }
  1792. return ls;
  1793. }
  1794. char *get_pcmstate(struct s_smc *smc, int np)
  1795. {
  1796. char *pcs ;
  1797. SK_UNUSED(smc) ;
  1798. switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) {
  1799. case PL_PC0 : pcs = "OFF" ; break ;
  1800. case PL_PC1 : pcs = "BREAK" ; break ;
  1801. case PL_PC2 : pcs = "TRACE" ; break ;
  1802. case PL_PC3 : pcs = "CONNECT"; break ;
  1803. case PL_PC4 : pcs = "NEXT" ; break ;
  1804. case PL_PC5 : pcs = "SIGNAL" ; break ;
  1805. case PL_PC6 : pcs = "JOIN" ; break ;
  1806. case PL_PC7 : pcs = "VERIFY" ; break ;
  1807. case PL_PC8 : pcs = "ACTIV" ; break ;
  1808. case PL_PC9 : pcs = "MAINT" ; break ;
  1809. default : pcs = "UNKNOWN" ; break ;
  1810. }
  1811. return pcs;
  1812. }
  1813. void list_phy(struct s_smc *smc)
  1814. {
  1815. struct s_plc *plc ;
  1816. int np ;
  1817. for (np = 0 ; np < NUMPHYS ; np++) {
  1818. plc = &smc->y[np].plc ;
  1819. printf("PHY %d:\tERRORS\t\t\tBREAK_REASONS\t\tSTATES:\n",np) ;
  1820. printf("\tsoft_error: %ld \t\tPC_Start : %ld\n",
  1821. plc->soft_err,plc->b_pcs);
  1822. printf("\tparity_err: %ld \t\tTPC exp. : %ld\t\tLine: %s\n",
  1823. plc->parity_err,plc->b_tpc,get_linestate(smc,np)) ;
  1824. printf("\tebuf_error: %ld \t\tTNE exp. : %ld\n",
  1825. plc->ebuf_err,plc->b_tne) ;
  1826. printf("\tphyinvalid: %ld \t\tQLS det. : %ld\t\tPCM : %s\n",
  1827. plc->phyinv,plc->b_qls,get_pcmstate(smc,np)) ;
  1828. printf("\tviosym_ctr: %ld \t\tILS det. : %ld\n",
  1829. plc->vsym_ctr,plc->b_ils) ;
  1830. printf("\tmingap_ctr: %ld \t\tHLS det. : %ld\n",
  1831. plc->mini_ctr,plc->b_hls) ;
  1832. printf("\tnodepr_err: %ld\n",plc->np_err) ;
  1833. printf("\tTPC_exp : %ld\n",plc->tpc_exp) ;
  1834. printf("\tLEM_err : %ld\n",smc->y[np].lem.lem_errors) ;
  1835. }
  1836. }
  1837. #ifdef CONCENTRATOR
  1838. void pcm_lem_dump(struct s_smc *smc)
  1839. {
  1840. int i ;
  1841. struct s_phy *phy ;
  1842. struct fddi_mib_p *mib ;
  1843. char *entostring() ;
  1844. printf("PHY errors BER\n") ;
  1845. printf("----------------------\n") ;
  1846. for (i = 0,phy = smc->y ; i < NUMPHYS ; i++,phy++) {
  1847. if (!plc_is_installed(smc,i))
  1848. continue ;
  1849. mib = phy->mib ;
  1850. printf("%s\t%ld\t10E-%d\n",
  1851. entostring(smc,ENTITY_PHY(i)),
  1852. mib->fddiPORTLem_Ct,
  1853. mib->fddiPORTLer_Estimate) ;
  1854. }
  1855. }
  1856. #endif
  1857. #endif