Skip to content

Commit 5e9c885

Browse files
DellEMC: get_change_event Platform API implementation for S6000, S6100 and Z9100
1 parent cbe948e commit 5e9c885

3 files changed

Lines changed: 305 additions & 6 deletions

File tree

platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/chassis.py

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -237,13 +237,32 @@ def _get_transceiver_status(self):
237237

238238
return int(content, 16)
239239

240-
def get_transceiver_change_event(self, timeout=0):
240+
def get_change_event(self, timeout=0):
241241
"""
242-
Returns a dictionary containing sfp changes which have
242+
Returns a nested dictionary containing all devices which have
243243
experienced a change at chassis level
244+
245+
Args:
246+
timeout: Timeout in milliseconds (optional). If timeout == 0,
247+
this method will block until a change is detected.
248+
249+
Returns:
250+
(bool, dict):
251+
- True if call successful, False if not;
252+
- A nested dictionary where key is a device type,
253+
value is a dictionary with key:value pairs in the
254+
format of {'device_id':'device_event'},
255+
where device_id is the device ID for this device and
256+
device_event,
257+
status='1' represents device inserted,
258+
status='0' represents device removed.
259+
Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}}
260+
indicates that fan 0 has been removed, fan 2
261+
has been inserted and sfp 11 has been removed.
244262
"""
245263
start_time = time.time()
246264
port_dict = {}
265+
ret_dict = {"sfp": port_dict}
247266
port = self.PORT_START
248267
forever = False
249268

@@ -256,7 +275,7 @@ def get_transceiver_change_event(self, timeout=0):
256275
end_time = start_time + timeout
257276

258277
if (start_time > end_time):
259-
return False, {} # Time wrap or possibly incorrect timeout
278+
return False, ret_dict # Time wrap or possibly incorrect timeout
260279

261280
while (timeout >= 0):
262281
# Check for OIR events and return updated port_dict
@@ -276,7 +295,7 @@ def get_transceiver_change_event(self, timeout=0):
276295

277296
# Update reg value
278297
self.modprs_register = reg_value
279-
return True, port_dict
298+
return True, ret_dict
280299

281300
if forever:
282301
time.sleep(1)
@@ -287,7 +306,7 @@ def get_transceiver_change_event(self, timeout=0):
287306
else:
288307
if timeout > 0:
289308
time.sleep(timeout)
290-
return True, {}
291-
return False, {}
309+
return True, ret_dict
310+
return False, ret_dict
292311

293312

platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/chassis.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class Chassis(ChassisBase):
3939
HWMON_DIR = "/sys/devices/platform/SMF.512/hwmon/"
4040
HWMON_NODE = os.listdir(HWMON_DIR)[0]
4141
MAILBOX_DIR = HWMON_DIR + HWMON_NODE
42+
POLL_INTERVAL = 1 # Poll interval in seconds
4243

4344
reset_reason_dict = {}
4445
reset_reason_dict[11] = ChassisBase.REBOOT_CAUSE_POWER_LOSS
@@ -81,6 +82,7 @@ def __init__(self):
8182
self._component_list.append(component)
8283

8384
self._watchdog = Watchdog()
85+
self._transceiver_presence = self._get_transceiver_presence()
8486

8587
def _get_reboot_reason_smf_register(self):
8688
# In S6100, mb_poweron_reason register will
@@ -111,6 +113,24 @@ def _get_pmc_register(self, reg_name):
111113
rv = rv.lstrip(" ")
112114
return rv
113115

116+
def _get_register(self, reg_file):
117+
# On successful read, returns the value read from given
118+
# reg_name and on failure returns 'ERR'
119+
rv = 'ERR'
120+
121+
if (not os.path.isfile(reg_file)):
122+
return rv
123+
124+
try:
125+
with open(reg_file, 'r') as fd:
126+
rv = fd.read()
127+
except Exception as error:
128+
rv = 'ERR'
129+
130+
rv = rv.rstrip('\r\n')
131+
rv = rv.lstrip(" ")
132+
return rv
133+
114134
def get_name(self):
115135
"""
116136
Retrieves the name of the chassis
@@ -215,3 +235,103 @@ def get_reboot_cause(self):
215235
return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None)
216236

217237
return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Invalid Reason")
238+
239+
def _get_transceiver_presence(self):
240+
241+
cpld2_modprs = self._get_register(
242+
"/sys/class/i2c-adapter/i2c-14/14-003e/qsfp_modprs")
243+
cpld3_modprs = self._get_register(
244+
"/sys/class/i2c-adapter/i2c-15/15-003e/qsfp_modprs")
245+
cpld4_modprs = self._get_register(
246+
"/sys/class/i2c-adapter/i2c-16/16-003e/qsfp_modprs")
247+
cpld5_modprs = self._get_register(
248+
"/sys/class/i2c-adapter/i2c-17/17-003e/qsfp_modprs")
249+
250+
# If IOM is not present, register read will fail.
251+
# Handle the scenario gracefully
252+
if (cpld2_modprs == 'read error') or (cpld2_modprs == 'ERR'):
253+
cpld2_modprs = '0x0'
254+
if (cpld3_modprs == 'read error') or (cpld3_modprs == 'ERR'):
255+
cpld3_modprs = '0x0'
256+
if (cpld4_modprs == 'read error') or (cpld4_modprs == 'ERR'):
257+
cpld4_modprs = '0x0'
258+
if (cpld5_modprs == 'read error') or (cpld5_modprs == 'ERR'):
259+
cpld5_modprs = '0x0'
260+
261+
# Make it contiguous
262+
transceiver_presence = (int(cpld2_modprs, 16) & 0xffff) |\
263+
((int(cpld4_modprs, 16) & 0xffff) << 16) |\
264+
((int(cpld3_modprs, 16) & 0xffff) << 32) |\
265+
((int(cpld5_modprs, 16) & 0xffff) << 48)
266+
267+
return transceiver_presence
268+
269+
def get_change_event(self, timeout=0):
270+
"""
271+
Returns a nested dictionary containing all devices which have
272+
experienced a change at chassis level
273+
274+
Args:
275+
timeout: Timeout in milliseconds (optional). If timeout == 0,
276+
this method will block until a change is detected.
277+
278+
Returns:
279+
(bool, dict):
280+
- True if call successful, False if not;
281+
- A nested dictionary where key is a device type,
282+
value is a dictionary with key:value pairs in the
283+
format of {'device_id':'device_event'},
284+
where device_id is the device ID for this device and
285+
device_event,
286+
status='1' represents device inserted,
287+
status='0' represents device removed.
288+
Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}}
289+
indicates that fan 0 has been removed, fan 2
290+
has been inserted and sfp 11 has been removed.
291+
"""
292+
port_dict = {}
293+
ret_dict = {'sfp': port_dict}
294+
forever = False
295+
296+
if timeout == 0:
297+
forever = True
298+
elif timeout > 0:
299+
timeout = timeout / float(1000) # Convert to secs
300+
else:
301+
return False, ret_dict # Incorrect timeout
302+
303+
while True:
304+
if forever:
305+
timer = self.POLL_INTERVAL
306+
else:
307+
timer = min(timeout, self.POLL_INTERVAL)
308+
start_time = time.time()
309+
310+
time.sleep(timer)
311+
cur_presence = self._get_transceiver_presence()
312+
313+
# Update dict only if a change has been detected
314+
if cur_presence != self._transceiver_presence:
315+
changed_ports = self._transceiver_presence ^ cur_presence
316+
for port in range(self.get_num_sfps()):
317+
# Mask off the bit corresponding to particular port
318+
mask = 1 << port
319+
if changed_ports & mask:
320+
# qsfp_modprs 1 => optics is removed
321+
if cur_presence & mask:
322+
port_dict[port] = '0'
323+
# qsfp_modprs 0 => optics is inserted
324+
else:
325+
port_dict[port] = '1'
326+
327+
# Update current presence
328+
self._transceiver_presence = cur_presence
329+
break
330+
331+
if not forever:
332+
elapsed_time = time.time() - start_time
333+
timeout = round(timeout - elapsed_time, 3)
334+
if timeout <= 0:
335+
break
336+
337+
return True, ret_dict

0 commit comments

Comments
 (0)