Skip to content

Commit ea9a615

Browse files
author
Wirut Getbamrung
authored
Merge pull request sonic-net#155 from SONIC-DEV/upstream_silverstone-dp_platform_api
[device/celestica]: Implement Silverstone-DP platform api version 1.0
2 parents 5ae98cd + 25ed148 commit ea9a615

File tree

15 files changed

+3091
-3
lines changed

15 files changed

+3091
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
__all__ = ["platform", "chassis"]
2+
from sonic_platform import *
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
#!/usr/bin/env python
2+
3+
#############################################################################
4+
# Celestica
5+
#
6+
# Module contains an implementation of SONiC Platform Base API and
7+
# provides the Chassis information which are available in the platform
8+
#
9+
#############################################################################
10+
11+
try:
12+
import sys
13+
import re
14+
import os
15+
import subprocess
16+
import time
17+
import json
18+
from sonic_platform_base.chassis_base import ChassisBase
19+
from helper import APIHelper
20+
except ImportError as e:
21+
raise ImportError(str(e) + "- required module not found")
22+
23+
NUM_FAN_TRAY = 7
24+
NUM_FAN = 2
25+
NUM_PSU = 2
26+
NUM_THERMAL = 14
27+
NUM_SFP = 30
28+
NUM_COMPONENT = 5
29+
30+
QSFP_PORT_START = 1
31+
QSFP_PORT_END = 24
32+
OSFP_PORT_START = 25
33+
OSFP_PORT_END = 30
34+
35+
IPMI_OEM_NETFN = "0x3A"
36+
IPMI_GET_REBOOT_CAUSE = "0x03 0x00 0x01 0x06"
37+
TLV_EEPROM_I2C_BUS = 0
38+
TLV_EEPROM_I2C_ADDR = 56
39+
PORT_INFO_PATH = "/sys/devices/platform/cls-xcvr"
40+
PATH_INT_SYSFS = "{0}/{1}/interrupt"
41+
PATH_INTMASK_SYSFS = "{0}/{1}/interrupt_mask"
42+
PATH_PRS_SYSFS = "{0}/{1}/qsfp_modprsL"
43+
44+
45+
class Chassis(ChassisBase):
46+
"""Platform-specific Chassis class"""
47+
48+
def __init__(self):
49+
ChassisBase.__init__(self)
50+
self._api_helper = APIHelper()
51+
self.sfp_module_initialized = False
52+
self.__initialize_components()
53+
self.__initialize_eeprom()
54+
55+
if not self._api_helper.is_host():
56+
self.__initialize_psu()
57+
self.__initialize_fan()
58+
self.__initialize_thermals()
59+
self.__initialize_interrupts()
60+
61+
def __initialize_sfp(self):
62+
from sonic_platform.sfp import Sfp
63+
for index in range(0, NUM_SFP):
64+
sfp = Sfp(index)
65+
self._sfp_list.append(sfp)
66+
self.sfp_module_initialized = True
67+
68+
def __initialize_psu(self):
69+
from sonic_platform.psu import Psu
70+
for index in range(0, NUM_PSU):
71+
psu = Psu(index)
72+
self._psu_list.append(psu)
73+
74+
def __initialize_fan(self):
75+
from sonic_platform.fan import Fan
76+
for fant_index in range(0, NUM_FAN_TRAY):
77+
for fan_index in range(0, NUM_FAN):
78+
fan = Fan(fant_index, fan_index)
79+
self._fan_list.append(fan)
80+
81+
def __initialize_thermals(self):
82+
from sonic_platform.thermal import Thermal
83+
for index in range(0, NUM_THERMAL):
84+
thermal = Thermal(index)
85+
self._thermal_list.append(thermal)
86+
87+
def __initialize_eeprom(self):
88+
from sonic_platform.eeprom import Eeprom
89+
self._eeprom = Eeprom(TLV_EEPROM_I2C_BUS, TLV_EEPROM_I2C_ADDR)
90+
91+
def __initialize_components(self):
92+
from sonic_platform.component import Component
93+
for index in range(0, NUM_COMPONENT):
94+
component = Component(index)
95+
self._component_list.append(component)
96+
97+
def __initialize_interrupts(self):
98+
# Initial Interrup MASK for QSFP, QSFPDD
99+
sfp_info_obj = {}
100+
for index in range(NUM_SFP):
101+
port_num = index+1
102+
if port_num in range(QSFP_PORT_START, QSFP_PORT_END+1):
103+
port_name = "QSFP{}".format(
104+
str(port_num - QSFP_PORT_START + 1))
105+
elif port_num in range(OSFP_PORT_START, OSFP_PORT_END+1):
106+
port_name = "QSFPDD{}".format(
107+
str(port_num - OSFP_PORT_START + 1))
108+
109+
sfp_info_obj[index] = {}
110+
sfp_info_obj[index]['intmask_sysfs'] = PATH_INTMASK_SYSFS.format(
111+
PORT_INFO_PATH, port_name)
112+
sfp_info_obj[index]['int_sysfs'] = PATH_INT_SYSFS.format(
113+
PORT_INFO_PATH, port_name)
114+
sfp_info_obj[index]['prs_sysfs'] = PATH_PRS_SYSFS.format(
115+
PORT_INFO_PATH, port_name)
116+
117+
self._api_helper.write_hex_value(
118+
sfp_info_obj[index]["intmask_sysfs"], 255)
119+
120+
self.sfp_info_obj = sfp_info_obj
121+
122+
def get_base_mac(self):
123+
"""
124+
Retrieves the base MAC address for the chassis
125+
Returns:
126+
A string containing the MAC address in the format
127+
'XX:XX:XX:XX:XX:XX'
128+
"""
129+
return self._eeprom.get_mac()
130+
131+
def get_serial_number(self):
132+
"""
133+
Retrieves the hardware serial number for the chassis
134+
Returns:
135+
A string containing the hardware serial number for this chassis.
136+
"""
137+
return self._eeprom.get_serial()
138+
139+
def get_system_eeprom_info(self):
140+
"""
141+
Retrieves the full content of system EEPROM information for the chassis
142+
Returns:
143+
A dictionary where keys are the type code defined in
144+
OCP ONIE TlvInfo EEPROM format and values are their corresponding
145+
values.
146+
"""
147+
return self._eeprom.get_eeprom()
148+
149+
def get_reboot_cause(self):
150+
"""
151+
Retrieves the cause of the previous reboot
152+
153+
Returns:
154+
A tuple (string, string) where the first element is a string
155+
containing the cause of the previous reboot. This string must be
156+
one of the predefined strings in this class. If the first string
157+
is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
158+
to pass a description of the reboot cause.
159+
"""
160+
161+
status, raw_cause = self._api_helper.ipmi_raw(
162+
IPMI_OEM_NETFN, IPMI_GET_REBOOT_CAUSE)
163+
hx_cause = raw_cause.split()[0] if status and len(
164+
raw_cause.split()) > 0 else 00
165+
reboot_cause = {
166+
"00": self.REBOOT_CAUSE_HARDWARE_OTHER,
167+
"11": self.REBOOT_CAUSE_POWER_LOSS,
168+
"22": self.REBOOT_CAUSE_NON_HARDWARE,
169+
"33": self.REBOOT_CAUSE_HARDWARE_OTHER,
170+
"44": self.REBOOT_CAUSE_NON_HARDWARE,
171+
"55": self.REBOOT_CAUSE_NON_HARDWARE,
172+
"66": self.REBOOT_CAUSE_WATCHDOG,
173+
"77": self.REBOOT_CAUSE_NON_HARDWARE
174+
}.get(hx_cause, self.REBOOT_CAUSE_HARDWARE_OTHER)
175+
176+
description = {
177+
"00": "Unknown reason",
178+
"11": "The last reset is Power on reset",
179+
"22": "The last reset is soft-set CPU warm reset",
180+
"33": "The last reset is soft-set CPU cold reset",
181+
"44": "The last reset is CPU warm reset",
182+
"55": "The last reset is CPU cold reset",
183+
"66": "The last reset is watchdog reset",
184+
"77": "The last reset is power cycle reset"
185+
}.get(hx_cause, "Unknown reason")
186+
187+
return (reboot_cause, description)
188+
189+
##############################################################
190+
######################## SFP methods #########################
191+
##############################################################
192+
193+
def get_num_sfps(self):
194+
"""
195+
Retrieves the number of sfps available on this chassis
196+
Returns:
197+
An integer, the number of sfps available on this chassis
198+
"""
199+
if not self.sfp_module_initialized:
200+
self.__initialize_sfp()
201+
202+
return len(self._sfp_list)
203+
204+
def get_all_sfps(self):
205+
"""
206+
Retrieves all sfps available on this chassis
207+
Returns:
208+
A list of objects derived from SfpBase representing all sfps
209+
available on this chassis
210+
"""
211+
if not self.sfp_module_initialized:
212+
self.__initialize_sfp()
213+
214+
return self._sfp_list
215+
216+
def get_sfp(self, index):
217+
"""
218+
Retrieves sfp represented by (1-based) index <index>
219+
Args:
220+
index: An integer, the index (1-based) of the sfp to retrieve.
221+
The index should be the sequence of a physical port in a chassis,
222+
starting from 1.
223+
For example, 1 for Ethernet0, 2 for Ethernet4 and so on.
224+
Returns:
225+
An object dervied from SfpBase representing the specified sfp
226+
"""
227+
sfp = None
228+
if not self.sfp_module_initialized:
229+
self.__initialize_sfp()
230+
231+
try:
232+
# The index will start from 1
233+
sfp = self._sfp_list[index-1]
234+
except IndexError:
235+
sys.stderr.write("SFP index {} out of range (1-{})\n".format(
236+
index, len(self._sfp_list)))
237+
return sfp
238+
239+
##############################################################
240+
####################### Other methods ########################
241+
##############################################################
242+
243+
def get_watchdog(self):
244+
"""
245+
Retreives hardware watchdog device on this chassis
246+
Returns:
247+
An object derived from WatchdogBase representing the hardware
248+
watchdog device
249+
"""
250+
if self._watchdog is None:
251+
from sonic_platform.watchdog import Watchdog
252+
self._watchdog = Watchdog()
253+
254+
return self._watchdog
255+
256+
##############################################################
257+
###################### Device methods ########################
258+
##############################################################
259+
260+
def get_name(self):
261+
"""
262+
Retrieves the name of the device
263+
Returns:
264+
string: The name of the device
265+
"""
266+
return self._api_helper.hwsku
267+
268+
def get_presence(self):
269+
"""
270+
Retrieves the presence of the PSU
271+
Returns:
272+
bool: True if PSU is present, False if not
273+
"""
274+
return True
275+
276+
def get_model(self):
277+
"""
278+
Retrieves the model number (or part number) of the device
279+
Returns:
280+
string: Model/part number of device
281+
"""
282+
return self._eeprom.get_pn()
283+
284+
def get_serial(self):
285+
"""
286+
Retrieves the serial number of the device
287+
Returns:
288+
string: Serial number of device
289+
"""
290+
return self.get_serial_number()
291+
292+
def get_status(self):
293+
"""
294+
Retrieves the operational status of the device
295+
Returns:
296+
A boolean value, True if device is operating properly, False if not
297+
"""
298+
return True
299+
300+
##############################################################
301+
###################### Event methods ########################
302+
##############################################################
303+
def __clear_interrupt(self, port_idx):
304+
int_path = self.sfp_info_obj[port_idx]["int_sysfs"]
305+
self._api_helper.write_hex_value(int_path, 255)
306+
time.sleep(0.5)
307+
self._api_helper.write_hex_value(int_path, 0)
308+
return self._api_helper.read_txt_file(int_path)
309+
310+
def __check_devices_status(self, port_idx):
311+
prs_path = self.sfp_info_obj[port_idx]["prs_sysfs"]
312+
return self._api_helper.read_txt_file(prs_path)
313+
314+
def __compare_event_object(self, interrup_devices):
315+
devices = {}
316+
event_obj = {}
317+
for port_idx in interrup_devices:
318+
devices[port_idx] = 1 - \
319+
int(self.__check_devices_status(port_idx))
320+
self.__clear_interrupt(port_idx)
321+
322+
if len(devices):
323+
event_obj['sfp'] = devices
324+
325+
return json.dumps(event_obj)
326+
327+
def __check_all_interrupt_event(self):
328+
interrupt_device = {}
329+
for i in range(NUM_SFP):
330+
int_sysfs = self.sfp_info_obj[i]["int_sysfs"]
331+
if self._api_helper.read_txt_file(int_sysfs) != '0x00':
332+
interrupt_device[i] = 1
333+
return interrupt_device
334+
335+
def get_change_event(self, timeout=0):
336+
if timeout == 0:
337+
flag_change = True
338+
while flag_change:
339+
interrup_device = self.__check_all_interrupt_event()
340+
if len(interrup_device):
341+
flag_change = False
342+
else:
343+
time.sleep(0.5)
344+
return (True, self.__compare_event_object(interrup_device))
345+
else:
346+
device_list_change = {}
347+
while timeout:
348+
interrup_device = self.__check_all_interrupt_event()
349+
time.sleep(1)
350+
timeout -= 1
351+
device_list_change = self.__compare_event_object(interrup_device)
352+
return (True, device_list_change)

0 commit comments

Comments
 (0)