pcmplc.c 48 KB

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