platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/chassis.py (214 lines of code) (raw):
#!/usr/bin/env python
#############################################################################
# DELLEMC Z9332F
#
# Module contains an implementation of SONiC Platform Base API and
# provides the platform information
#
#############################################################################
try:
import time
import sys
from sonic_platform_base.chassis_base import ChassisBase
from sonic_platform.sfp import Sfp
from sonic_platform.eeprom import Eeprom
from sonic_platform.component import Component
from sonic_platform.psu import Psu
from sonic_platform.thermal import Thermal
from sonic_platform.fan_drawer import FanDrawer
from sonic_platform.watchdog import Watchdog
import sonic_platform.hwaccess as hwaccess
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
MAX_Z9332F_FANTRAY = 7
MAX_Z9332F_FAN = 2
MAX_Z9332F_PSU = 2
MAX_Z9332F_THERMAL = 14
MAX_Z9332F_COMPONENT = 9 # BIOS,FPGA,BMC,BB CPLD,2 Switch CPLDs,SSD,PCIe and ONIE
media_part_num_list = set([ \
"8T47V","XTY28","MHVPK","GF76J","J6FGD","F1KMV","9DN5J","H4DHD","6MCNV","0WRX0","X7F70","5R2PT","WTRD1","WTRD1","WTRD1","WTRD1","5250G","WTRD1","C5RNH","C5RNH","FTLX8571D3BCL-FC",
"C5RNH","5250G","N8TDR","7D64H","7D64H","RN84N","RN84N","HMTNW","6K3Y6","6K3Y6","TY5FM","50M0R","PGYJT","WP2PP","85Y13","1HCGH","FP9R1","FYD0M","C6Y7M","C6Y7M","V250M","V250M",
"5CWK6","5CWK6","53HVN","53HVN","358VV","358VV","MV799","MV799","YJF03","P9GND","T1KCN","1DXKP","MT7R2","K0T7R","W5G04","7TCDN","7TCDN","7TCDN","7TCDN","7TCDN","V3XJK","0MV31",
"5FVP7","N6KM9","C41MF","77KC3","XW7J0","V4NJV","2XJHY","H93DH","H93DH","F8CG0","F8CG0","F8CG0","119N6","WFMF5","794RX","288F6","1M31V","1M31V","5NP8R","5NP8R","4TC09","4TC09",
"FC6KV","FC6KV","J90VN","J90VN","05RH0","05RH0","YDN52","0C2YV","YDN52","0C2YV","9JT65","D7M6H","6GW14","FYVFW","0VF5H","P4YPY","P4YPY","TCPM2","TCPM2","JNPF8","JNPF8","27GG5",
"27GG5","P8T4W","P8T4W","JR54Y","M6N0J","XJYD0","K44H9","035KG","P7C7N","76V43","3CC35","FN4FC","26FN3","YFNDD","YFNDD","7R9N9","035KG","P7C7N","76V43","3CC35","PLRXPLSCS43811",
"FN4FC","26FN3","YFNDD","YFNDD","7R9N9","G86YJ","V407F","V407F","9KH6T","G86YJ","V407F","9KH6T","2JVDD","D0R73","VXFJY","9X8JP","2JVDD","D0R73","VXFJY","9X8JP","2JVDD","D0R73","VXFJY",
"9X8JP","GMFC5","GMFC5","GMFC5","D7P80","3MFXG","3MFXG","0GWXJ","THPF3","THPF3","THPF3","THPF3","THPF3","PJ62G","3XCX1","JJYKG","RRRTK","16K56","86JM2","K5R6C","7MG2C","WTPPN","9HTT2",
"NKM4F","VXGGG","JC9W6","6MR8M","RP3GV","M5PPJ","XKY55","TKCXT","05J8P","5WGKD","XFDRT","NW8DM","YPKH3","5WGKD","XFDRT","NW8DM","YPKH3","71XXK","MVCX6","0XYP6","HPPVW","3GHRT","71XXK",
"MVCX6","0XYP6","HPPVW","3GHRT","2X5T6","135V2","KD5MV","2X5T6","KD5MV","HHFK0","3YWG7","5CMT2","RCVP5","X5DH4","HHFK0","3YWG7","5CMT2","RCVP5","X5DH4","3YWG7","5CMT2","RCVP5","X5DH4",
"4WJ41","4WJ41","14NV5","14NV5","14NV5","4WGYD","YKMH7","X7CCC","X7CCC","0X9CT","0CY8V","P7D7R","W4GPP","W4GPP","W4GPP","HHHCHC","07RN7","07RN7","0YR96","0YR96","JCYM9","FTLX8571D3BCL",
"DDW0X","VPFDJ","229KM","9FC7D","DDW0X","VPFDJ","6FMR5","J7K20","N3K9W","6FMR5","8R4VM","7VN5T","D9YM8","8R4VM","VYXPW","87TPX","WY6FK","VYXPW","87TPX","WY6FK","WG8C4","N8K82","2DV6Y",
"77C3C","RC0HM","77C3C","RC0HM","JHXTN","3P3PG","92YVM","4VX5M","4VX5M","6RRGD","W4JWV","22V6R","XR11M","9GMDY","JMCWK","TP2F0","6MGDY","78RHK", "C0TP5","0WDNV","FCLF8522P2BTL"\
])
class Chassis(ChassisBase):
"""
DELLEMC Platform-specific Chassis class
"""
REBOOT_CAUSE_PATH = "/host/reboot-cause/platform/reboot_reason"
oir_fd = -1
epoll = -1
io_res = "/dev/port"
sysled_offset = 0xA162
SYSLED_COLOR_TO_REG = {
"green": 0xd0,
"yellow": 0xe0,
"flashing green": 0xd2,
"flashing yellow": 0xe2
}
REG_TO_SYSLED_COLOR = {
0xd0 : "green",
0xe0 : "yellow",
0xd2 : "flashing green",
0xd1 : "flashing green",
0xe2 : "flashing yellow",
0xe1 : "flashing yellow"
}
_global_port_pres_dict = {}
_port_to_i2c_mapping = {
1: 10,
2: 11,
3: 12,
4: 13,
5: 14,
6: 15,
7: 16,
8: 17,
9: 18,
10: 19,
11: 20,
12: 21,
13: 22,
14: 23,
15: 24,
16: 25,
17: 26,
18: 27,
19: 28,
20: 29,
21: 30,
22: 31,
23: 32,
24: 33,
25: 34,
26: 35,
27: 36,
28: 37,
29: 38,
30: 39,
31: 40,
32: 41,
33: 1,
34: 2
}
reboot_reason_dict = { 0x11: (ChassisBase.REBOOT_CAUSE_POWER_LOSS, "Power on reset"),
0x22: (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Soft-set CPU warm reset"),
0x33: (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Soft-set CPU cold reset"),
0x66: (ChassisBase.REBOOT_CAUSE_WATCHDOG, "GPIO watchdog reset"),
0x77: (ChassisBase.REBOOT_CAUSE_POWER_LOSS, "Power cycle reset"),
0x88: (ChassisBase.REBOOT_CAUSE_WATCHDOG, "CPLD watchdog reset")
}
def __init__(self):
ChassisBase.__init__(self)
# sfp.py will read eeprom contents and retrive the eeprom data.
# We pass the eeprom path from chassis.py
self.PORT_START = 1
self.PORT_END = 34
self.PORTS_IN_BLOCK = (self.PORT_END + 1)
_sfp_port = range(33, self.PORTS_IN_BLOCK)
eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom"
for index in range(self.PORT_START, self.PORTS_IN_BLOCK):
eeprom_path = eeprom_base.format(self._port_to_i2c_mapping[index])
port_type = 'SFP' if index in _sfp_port else 'QSFP_DD'
sfp_node = Sfp(index, port_type, eeprom_path)
self._sfp_list.append(sfp_node)
self._eeprom = Eeprom()
self._watchdog = Watchdog()
for i in range(MAX_Z9332F_FANTRAY):
fandrawer = FanDrawer(i)
self._fan_drawer_list.append(fandrawer)
self._fan_list.extend(fandrawer._fan_list)
self._num_sfps = self.PORT_END
self._num_fans = MAX_Z9332F_FANTRAY * MAX_Z9332F_FAN
self._psu_list = [Psu(i) for i in range(MAX_Z9332F_PSU)]
self._thermal_list = [Thermal(i) for i in range(MAX_Z9332F_THERMAL)]
self._component_list = [Component(i) for i in range(MAX_Z9332F_COMPONENT)]
for port_num in range(self.PORT_START, self.PORTS_IN_BLOCK):
# sfp get uses zero-indexing, but port numbers start from 1
self._global_port_pres_dict[port_num] = '0'
self._watchdog = Watchdog()
def __del__(self):
if self.oir_fd != -1:
self.epoll.unregister(self.oir_fd.fileno())
self.epoll.close()
self.oir_fd.close()
# check for this event change for sfp / do we need to handle timeout/sleep
def get_change_event(self, timeout=0):
"""
Returns a nested dictionary containing all devices which have
experienced a change at chassis level
"""
start_ms = time.time() * 1000
port_dict = {}
change_dict = {}
change_dict['sfp'] = port_dict
while True:
time.sleep(0.5)
for port_num in range(self.PORT_START, (self.PORT_END + 1)):
presence = self.get_sfp(port_num).get_presence()
if(presence and self._global_port_pres_dict[port_num] == '0'):
self._global_port_pres_dict[port_num] = '1'
port_dict[port_num] = '1'
self.get_sfp(port_num)._initialize_media(delay=True)
elif(not presence and
self._global_port_pres_dict[port_num] == '1'):
self._global_port_pres_dict[port_num] = '0'
port_dict[port_num] = '0'
if(len(port_dict) > 0):
return True, change_dict
if timeout:
now_ms = time.time() * 1000
if (now_ms - start_ms >= timeout):
return True, change_dict
def get_sfp(self, index):
"""
Retrieves sfp represented by (0-based) index <index>
Args:
index: An integer, the index (0-based) of the sfp to retrieve.
The index should be the sequence of a physical port in a chassis,
starting from 0.
For example, 0 for Ethernet0, 1 for Ethernet4 and so on.
Returns:
An object dervied from SfpBase representing the specified sfp
"""
sfp = None
try:
# The index will start from 0
sfp = self._sfp_list[index-1]
except IndexError:
sys.stderr.write("SFP index {} out of range (1-{})\n".format(
index, len(self._sfp_list)))
return sfp
def get_name(self):
"""
Retrieves the name of the chassis
Returns:
string: The name of the chassis
"""
return self._eeprom.modelstr()
def get_presence(self):
"""
Retrieves the presence of the chassis
Returns:
bool: True if chassis is present, False if not
"""
return True
def get_model(self):
"""
Retrieves the model number (or part number) of the chassis
Returns:
string: Model/part number of chassis
"""
return self._eeprom.part_number_str()
def get_serial(self):
"""
Retrieves the serial number of the chassis (Service tag)
Returns:
string: Serial number of chassis
"""
return self._eeprom.serial_str()
def get_status(self):
"""
Retrieves the operational status of the chassis
Returns:
bool: A boolean value, True if chassis is operating properly
False if not
"""
return True
def get_base_mac(self):
"""
Retrieves the base MAC address for the chassis
Returns:
A string containing the MAC address in the format
'XX:XX:XX:XX:XX:XX'
"""
return self._eeprom.base_mac_addr()
def get_serial_number(self):
"""
Retrieves the hardware serial number for the chassis
Returns:
A string containing the hardware serial number for this chassis.
"""
return self._eeprom.serial_number_str()
def get_revision(self):
"""
Retrieves the hardware revision of the device
Returns:
string: Revision value of device
"""
return self._eeprom.revision_str()
def get_system_eeprom_info(self):
"""
Retrieves the full content of system EEPROM information for the chassis
Returns:
A dictionary where keys are the type code defined in
OCP ONIE TlvInfo EEPROM format and values are their corresponding
values.
"""
return self._eeprom.system_eeprom_info()
def get_eeprom(self):
"""
Retrieves the Sys Eeprom instance for the chassis.
Returns :
The instance of the Sys Eeprom
"""
return self._eeprom
def get_num_fans(self):
"""
Retrives the number of Fans on the chassis.
Returns :
An integer represents the number of Fans on the chassis.
"""
return self._num_fans
def get_num_sfps(self):
"""
Retrives the numnber of Media on the chassis.
Returns:
An integer represences the number of SFPs on the chassis.
"""
return self._num_sfps
def get_reboot_cause(self):
"""
Retrieves the cause of the previous reboot
Returns:
A tuple (string, string) where the first element is a string
containing the cause of the previous reboot. This string must be
one of the predefined strings in this class. If the first string
is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
to pass a description of the reboot cause.
"""
try:
with open(self.REBOOT_CAUSE_PATH) as fd:
reboot_cause = int(fd.read(), 16)
except EnvironmentError:
return (self.REBOOT_CAUSE_NON_HARDWARE, None)
if reboot_cause in self.reboot_reason_dict.keys():
return self.reboot_reason_dict.get(reboot_cause)
else:
return (self.REBOOT_CAUSE_NON_HARDWARE, None)
def get_qualified_media_list(self):
return media_part_num_list
def initizalize_system_led(self):
self.sys_ledcolor = "green"
def get_status_led(self):
"""
Gets the current system LED color
Returns:
A string that represents the supported color
"""
val = hwaccess.io_reg_read(self.io_res, self.sysled_offset)
if val != -1:
return self.REG_TO_SYSLED_COLOR.get(val)
return self.sys_ledcolor
def set_status_led(self, color):
"""
Set system LED status based on the color type passed in the argument.
Argument: Color to be set
Returns:
bool: True is specified color is set, Otherwise return False
"""
if color not in list(self.SYSLED_COLOR_TO_REG.keys()):
return False
if(not hwaccess.io_reg_write(self.io_res, self.sysled_offset, self.SYSLED_COLOR_TO_REG[color])):
return False
self.sys_ledcolor = color
return True
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device.
Returns:
integer: The 1-based relative physical position in parent
device or -1 if cannot determine the position
"""
return -1
def is_replaceable(self):
"""
Indicate whether Chassis is replaceable.
Returns:
bool: True if it is replaceable.
"""
return False