pcmplc.c 48 KB

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