pcmplc.c 48 KB

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