Added Support for Dell EMC S5212f in SONiC (#8678)

Why I did it
Added Support for Dell EMC S5212f platform

How I did it
Implemented the support for Dell EMC S5212f platform

Platform: x86_64-dellemc_s5212f_c3538-r0
HwSKU: DellEMC-S5212f-P-25G
ASIC: broadcom
ASIC Count: 1

How to verify it
Verified the show command outputs
This commit is contained in:
thaj-deen 2021-10-26 12:52:03 -07:00 committed by GitHub
parent 453346f8df
commit f01076ea2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 5705 additions and 1 deletions

View File

@ -0,0 +1,2 @@
{%- set default_topo = 't1' %}
{%- include 'buffers_config.j2' %}

View File

@ -0,0 +1,37 @@
{%- set default_cable = '5m' %}
{%- macro generate_buffer_pool_and_profiles() %}
"BUFFER_POOL": {
"ingress_lossless_pool": {
"size": "26531072",
"type": "ingress",
"mode": "dynamic",
"xoff": "6291456"
},
"egress_lossless_pool": {
"size": "32822528",
"type": "egress",
"mode": "static"
}
},
"BUFFER_PROFILE": {
"ingress_lossy_profile": {
"pool":"[BUFFER_POOL|ingress_lossless_pool]",
"size":"0",
"dynamic_th":"3"
},
"egress_lossless_profile": {
"pool":"[BUFFER_POOL|egress_lossless_pool]",
"size":"0",
"mode": "static",
"static_th":"32822528"
},
"egress_lossy_profile": {
"pool":"[BUFFER_POOL|egress_lossless_pool]",
"size":"0",
"mode": "dynamic",
"dynamic_th":"3"
}
},
{%- endmacro %}

View File

@ -0,0 +1,37 @@
{%- set default_cable = '40m' %}
{%- macro generate_buffer_pool_and_profiles() %}
"BUFFER_POOL": {
"ingress_lossless_pool": {
"size": "26531072",
"type": "ingress",
"mode": "dynamic",
"xoff": "6291456"
},
"egress_lossless_pool": {
"size": "32822528",
"type": "egress",
"mode": "static"
}
},
"BUFFER_PROFILE": {
"ingress_lossy_profile": {
"pool":"[BUFFER_POOL|ingress_lossless_pool]",
"size":"0",
"dynamic_th":"3"
},
"egress_lossless_profile": {
"pool":"[BUFFER_POOL|egress_lossless_pool]",
"size":"0",
"mode": "static",
"static_th":"32822528"
},
"egress_lossy_profile": {
"pool":"[BUFFER_POOL|egress_lossless_pool]",
"size":"0",
"mode": "dynamic",
"dynamic_th":"3"
}
},
{%- endmacro %}

View File

@ -0,0 +1,17 @@
# PG lossless profiles.
# speed cable size xon xoff threshold xon_offset
10000 5m 1248 2288 35776 -3 2288
25000 5m 1248 2288 53248 -3 2288
40000 5m 1248 2288 66560 -3 2288
50000 5m 1248 2288 90272 -3 2288
100000 5m 1248 2288 165568 -3 2288
10000 40m 1248 2288 37024 -3 2288
25000 40m 1248 2288 53248 -3 2288
40000 40m 1248 2288 71552 -3 2288
50000 40m 1248 2288 96096 -3 2288
100000 40m 1248 2288 177632 -3 2288
10000 300m 1248 2288 46176 -3 2288
25000 300m 1248 2288 79040 -3 2288
40000 300m 1248 2288 108160 -3 2288
50000 300m 1248 2288 141856 -3 2288
100000 300m 1248 2288 268736 -3 2288

View File

@ -0,0 +1,16 @@
# name lanes alias index speed
Ethernet0 29 twentyfiveGigE1/1 1 25000
Ethernet1 30 twentyfiveGigE1/2 2 25000
Ethernet2 31 twentyfiveGigE1/3 3 25000
Ethernet3 32 twentyfiveGigE1/4 4 25000
Ethernet4 33 twentyfiveGigE1/5 5 25000
Ethernet5 34 twentyfiveGigE1/6 6 25000
Ethernet6 35 twentyfiveGigE1/7 7 25000
Ethernet7 36 twentyfiveGigE1/8 8 25000
Ethernet8 37 twentyfiveGigE1/9 9 25000
Ethernet9 38 twentyfiveGigE1/10 10 25000
Ethernet10 39 twentyfiveGigE1/11 11 25000
Ethernet11 40 twentyfiveGigE1/12 12 25000
Ethernet12 41,42,43,44 hundredGigE1/13 13 100000
Ethernet16 45,46,47,48 hundredGigE1/14 14 100000
Ethernet20 49,50,51,52 hundredGigE1/15 15 100000

View File

@ -0,0 +1 @@
{%- include 'qos_config.j2' %}

View File

@ -0,0 +1 @@
SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/td3-s5212f-25g.config.bcm

View File

@ -0,0 +1,2 @@
m0 load 0 0x0 /usr/share/sonic/hwsku/linkscan_led_fw.bin
m0 load 0 0x3800 /usr/share/sonic/hwsku/custom_led.bin

View File

@ -0,0 +1,159 @@
portmap_1.0=29:25
portmap_2.0=30:25
portmap_3.0=31:25
portmap_4.0=32:25
portmap_5.0=33:25
portmap_6.0=34:25
portmap_7.0=35:25
portmap_8.0=36:25
portmap_9.0=37:25
portmap_10.0=38:25
portmap_11.0=39:25
portmap_12.0=40:25
portmap_33.0=41:100
portmap_37.0=45:100
portmap_41.0=49:100
phy_chain_tx_lane_map_physical{29.0}=0x0123
phy_chain_rx_lane_map_physical{29.0}=0x1032
phy_chain_tx_lane_map_physical{33.0}=0x0123
phy_chain_rx_lane_map_physical{33.0}=0x1032
phy_chain_tx_lane_map_physical{37.0}=0x2013
phy_chain_rx_lane_map_physical{37.0}=0x0231
phy_chain_tx_lane_map_physical{41.0}=0x2301
phy_chain_rx_lane_map_physical{41.0}=0x1230
phy_chain_tx_lane_map_physical{45.0}=0x3120
phy_chain_rx_lane_map_physical{45.0}=0x0213
phy_chain_tx_lane_map_physical{49.0}=0x2301
phy_chain_rx_lane_map_physical{49.0}=0x1032
phy_chain_tx_polarity_flip_physical{29.0}=0x1
phy_chain_rx_polarity_flip_physical{29.0}=0x1
phy_chain_tx_polarity_flip_physical{30.0}=0x1
phy_chain_rx_polarity_flip_physical{30.0}=0x1
phy_chain_tx_polarity_flip_physical{31.0}=0x1
phy_chain_rx_polarity_flip_physical{31.0}=0x1
phy_chain_tx_polarity_flip_physical{32.0}=0x1
phy_chain_rx_polarity_flip_physical{32.0}=0x1
phy_chain_tx_polarity_flip_physical{33.0}=0x1
phy_chain_rx_polarity_flip_physical{33.0}=0x1
phy_chain_tx_polarity_flip_physical{34.0}=0x1
phy_chain_rx_polarity_flip_physical{34.0}=0x1
phy_chain_tx_polarity_flip_physical{35.0}=0x1
phy_chain_rx_polarity_flip_physical{35.0}=0x1
phy_chain_tx_polarity_flip_physical{36.0}=0x1
phy_chain_rx_polarity_flip_physical{36.0}=0x1
phy_chain_tx_polarity_flip_physical{37.0}=0x0
phy_chain_rx_polarity_flip_physical{37.0}=0x0
phy_chain_tx_polarity_flip_physical{38.0}=0x1
phy_chain_rx_polarity_flip_physical{38.0}=0x1
phy_chain_tx_polarity_flip_physical{39.0}=0x1
phy_chain_rx_polarity_flip_physical{39.0}=0x1
phy_chain_tx_polarity_flip_physical{40.0}=0x0
phy_chain_rx_polarity_flip_physical{40.0}=0x0
phy_chain_tx_polarity_flip_physical{41.0}=0x0
phy_chain_rx_polarity_flip_physical{41.0}=0x1
phy_chain_tx_polarity_flip_physical{42.0}=0x1
phy_chain_rx_polarity_flip_physical{42.0}=0x1
phy_chain_tx_polarity_flip_physical{43.0}=0x1
phy_chain_rx_polarity_flip_physical{43.0}=0x0
phy_chain_tx_polarity_flip_physical{44.0}=0x0
phy_chain_rx_polarity_flip_physical{44.0}=0x1
phy_chain_tx_polarity_flip_physical{45.0}=0x1
phy_chain_rx_polarity_flip_physical{45.0}=0x1
phy_chain_tx_polarity_flip_physical{46.0}=0x1
phy_chain_rx_polarity_flip_physical{46.0}=0x1
phy_chain_tx_polarity_flip_physical{47.0}=0x0
phy_chain_rx_polarity_flip_physical{47.0}=0x0
phy_chain_tx_polarity_flip_physical{48.0}=0x0
phy_chain_rx_polarity_flip_physical{48.0}=0x0
phy_chain_tx_polarity_flip_physical{49.0}=0x0
phy_chain_rx_polarity_flip_physical{49.0}=0x0
phy_chain_tx_polarity_flip_physical{50.0}=0x1
phy_chain_rx_polarity_flip_physical{50.0}=0x0
phy_chain_tx_polarity_flip_physical{51.0}=0x1
phy_chain_rx_polarity_flip_physical{51.0}=0x0
phy_chain_tx_polarity_flip_physical{52.0}=0x1
phy_chain_rx_polarity_flip_physical{52.0}=0x1
dport_map_port_1=1
dport_map_port_2=2
dport_map_port_3=3
dport_map_port_4=4
dport_map_port_5=5
dport_map_port_6=6
dport_map_port_7=7
dport_map_port_8=8
dport_map_port_9=9
dport_map_port_10=10
dport_map_port_11=11
dport_map_port_12=12
dport_map_port_33=13
dport_map_port_34=14
dport_map_port_35=15
dport_map_port_36=16
dport_map_port_37=17
dport_map_port_38=18
dport_map_port_39=19
dport_map_port_40=20
dport_map_port_41=21
dport_map_port_42=22
dport_map_port_43=23
dport_map_port_44=24
pbmp_oversubscribe=0x7fff9fffffffffffffffe
pbmp_xport_xe=0x7fff9fffffffffffffffe
port_flex_enable=1
phy_an_c73=3
oversubscribe_mode=1
core_clock_frequency=1525
l2xmsg_mode=1
l2xmsg_hostbuf_size=16384
module_64ports=0
#Interrupts and Parity
max_vp_lags=0
schan_intr_enable=0
tdma_timeout_usec=5000000
stable_size=0x5500000
#Default L3 profile
l2_mem_entries=40960
l3_alpm_enable=2
l3_alpm_ipv6_128b_bkt_rsvd=1
l3_mem_entries=40960
#Tunnels
use_all_splithorizon_groups=1
sai_tunnel_support=1
bcm_tunnel_term_compatible_mode=1
#RIOT Enable
riot_enable=1
riot_overlay_l3_intf_mem_size=4096
riot_overlay_l3_egress_mem_size=32768
l3_ecmp_levels=2
riot_overlay_ecmp_resilient_hash_size=16384
#sai_preinit_cmd_file=/usr/share/sonic/hwsku/sai_preinit_cmd.soc
#New Additions
pfc_deadlock_seq_control=1
#Common configs from broadcom/x86_64-broadcom_common/x86_64-broadcom_b77/broadcom-sonic-td3.config.bcm (Lower version of Td3 (0xb771))
mem_cache_enable=0
ifp_inports_support_enable=1
ipv6_lpm_128b_enable=0x1
l3_max_ecmp_mode=1
lpm_scaling_enable=0
bcm_num_cos=10
default_cpu_tx_queue=9
mmu_lossless=0
host_as_route_disable=1
sai_eapp_config_file=/etc/broadcom/eapps_cfg.json
sai_fast_convergence_support=1
flow_init_mode=1
sai_load_hw_config=/usr/lib/cancun/
# Reduced Trap Group QSET for BRCM Sonic

View File

@ -0,0 +1 @@
DellEMC-S5212f-P-25G t1

View File

@ -0,0 +1,3 @@
CONSOLE_PORT=0x3f8
CONSOLE_DEV=0
CONSOLE_SPEED=115200

View File

@ -0,0 +1,9 @@
# LED microprocessor initialization for Dell S5212
#
#
#Led0
led stop
#m0 load 0 0x0 /usr/share/sonic/hwsku/linkscan_led_fw.bin
m0 load 0 0x3800 /usr/share/sonic/hwsku/custom_led.bin
#led auto on
led start

View File

@ -0,0 +1,31 @@
#!/usr/bin/env python
#############################################################################
# DellEMC S5248f
#
# Platform and model specific eeprom subclass, inherits from the base class,
# and provides the followings:
# - the eeprom format definition
# - specific encoder/decoder if there is special need
#############################################################################
try:
import os.path
from sonic_eeprom import eeprom_tlvinfo
except ImportError, e:
raise ImportError (str(e) + "- required module not found")
class board(eeprom_tlvinfo.TlvInfoDecoder):
def __init__(self, name, path, cpld_root, ro):
self.eeprom_path = None
for b in (0, 1):
f = '/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom'.format(b)
if os.path.exists(f):
self.eeprom_path = f
break
if self.eeprom_path is None:
return
super(board, self).__init__(self.eeprom_path, 0, '', True)

View File

@ -0,0 +1,50 @@
#
# psuutil.py
# Platform-specific PSU status interface for SONiC
#
try:
from sonic_psu.psu_base import PsuBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class PsuUtil(PsuBase):
"""Platform-specific PSUutil class"""
def __init__(self):
PsuBase.__init__(self)
def isDockerEnv(self):
num_docker = open('/proc/self/cgroup', 'r').read().count(":/docker")
return (num_docker > 0)
def get_num_psus(self):
"""
Retrieves the number of PSUs available on the device
:return: An integer, the number of PSUs available on the device
"""
S5212F_MAX_PSUS = 2
return S5212F_MAX_PSUS
def get_psu_status(self, index):
"""
Retrieves the oprational status of power supply unit (PSU) defined
by index <index>
:param index: An integer, index of the PSU of which to query status
:return: Boolean, True if PSU is operating properly, False if PSU is\
faulty
"""
# Until psu_status is implemented this is hardcoded temporarily
return 1
def get_psu_presence(self, index):
"""
Retrieves the presence status of power supply unit (PSU) defined
by index <index>
:param index: An integer, index of the PSU of which to query status
:return: Boolean, True if PSU is plugged, False if not
"""
return 1

View File

@ -0,0 +1,564 @@
# sfputil.py
#
# Platform-specific SFP transceiver interface for SONiC
#
# For S5248F-ON, hardware version X01
try:
import struct
import time
import io
from sonic_sfp.sfputilbase import SfpUtilBase
from os import *
from mmap import *
from sonic_sfp.sff8436 import sff8436InterfaceId
from sonic_sfp.sff8436 import sff8436Dom
from sonic_sfp.sff8472 import sff8472Dom
except ImportError as e:
raise ImportError("%s - required module not found" % str(e))
#definitions of the offset and width for values in DOM info eeprom
QSFP_DOM_REV_OFFSET = 1
QSFP_DOM_REV_WIDTH = 1
QSFP_TEMPE_OFFSET = 22
QSFP_TEMPE_WIDTH = 2
QSFP_VOLT_OFFSET = 26
QSFP_VOLT_WIDTH = 2
QSFP_CHANNL_MON_OFFSET = 34
QSFP_CHANNL_MON_WIDTH = 16
QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24
QSFP_MODULE_THRESHOLD_OFFSET = 128
QSFP_MODULE_THRESHOLD_WIDTH = 24
QSFP_CHANNL_THRESHOLD_OFFSET = 176
QSFP_CHANNL_THRESHOLD_WIDTH = 16
QSFP_CHANNL_MON_MASK_OFFSET = 242
QSFP_CHANNL_MON_MASK_WIDTH = 4
SFP_TEMPE_OFFSET = 96
SFP_TEMPE_WIDTH = 2
SFP_VOLT_OFFSET = 98
SFP_VOLT_WIDTH = 2
SFP_MODULE_THRESHOLD_OFFSET = 0
SFP_MODULE_THRESHOLD_WIDTH = 56
XCVR_DOM_CAPABILITY_OFFSET = 92
XCVR_DOM_CAPABILITY_WIDTH = 1
XCVR_EEPROM_TYPE_SFP = 1
class SfpUtil(SfpUtilBase):
"""Platform-specific SfpUtil class"""
PORT_START = 1
PORT_END = 15
PORTS_IN_BLOCK = 15
BASE_RES_PATH = "/sys/bus/pci/devices/0000:03:00.0/resource0"
_port_to_i2c_mapping = {
1: 2,
2: 3,
3: 4,
4: 5,
5: 6,
6: 7,
7: 8,
8: 9,
9: 10,
10: 11,
11: 12,
12: 13,
# QSFP28
13: 14,
14: 15,
15: 16,
}
_port_to_eeprom_mapping = {}
_global_port_pres_dict = {}
@property
def port_start(self):
return self.PORT_START
@property
def port_end(self):
return self.PORT_END
@property
def qsfp_ports(self):
return range(13, self.PORTS_IN_BLOCK + 1)
@property
def port_to_eeprom_mapping(self):
return self._port_to_eeprom_mapping
def pci_mem_read(self, mm, offset):
mm.seek(offset)
read_data_stream=mm.read(4)
reg_val=struct.unpack('I',read_data_stream)
mem_val = str(reg_val)[1:-2]
# print "reg_val read:%x"%reg_val
return mem_val
def pci_mem_write(self, mm, offset, data):
mm.seek(offset)
# print "data to write:%x"%data
mm.write(struct.pack('I',data))
def pci_set_value(self, resource, val, offset):
fd = open(resource, O_RDWR)
mm = mmap(fd, 0)
val = self.pci_mem_write(mm, offset, val)
mm.close()
close(fd)
return val
def pci_get_value(self, resource, offset):
fd = open(resource, O_RDWR)
mm = mmap(fd, 0)
val = self.pci_mem_read(mm, offset)
mm.close()
close(fd)
return val
def init_global_port_presence(self):
for port_num in range(self.port_start, (self.port_end + 1)):
presence = self.get_presence(port_num)
if(presence):
self._global_port_pres_dict[port_num] = '1'
else:
self._global_port_pres_dict[port_num] = '0'
def __init__(self):
eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom"
for x in range(self.port_start, self.port_end + 1):
self.port_to_eeprom_mapping[x] = eeprom_path.format(
self._port_to_i2c_mapping[x])
self.init_global_port_presence()
SfpUtilBase.__init__(self)
def get_presence(self, port_num):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
# Port offset starts with 0x4004
port_offset = 16388 + ((port_num-1) * 16)
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
reg_value = int(status)
# Absence of status throws error
if (reg_value == "" ):
return False
# Mask off bit for presence
mask = 1
if (port_num > 12):
mask = (1 << 4)
# ModPrsL is active low
if reg_value & mask == 0:
return True
return False
def get_low_power_mode(self, port_num):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
# Port offset starts with 0x4000
port_offset = 16384 + ((port_num-1) * 16)
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
reg_value = int(status)
# Absence of status throws error
if (reg_value == "" ):
return False
# Mask off 4th bit for presence
mask = (1 << 6)
# LPMode is active high
if reg_value & mask == 0:
return False
return True
def set_low_power_mode(self, port_num, lpmode):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
# Port offset starts with 0x4000
port_offset = 16384 + ((port_num-1) * 16)
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
reg_value = int(status)
# Absence of status throws error
if (reg_value == "" ):
return False
# Mask off 4th bit for presence
mask = (1 << 6)
# LPMode is active high; set or clear the bit accordingly
if lpmode is True:
reg_value = reg_value | mask
else:
reg_value = reg_value & ~mask
# Convert our register value back to a hex string and write back
self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)
return True
def reset(self, port_num):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
# Port offset starts with 0x4000
port_offset = 16384 + ((port_num-1) * 16)
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
reg_value = int(status)
# Absence of status throws error
if (reg_value == "" ):
return False
# Mask off 4th bit for presence
mask = (1 << 6)
# ResetL is active low
reg_value = reg_value & ~mask
# Convert our register value back to a hex string and write back
self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)
# Sleep 1 second to allow it to settle
time.sleep(1)
reg_value = reg_value | mask
# Convert our register value back to a hex string and write back
self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)
return True
def get_transceiver_change_event(self, timeout=0):
port_dict = {}
while True:
for port_num in range(self.port_start, (self.port_end + 1)):
presence = self.get_presence(port_num)
if(presence and self._global_port_pres_dict[port_num] == '0'):
self._global_port_pres_dict[port_num] = '1'
port_dict[port_num] = '1'
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, port_dict
time.sleep(0.5)
def get_transceiver_dom_info_dict(self, port_num):
transceiver_dom_info_dict = {}
dom_info_dict_keys = ['temperature', 'voltage', 'rx1power',
'rx2power', 'rx3power', 'rx4power',
'tx1bias', 'tx2bias', 'tx3bias',
'tx4bias', 'tx1power', 'tx2power',
'tx3power', 'tx4power',
]
transceiver_dom_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A')
if port_num in self.qsfp_ports:
offset = 0
offset_xcvr = 128
file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR)
if not self._sfp_eeprom_present(file_path, 0):
return None
try:
sysfsfile_eeprom = io.open(file_path, mode="rb", buffering=0)
except IOError:
print("Error: reading sysfs file %s" % file_path)
return None
sfpd_obj = sff8436Dom()
if sfpd_obj is None:
return transceiver_dom_info_dict
sfpi_obj = sff8436InterfaceId()
if sfpi_obj is None:
return transceiver_dom_info_dict
# QSFP capability byte parse, through this byte can know whether it support tx_power or not.
# TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436,
# need to add more code for determining the capability and version compliance
# in SFF-8636 dom capability definitions evolving with the versions.
qsfp_dom_capability_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset_xcvr + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH)
if qsfp_dom_capability_raw is not None:
qspf_dom_capability_data = sfpi_obj.parse_qsfp_dom_capability(qsfp_dom_capability_raw, 0)
else:
return transceiver_dom_info_dict
dom_temperature_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH)
if dom_temperature_raw is not None:
dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0)
else:
return transceiver_dom_info_dict
dom_voltage_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH)
if dom_voltage_raw is not None:
dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0)
else:
return transceiver_dom_info_dict
qsfp_dom_rev_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_DOM_REV_OFFSET), QSFP_DOM_REV_WIDTH)
if qsfp_dom_rev_raw is not None:
qsfp_dom_rev_data = sfpd_obj.parse_sfp_dom_rev(qsfp_dom_rev_raw, 0)
else:
return transceiver_dom_info_dict
transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value']
transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value']
# The tx_power monitoring is only available on QSFP which compliant with SFF-8636
# and claimed that it support tx_power with one indicator bit.
dom_channel_monitor_data = {}
qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value']
qsfp_tx_power_support = qspf_dom_capability_data['data']['Tx_power_support']['value']
if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')):
dom_channel_monitor_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WIDTH)
if dom_channel_monitor_raw is not None:
dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0)
else:
return transceiver_dom_info_dict
transceiver_dom_info_dict['tx1power'] = 'N/A'
transceiver_dom_info_dict['tx2power'] = 'N/A'
transceiver_dom_info_dict['tx3power'] = 'N/A'
transceiver_dom_info_dict['tx4power'] = 'N/A'
try:
sysfsfile_eeprom.close()
except IOError:
print("Error: closing sysfs file %s" % file_path)
return None
transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value']
transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value']
transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value']
transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value']
transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value']
transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value']
transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value']
transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value']
transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value']
transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value']
else:
offset = 256
file_path = self._get_port_eeprom_path(port_num, self.DOM_EEPROM_ADDR)
if not self._sfp_eeprom_present(file_path, 0):
return None
try:
sysfsfile_eeprom = io.open(file_path,"rb",0)
except IOError:
print("Error: reading sysfs file %s" % file_path)
return None
sfpd_obj = sff8472Dom(None,1)
if sfpd_obj is None:
return transceiver_dom_info_dict
dom_temperature_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_TEMPE_OFFSET),
SFP_TEMPE_WIDTH)
if dom_temperature_raw is not None:
dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0)
else:
return transceiver_dom_info_dict
dom_voltage_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_VOLT_OFFSET),
SFP_VOLT_WIDTH)
if dom_voltage_raw is not None:
dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0)
else:
return transceiver_dom_info_dict
dom_channel_monitor_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_MODULE_THRESHOLD_OFFSET),
SFP_MODULE_THRESHOLD_WIDTH)
if dom_channel_monitor_raw is not None:
dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0)
else:
return transceiver_dom_info_dict
try:
sysfsfile_eeprom.close()
except IOError:
print("Error: closing sysfs file %s" % file_path)
return None
transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value']
transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value']
transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RXPower']['value']
transceiver_dom_info_dict['rx2power'] = 'N/A'
transceiver_dom_info_dict['rx3power'] = 'N/A'
transceiver_dom_info_dict['rx4power'] = 'N/A'
transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TXBias']['value']
transceiver_dom_info_dict['tx2bias'] = 'N/A'
transceiver_dom_info_dict['tx3bias'] = 'N/A'
transceiver_dom_info_dict['tx4bias'] = 'N/A'
transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TXPower']['value']
transceiver_dom_info_dict['tx2power'] = 'N/A'
transceiver_dom_info_dict['tx3power'] = 'N/A'
transceiver_dom_info_dict['tx4power'] = 'N/A'
return transceiver_dom_info_dict
def get_transceiver_dom_threshold_info_dict(self, port_num):
transceiver_dom_threshold_info_dict = {}
dom_info_dict_keys = ['temphighalarm', 'temphighwarning',
'templowalarm', 'templowwarning',
'vcchighalarm', 'vcchighwarning',
'vcclowalarm', 'vcclowwarning',
'rxpowerhighalarm', 'rxpowerhighwarning',
'rxpowerlowalarm', 'rxpowerlowwarning',
'txpowerhighalarm', 'txpowerhighwarning',
'txpowerlowalarm', 'txpowerlowwarning',
'txbiashighalarm', 'txbiashighwarning',
'txbiaslowalarm', 'txbiaslowwarning'
]
transceiver_dom_threshold_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A')
if port_num in self.qsfp_ports:
file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR)
if not self._sfp_eeprom_present(file_path, 0):
return None
try:
sysfsfile_eeprom = io.open(file_path, mode="rb", buffering=0)
except IOError:
print("Error: reading sysfs file %s" % file_path)
return None
sfpd_obj = sff8436Dom()
if sfpd_obj is None:
return transceiver_dom_threshold_info_dict
# Dom Threshold data starts from offset 384
# Revert offset back to 0 once data is retrieved
offset = 384
dom_module_threshold_raw = self._read_eeprom_specific_bytes(
sysfsfile_eeprom,
(offset + QSFP_MODULE_THRESHOLD_OFFSET),
QSFP_MODULE_THRESHOLD_WIDTH)
if dom_module_threshold_raw is not None:
dom_module_threshold_data = sfpd_obj.parse_module_threshold_values(dom_module_threshold_raw, 0)
else:
return transceiver_dom_threshold_info_dict
dom_channel_threshold_raw = self._read_eeprom_specific_bytes(
sysfsfile_eeprom,
(offset + QSFP_CHANNL_THRESHOLD_OFFSET),
QSFP_CHANNL_THRESHOLD_WIDTH)
if dom_channel_threshold_raw is not None:
dom_channel_threshold_data = sfpd_obj.parse_channel_threshold_values(dom_channel_threshold_raw, 0)
else:
return transceiver_dom_threshold_info_dict
try:
sysfsfile_eeprom.close()
except IOError:
print("Error: closing sysfs file %s" % file_path)
return None
# Threshold Data
transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value']
transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value']
transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value']
transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value']
transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value']
transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value']
transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value']
transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value']
transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_channel_threshold_data['data']['RxPowerHighAlarm']['value']
transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_channel_threshold_data['data']['RxPowerHighWarning']['value']
transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_channel_threshold_data['data']['RxPowerLowAlarm']['value']
transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_channel_threshold_data['data']['RxPowerLowWarning']['value']
transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_channel_threshold_data['data']['TxBiasHighAlarm']['value']
transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_channel_threshold_data['data']['TxBiasHighWarning']['value']
transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_channel_threshold_data['data']['TxBiasLowAlarm']['value']
transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['TxBiasLowWarning']['value']
else:
offset = 256
file_path = self._get_port_eeprom_path(port_num, self.DOM_EEPROM_ADDR)
if not self._sfp_eeprom_present(file_path, 0):
return None
try:
sysfsfile_eeprom = io.open(file_path,"rb",0)
except IOError:
print("Error: reading sysfs file %s" % file_path)
return None
sfpd_obj = sff8472Dom(None,1)
if sfpd_obj is None:
return transceiver_dom_threshold_info_dict
dom_module_threshold_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom,
(offset + SFP_MODULE_THRESHOLD_OFFSET), SFP_MODULE_THRESHOLD_WIDTH)
if dom_module_threshold_raw is not None:
dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold(dom_module_threshold_raw, 0)
else:
return transceiver_dom_threshold_info_dict
try:
sysfsfile_eeprom.close()
except IOError:
print("Error: closing sysfs file %s" % file_path)
return None
#Threshold Data
transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value']
transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value']
transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value']
transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value']
transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value']
transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value']
transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VoltageHighWarning']['value']
transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value']
transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value']
transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value']
transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value']
transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value']
transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value']
transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value']
transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value']
transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value']
transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value']
transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value']
transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value']
transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value']
return transceiver_dom_threshold_info_dict

View File

@ -0,0 +1,4 @@
{
"skip_ledd": true,
"start_ipmievd": true
}

View File

@ -9,6 +9,7 @@ $(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR)
$(SONIC_ONE_IMAGE)_INSTALLS += $(FLASHROM)
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \
$(DELL_Z9264F_PLATFORM_MODULE) \
$(DELL_S5212F_PLATFORM_MODULE) \
$(DELL_S5224F_PLATFORM_MODULE) \
$(DELL_S5232F_PLATFORM_MODULE) \
$(DELL_S5248F_PLATFORM_MODULE) \

View File

@ -4,6 +4,7 @@ DELL_S6000_PLATFORM_MODULE_VERSION = 1.1
DELL_Z9100_PLATFORM_MODULE_VERSION = 1.1
DELL_S6100_PLATFORM_MODULE_VERSION = 1.1
DELL_Z9264F_PLATFORM_MODULE_VERSION = 1.1
DELL_S5212F_PLATFORM_MODULE_VERSION = 1.1
DELL_S5224F_PLATFORM_MODULE_VERSION = 1.1
DELL_S5232F_PLATFORM_MODULE_VERSION = 1.1
DELL_Z9332F_PLATFORM_MODULE_VERSION = 1.1
@ -16,6 +17,7 @@ export DELL_S6000_PLATFORM_MODULE_VERSION
export DELL_Z9100_PLATFORM_MODULE_VERSION
export DELL_S6100_PLATFORM_MODULE_VERSION
export DELL_Z9264F_PLATFORM_MODULE_VERSION
export DELL_S5212F_PLATFORM_MODULE_VERSION
export DELL_S5224F_PLATFORM_MODULE_VERSION
export DELL_S5232F_PLATFORM_MODULE_VERSION
export DELL_Z9332F_PLATFORM_MODULE_VERSION
@ -43,6 +45,10 @@ DELL_S6000_PLATFORM_MODULE = platform-modules-s6000_$(DELL_S6000_PLATFORM_MODULE
$(DELL_S6000_PLATFORM_MODULE)_PLATFORM = x86_64-dell_s6000_s1220-r0
$(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_S6000_PLATFORM_MODULE)))
DELL_S5212F_PLATFORM_MODULE = platform-modules-s5212f_$(DELL_S5212F_PLATFORM_MODULE_VERSION)_amd64.deb
$(DELL_S5212F_PLATFORM_MODULE)_PLATFORM = x86_64-dellemc_s5212f_c3538-r0
$(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_S5212F_PLATFORM_MODULE)))
DELL_S5224F_PLATFORM_MODULE = platform-modules-s5224f_$(DELL_S5224F_PLATFORM_MODULE_VERSION)_amd64.deb
$(DELL_S5224F_PLATFORM_MODULE)_PLATFORM = x86_64-dellemc_s5224f_c3538-r0
$(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_S5224F_PLATFORM_MODULE)))

View File

@ -25,6 +25,11 @@ Architecture: amd64
Depends: linux-image-4.19.0-12-2-amd64-unsigned
Description: kernel modules for platform devices such as fan, led, sfp
Package: platform-modules-s5212f
Architecture: amd64
Depends: linux-image-4.19.0-12-2-amd64-unsigned
Description: kernel modules for platform devices such as fan, led, sfp
Package: platform-modules-s5224f
Architecture: amd64
Depends: linux-image-4.19.0-12-2-amd64-unsigned

View File

@ -0,0 +1,40 @@
#!/bin/bash
### BEGIN INIT INFO
# Provides: setup-board
# Required-Start:
# Required-Stop:
# Should-Start:
# Should-Stop:
# Default-Start: S
# Default-Stop: 0 6
# Short-Description: Setup S5212f board.
### END INIT INFO
case "$1" in
start)
echo -n "Setting up board... "
# /usr/local/bin/iom_power_on.sh
/usr/local/bin/s5212f_platform.sh init
echo "done."
;;
stop)
/usr/local/bin/s5212f_platform.sh deinit
echo "done."
;;
force-reload|restart)
echo "Not supported"
;;
*)
echo "Usage: /etc/init.d/platform-modules-s5212f.init {start|stop}"
exit 1
;;
esac
exit 0

View File

@ -0,0 +1,13 @@
s5212f/scripts/s5212f_platform.sh usr/local/bin
s5212f/scripts/check_qsfp.sh usr/local/bin
s5212f/scripts/platform_sensors.py usr/local/bin
s5212f/scripts/sensors usr/bin
s5212f/scripts/qsfp_irq_enable.py usr/bin
s5212f/cfg/s5212f-modules.conf etc/modules-load.d
s5212f/systemd/platform-modules-s5212f.service etc/systemd/system
s5212f/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-dellemc_s5212f_c3538-r0
common/platform_reboot usr/share/sonic/device/x86_64-dellemc_s5212f_c3538-r0
common/fw-updater usr/local/bin
common/onie_mode_set usr/local/bin
s5212f/scripts/pcisysfs.py usr/bin
s5212f/cfg/s5212f-params.conf etc/modprobe.d

View File

@ -0,0 +1,10 @@
# postinst script for S5212f
# Enable Dell-S5212f-platform-service
depmod -a
systemctl enable platform-modules-s5212f.service
systemctl start platform-modules-s5212f.service
#DEBHELPER#

View File

@ -5,7 +5,7 @@ export INSTALL_MOD_DIR:=extra
KVERSION ?= $(shell uname -r)
KERNEL_SRC := /lib/modules/$(KVERSION)
MOD_SRC_DIR:= $(shell pwd)
MODULE_DIRS:= s6000 z9100 s6100 z9264f s5224f s5232f s5248f z9332f s5296f n3248pxe n3248te
MODULE_DIRS:= s6000 z9100 s6100 z9264f s5212f s5224f s5232f s5248f z9332f s5296f n3248pxe n3248te
COMMON_DIR := common
%:
@ -39,6 +39,11 @@ override_dh_auto_build:
python2.7 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \
python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \
cd $(MOD_SRC_DIR); \
elif [ $$mod = "s5212f" ]; then \
cp $(COMMON_DIR)/ipmihelper.py $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \
cd $(MOD_SRC_DIR)/$${mod}; \
python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \
cd $(MOD_SRC_DIR); \
elif [ $$mod = "s5224f" ]; then \
cp $(COMMON_DIR)/ipmihelper.py $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \
cd $(MOD_SRC_DIR)/$${mod}; \
@ -119,6 +124,11 @@ override_dh_clean:
rm -f $(MOD_SRC_DIR)/$${mod}/modules/*.whl; \
rm -rf $(MOD_SRC_DIR)/$${mod}/build; \
rm -rf $(MOD_SRC_DIR)/$${mod}/build/*.egg-info; \
elif [ $$mod = "s5212f" ]; then \
rm -f $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \
rm -f $(MOD_SRC_DIR)/$${mod}/modules/*.whl; \
rm -rf $(MOD_SRC_DIR)/$${mod}/build; \
rm -rf $(MOD_SRC_DIR)/$${mod}/build/*.egg-info; \
elif [ $$mod = "s5224f" ]; then \
rm -f $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \
rm -f $(MOD_SRC_DIR)/$${mod}/modules/*.whl; \

View File

@ -0,0 +1,19 @@
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
i2c-i801
i2c-isch
i2c-ismt
i2c-dev
i2c-mux
i2c-smbus
i2c-mux-gpio
i2c-mux-pca954x
ipmi_devintf
ipmi_si
dell_s5212f_fpga_ocores
i2c_ocores

View File

@ -0,0 +1,2 @@
options ipmi_si kipmid_max_busy_us=1000

View File

@ -0,0 +1,2 @@
obj-m := dell_s5212f_fpga_ocores.o

View File

@ -0,0 +1,3 @@
# Temporary dummy file for s5212f.
# Will be updated soon.

View File

@ -0,0 +1,102 @@
#!/usr/bin/python
# Copyright (c) 2015 Dell Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS
# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
#
# See the Apache Version 2.0 License for specific language governing
# permissions and limitations under the License.
import struct
import sys
import getopt
from os import *
from mmap import *
def usage():
''' This is the Usage Method '''
print '\t\t pcisysfs.py --get --offset <offset> --res <resource>'
print '\t\t pcisysfs.py --set --val <val> --offset <offset> --res <resource>'
sys.exit(1)
def pci_mem_read(mm,offset):
mm.seek(offset)
read_data_stream=mm.read(4)
print ""
reg_val=struct.unpack('I',read_data_stream)
print "reg_val read:%x"%reg_val
return reg_val
def pci_mem_write(mm,offset,data):
mm.seek(offset)
print "data to write:%x"%data
mm.write(struct.pack('I',data))
def pci_set_value(resource,val,offset):
fd=open(resource,O_RDWR)
mm=mmap(fd,0)
pci_mem_write(mm,offset,val)
def pci_get_value(resource,offset):
fd=open(resource,O_RDWR)
mm=mmap(fd,0)
pci_mem_read(mm,offset)
def main(argv):
''' The main function will read the user input from the
command line argument and process the request '''
opts = ''
val = ''
choice = ''
resource = ''
offset = ''
try:
opts, args = getopt.getopt(argv, "hgsv:" , \
["val=","res=","offset=","help", "get", "set"])
except getopt.GetoptError:
usage()
for opt,arg in opts:
if opt in ('-h','--help'):
choice = 'help'
elif opt in ('-g', '--get'):
choice = 'get'
elif opt in ('-s', '--set'):
choice = 'set'
elif opt == '--res':
resource = arg
elif opt == '--val':
val = int(arg,16)
elif opt == '--offset':
offset = int(arg,16)
if choice == 'set' and val != '' and offset !='' and resource !='':
pci_set_value(resource,val,offset)
elif choice == 'get' and offset != '' and resource !='':
pci_get_value(resource,offset)
else:
usage()
#Calling the main method
if __name__ == "__main__":
main(sys.argv[1:])

View File

@ -0,0 +1,125 @@
#!/usr/bin/python
# On S5212F, the BaseBoard Management Controller is an
# autonomous subsystem provides monitoring and management
# facility independent of the host CPU. IPMI standard
# protocol is used with ipmitool to fetch sensor details.
# Current script support X00 board only. X01 support will
# be added soon. This provies support for the
# following objects:
# * Onboard temperature sensors
# * FAN trays
# * PSU
import sys
import logging
import commands
S5212F_MAX_FAN_TRAYS = 4
IPMI_SENSOR_DATA = "ipmitool sdr list"
switch_sku = {
"0K6MG9":(' AC', ' Exhaust'),
"0GKK8W":(' AC', ' Intake'),
"0VK93C":(' AC', ' Exhaust'),
"05JHDM":(' AC', ' Intake'),
"0D72R7":(' AC', ' Exhaust'),
"02PC9F":(' AC', ' Exhaust'),
"0JM5DX":(' AC', ' Intake'),
"0TPDP8":(' AC', ' Exhaust'),
"0WND1V":(' AC', ' Exhaust'),
"05672M":(' DC', ' Intake'),
"0CJV4K":(' DC', ' Intake'),
"0X41RN":(' AC', ' Exhaust'),
"0Y3N82":(' AC', ' Intake'),
"0W4CMG":(' DC', ' Exhaust'),
"04T94Y":(' DC', ' Intake')
}
ipmi_status, ipmi_sdr_list = commands.getstatusoutput(IPMI_SENSOR_DATA)
def get_pmc_register(reg_name):
if ipmi_status:
logging.error('Failed to execute:' + ipmi_sdr_list)
sys.exit(0)
for line in ipmi_sdr_list.splitlines():
sdr = line.split('|')
if reg_name in sdr[0] : return sdr[1]
print('\nFailed to fetch: ' + reg_name + ' sensor ')
sys.exit(0)
# Print the information for temperature sensors
def print_temperature_sensors():
print("\nOnboard Temperature Sensors:")
print ' PT_Left_temp: ',\
(get_pmc_register('PT_Left_temp'))
print ' PT_Mid_temp: ',\
(get_pmc_register('PT_Mid_temp'))
print ' PT_Right_temp: ',\
(get_pmc_register('PT_Right_temp'))
print ' Broadcom Temp: ',\
(get_pmc_register('NPU_Near_temp'))
print ' Inlet Airflow Temp: ',\
(get_pmc_register('ILET_AF_temp'))
print ' CPU Temp: ',\
(get_pmc_register('CPU_temp'))
def get_switch_details():
status, ipmi_fru = commands.getstatusoutput('/usr/bin/ipmitool fru')
for line in ipmi_fru.splitlines():
info = line.split(':')
if 'Board Part Number' in info[0] :
partno = info[1][1:-3]
if (partno in switch_sku): return switch_sku[partno]
return None
commands.getstatusoutput('echo 0 > /sys/module/ipmi_si/parameters/kipmid_max_busy_us')
print_temperature_sensors()
# Print the information for 1 Fan Tray
def print_fan_tray(tray):
print ' Fan Tray ' + str(tray) + ':'
if (tray == 1):
print ' Fan1 Speed: ',\
get_pmc_register('FAN1_Front_rpm')
print ' Fan2 Speed: ',\
get_pmc_register('FAN1_Rear_rpm')
elif (tray == 2):
print ' Fan1 Speed: ',\
get_pmc_register('FAN2_Front_rpm')
print ' Fan2 Speed: ',\
get_pmc_register('FAN2_Rear_rpm')
elif (tray == 3):
print ' Fan1 Speed: ',\
get_pmc_register('FAN3_Front_rpm')
print ' Fan2 Speed: ',\
get_pmc_register('FAN3_Rear_rpm')
elif (tray == 4):
print ' Fan1 Speed: ',\
get_pmc_register('FAN4_Front_rpm')
print ' Fan2 Speed: ',\
get_pmc_register('FAN4_Rear_rpm')
type, dir = get_switch_details()
print('\nFan Trays(Fixed):')
print ' Fan Tray Direction: ', dir
for tray in range(1, S5212F_MAX_FAN_TRAYS + 1):
print_fan_tray(tray)
print('\nPSU Tray(Fixed):')
print ' PSU Tray Direction: ', dir
print ' PSU Tray Type: ', type
ret_status, ipmi_cmd_ret = commands.getstatusoutput('echo 1000 > /sys/module/ipmi_si/parameters/kipmid_max_busy_us')

View File

@ -0,0 +1,30 @@
#!/usr/bin/python
try:
import struct
from os import *
from mmap import *
except ImportError as e:
raise ImportError("%s - required module no found" % str(e))
BASE_RES_PATH = "/sys/bus/pci/devices/0000:04:00.0/resource0"
PORT_START = 0
PORT_END = 15
def pci_mem_write(mm, offset, data):
mm.seek(offset)
mm.write(struct.pack('I', data))
def pci_set_value(resource, val, offset):
fd = open(resource, O_RDWR)
mm = mmap(fd, 0)
pci_mem_write(mm, offset, val)
mm.close()
close(fd)
for port_num in range(PORT_START, PORT_END+1):
port_offset = 0x400c + ((port_num) * 16)
pci_set_value(BASE_RES_PATH, 0x30, port_offset)

View File

@ -0,0 +1,206 @@
#!/bin/bash
init_devnum() {
found=0
for devnum in 0 1; do
devname=`cat /sys/bus/i2c/devices/i2c-${devnum}/name`
# iSMT adapter can be at either dffd0000 or dfff0000
if [[ $devname == 'SMBus iSMT adapter at '* ]]; then
found=1
break
fi
done
[ $found -eq 0 ] && echo "cannot find iSMT" && exit 1
}
# Attach/Detach syseeprom on CPU board
sys_eeprom() {
case $1 in
"new_device") echo 24c16 0x50 > /sys/bus/i2c/devices/i2c-${devnum}/$1
;;
"delete_device") echo 0x50 > /sys/bus/i2c/devices/i2c-${devnum}/$1
;;
*) echo "s5212f_platform: sys_eeprom : invalid command !"
;;
esac
}
#Attach/Detach the MUX connecting all QSFPs
switch_board_qsfp_mux() {
case $1 in
"new_device")
for ((i=603;i<=604;i++));
do
echo "Attaching PCA9548 @ 0x74"
echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-$i/$1
done
;;
"delete_device")
for ((i=603;i<=604;i++));
do
echo "Detaching PCA9548 @ 0x74"
echo 0x74 > /sys/bus/i2c/devices/i2c-$i/$1
done
;;
*) echo "s5212f_platform: switch_board_qsfp_mux: invalid command !"
;;
esac
sleep 2
}
#Attach/Detach 64 instances of EEPROM driver QSFP ports
#eeprom can dump data using below command
switch_board_qsfp() {
case $1 in
"new_device")
for ((i=14;i<=16;i++));
do
echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-$i/$1
done
;;
"delete_device")
for ((i=14;i<=16;i++));
do
echo 0x50 > /sys/bus/i2c/devices/i2c-$i/$1
done
;;
*) echo "s5212f_platform: switch_board_qsfp: invalid command !"
;;
esac
}
#Attach/Detach 2 instances of EEPROM driver SFP+ ports. Use optoe2 (dual address devices)
#eeprom can dump data using below command
switch_board_sfp() {
case $1 in
"new_device")
for ((i=2;i<=13;i++));
do
echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-$i/$1
done
;;
"delete_device")
for ((i=2;i<=13;i++));
do
echo 0x50 > /sys/bus/i2c/devices/i2c-$i/$1
done
;;
*) echo "s5212f_platform: switch_board_sfp: invalid command !"
;;
esac
}
#Modsel 3 ports to applicable QSFP type modules
#This enables the adapter to respond for i2c commands
switch_board_modsel() {
resource="/sys/bus/pci/devices/0000:03:00.0/resource0"
for ((i=1;i<=15;i++));
do
port_addr=$(( 16384 + ((i - 1) * 16)))
hex=$( printf "0x%x" $port_addr )
python /usr/bin/pcisysfs.py --set --offset $hex --val 0x10 --res $resource > /dev/null 2>&1
done
}
#This enables the led control for CPU and default states
switch_board_led_default() {
resource="/sys/bus/pci/devices/0000:03:00.0/resource0"
python /usr/bin/pcisysfs.py --set --offset 0x24 --val 0x194 --res $resource > /dev/null 2>&1
}
# Readout firmware version of the system and
# store in /var/log/firmware_versions
platform_firmware_versions() {
FIRMWARE_VERSION_FILE=/var/log/firmware_versions
rm -rf ${FIRMWARE_VERSION_FILE}
echo "BIOS: `dmidecode -s system-version `" > $FIRMWARE_VERSION_FILE
## Get FPGA version
r=`/usr/bin/pcisysfs.py --get --offset 0x00 --res /sys/bus/pci/devices/0000\:03\:00.0/resource0 | sed '1d; s/.*\(....\)$/\1/; s/\(..\{1\}\)/\1./'`
r_min=$(echo $r | sed 's/.*\(..\)$/0x\1/')
r_maj=$(echo $r | sed 's/^\(..\).*/0x\1/')
echo "FPGA: $((r_maj)).$((r_min))" >> $FIRMWARE_VERSION_FILE
## Get BMC Firmware Revision
r=`cat /sys/class/ipmi/ipmi0/device/bmc/firmware_revision`
echo "BMC: $r" >> $FIRMWARE_VERSION_FILE
#System CPLD 0x31 on i2c bus 601 ( physical FPGA I2C-2)
r_min=`/usr/sbin/i2cget -y 601 0x31 0x0 | sed ' s/.*\(0x..\)$/\1/'`
r_maj=`/usr/sbin/i2cget -y 601 0x31 0x1 | sed ' s/.*\(0x..\)$/\1/'`
echo "System CPLD: $((r_maj)).$((r_min))" >> $FIRMWARE_VERSION_FILE
#Slave CPLD 1 0x30 on i2c bus 600 ( physical FPGA I2C-1)
r_min=`/usr/sbin/i2cget -y 600 0x30 0x0 | sed ' s/.*\(0x..\)$/\1/'`
r_maj=`/usr/sbin/i2cget -y 600 0x30 0x1 | sed ' s/.*\(0x..\)$/\1/'`
echo "Slave CPLD 1: $((r_maj)).$((r_min))" >> $FIRMWARE_VERSION_FILE
}
install_python_api_package() {
device="/usr/share/sonic/device"
platform=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform)
rv=$(pip3 install $device/$platform/sonic_platform-1.0-py3-none-any.whl)
}
remove_python_api_package() {
rv=$(pip3 show sonic-platform > /dev/null 2>/dev/null)
if [ $? -eq 0 ]; then
rv=$(pip3 uninstall -y sonic-platform > /dev/null 2>/dev/null)
fi
}
get_reboot_cause() {
REBOOT_REASON_FILE="/host/reboot-cause/platform/reboot_reason"
resource="/sys/bus/pci/devices/0000:03:00.0/resource0"
mkdir -p $(dirname $REBOOT_REASON_FILE)
# Handle First Boot into software version with reboot cause determination support
if [[ ! -e $REBOOT_REASON_FILE ]]; then
echo "0" > $REBOOT_REASON_FILE
else
/usr/bin/pcisysfs.py --get --offset 0x18 --res $resource | sed '1d; s/.*:\(.*\)$/\1/;' > $REBOOT_REASON_FILE
fi
/usr/bin/pcisysfs.py --set --val 0x0 --offset 0x18 --res $resource
}
init_devnum
if [ "$1" == "init" ]; then
modprobe i2c-dev
modprobe i2c-mux-pca954x force_deselect_on_exit=1
modprobe ipmi_devintf
modprobe ipmi_si kipmid_max_busy_us=1000
modprobe i2c_ocores
modprobe dell_s5212f_fpga_ocores
sys_eeprom "new_device"
get_reboot_cause
switch_board_qsfp_mux "new_device"
switch_board_qsfp "new_device"
switch_board_sfp "new_device"
switch_board_modsel
switch_board_led_default
install_python_api_package
platform_firmware_versions
elif [ "$1" == "deinit" ]; then
sys_eeprom "delete_device"
switch_board_qsfp "delete_device"
switch_board_sfp "delete_device"
switch_board_qsfp_mux "delete_device"
modprobe -r i2c-mux-pca954x
modprobe -r i2c-dev
remove_python_api_package
modprobe -r ipmi_devintf
modprobe -r ipmi_si
else
echo "s5212f_platform : Invalid option !"
fi

View File

@ -0,0 +1,8 @@
#!/bin/bash
docker exec -i pmon sensors "$@"
docker exec -i pmon /usr/bin/platform_sensors.py "$@"
#To probe sensors not part of lm-sensors
#if [ -r /usr/local/bin/platform_sensors.py ]; then
# python /usr/local/bin/platform_sensors.py
#fi

View File

@ -0,0 +1 @@
../s6100/setup.py

View File

@ -0,0 +1,3 @@
__all__ = ["platform", "chassis", "sfp", "eeprom", "component", "thermal", "psu", "fan","fan_drawer"]
from sonic_platform import *

View File

@ -0,0 +1,326 @@
#!/usr/bin/env python
#############################################################################
# DELLEMC 5212F
#
# Module contains an implementation of SONiC Platform Base API and
# provides the platform information
#
#############################################################################
try:
import os
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
from sonic_platform.fan import Fan
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
MAX_S5212F_COMPONENT = 5 # BIOS,BMC,FPGA,SYSTEM CPLD,SLAVE CPLD
MAX_S5212F_FANTRAY =4
MAX_S5212F_FAN = 2
MAX_S5212F_PSU = 2
MAX_S5212F_THERMAL = 6
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_PATH = "/sys/bus/pci/devices/0000:03:00.0/port_msi"
oir_fd = -1
epoll = -1
_global_port_pres_dict = {}
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 = 15
PORTS_IN_BLOCK = (self.PORT_END + 1)
_qsfp_port = range(13, self.PORT_END + 1)
eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom"
for index in range(self.PORT_START, PORTS_IN_BLOCK):
port_num = index + 1
eeprom_path = eeprom_base.format(port_num)
if index in _qsfp_port:
sfp_node = Sfp(index, 'QSFP', eeprom_path)
else:
sfp_node = Sfp(index, 'SFP', eeprom_path)
self._sfp_list.append(sfp_node)
self._eeprom = Eeprom()
for i in range(MAX_S5212F_THERMAL):
thermal = Thermal(i)
self._thermal_list.append(thermal)
for i in range(MAX_S5212F_COMPONENT):
component = Component(i)
self._component_list.append(component)
for i in range(MAX_S5212F_PSU):
psu = Psu(i)
self._psu_list.append(psu)
for i in range(MAX_S5212F_FANTRAY):
for j in range(MAX_S5212F_FAN):
fan = Fan(i,j)
self._fan_list.append(fan)
for i in range(MAX_S5212F_FANTRAY):
fandrawer = FanDrawer(i)
self._fan_drawer_list.append(fandrawer)
self._fan_list.extend(fandrawer._fan_list)
for port_num in range(self.PORT_START, (self.PORT_END + 1)):
# sfp get uses zero-indexing, but port numbers start from 1
presence = self.get_sfp(port_num).get_presence()
if presence:
self._global_port_pres_dict[port_num] = '1'
else:
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()
# not needed /delete after validation
def _get_register(self, reg_file):
retval = 'ERR'
if (not os.path.isfile(reg_file)):
print(reg_file, 'not found !')
return retval
try:
with os.fdopen(os.open(reg_file, os.O_RDONLY)) as fd:
retval = fd.read()
except Exception:
pass
retval = retval.rstrip('\r\n')
retval = retval.lstrip(" ")
return retval
# not needed /delete after validation
def _check_interrupts(self, port_dict):
retval = 0
is_port_dict_updated = False
for port_num in range(self.PORT_START, (self.PORT_END + 1)):
# sfp get uses zero-indexing, but port numbers start from 1
sfp = self.get_sfp(port_num-1)
presence = sfp.get_presence()
if(presence and (self._global_port_pres_dict[port_num] == '0')):
is_port_dict_updated = True
self._global_port_pres_dict[port_num] = '1'
port_dict[port_num] = '1'
elif(not presence and (self._global_port_pres_dict[port_num] == '1')):
is_port_dict_updated = True
self._global_port_pres_dict[port_num] = '0'
port_dict[port_num] = '0'
return retval, is_port_dict_updated
# 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-1).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'
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 (0-{})\n".format(
index, len(self._sfp_list)-1))
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_revision(self):
"""
Retrieves the revision number of the chassis (Service tag)
Returns:
string: Revision number of chassis
"""
return self._eeprom.revision_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_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_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 Exception:
return (self.REBOOT_CAUSE_NON_HARDWARE, None)
if reboot_cause & 0x1:
return (self.REBOOT_CAUSE_POWER_LOSS, None)
elif reboot_cause & 0x2:
return (self.REBOOT_CAUSE_NON_HARDWARE, None)
elif reboot_cause & 0x4:
return (self.REBOOT_CAUSE_HARDWARE_OTHER, "PSU Shutdown")
elif reboot_cause & 0x8:
return (self.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU, None)
elif reboot_cause & 0x10:
return (self.REBOOT_CAUSE_WATCHDOG, None)
elif reboot_cause & 0x20:
return (self.REBOOT_CAUSE_HARDWARE_OTHER, "BMC Shutdown")
elif reboot_cause & 0x40:
return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Hot-Swap Shutdown")
elif reboot_cause & 0x80:
return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Reset Button Shutdown")
elif reboot_cause & 0x100:
return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Reset Button Cold Reboot")
else:
return (self.REBOOT_CAUSE_NON_HARDWARE, None)
def get_qualified_media_list(self):
return media_part_num_list

View File

@ -0,0 +1,113 @@
#!/usr/bin/env python
########################################################################
# DELLEMC S5212F
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Components' (e.g., BIOS, CPLD, FPGA, BMC etc.) available in
# the platform
#
########################################################################
try:
import subprocess
from sonic_platform_base.component_base import ComponentBase
import sonic_platform.hwaccess as hwaccess
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
def get_bios_version():
return subprocess.check_output(['dmidecode', '-s', 'system-version']).strip()
def get_fpga_version():
val = hwaccess.pci_get_value('/sys/bus/pci/devices/0000:03:00.0/resource0', 0)
return '{}.{}'.format((val >> 8) & 0xff, val & 0xff)
def get_bmc_version():
return subprocess.check_output(
['cat', '/sys/class/ipmi/ipmi0/device/bmc/firmware_revision']
).strip()
def get_cpld_version(bus, i2caddr):
return '{}.{}'.format(hwaccess.i2c_get(bus, i2caddr, 1),
hwaccess.i2c_get(bus, i2caddr, 0)
)
def get_cpld0_version():
return get_cpld_version(601, 0x31)
def get_cpld1_version():
return get_cpld_version(600, 0x30)
class Component(ComponentBase):
"""DellEMC Platform-specific Component class"""
CHASSIS_COMPONENTS = [
['BIOS',
'Performs initialization of hardware components during booting',
get_bios_version
],
['FPGA',
'Used for managing the system LEDs',
get_fpga_version
],
['BMC',
'Platform management controller for on-board temperature monitoring, in-chassis power, Fan and LED control',
get_bmc_version
],
['System CPLD',
'Used for managing the CPU power sequence and CPU states',
get_cpld0_version
],
['Slave CPLD 1',
'Used for managing SFP28/QSFP28 port transceivers (SFP28 1-24, QSFP28 1-4)',
get_cpld1_version
]
]
def __init__(self, component_index = 0):
self.index = component_index
self.name = self.CHASSIS_COMPONENTS[self.index][0]
self.description = self.CHASSIS_COMPONENTS[self.index][1]
self.version = self.CHASSIS_COMPONENTS[self.index][2]()
def get_name(self):
"""
Retrieves the name of the component
Returns:
A string containing the name of the component
"""
return self.name
def get_description(self):
"""
Retrieves the description of the component
Returns:
A string containing the description of the component
"""
return self.description
def get_firmware_version(self):
"""
Retrieves the firmware version of the component
Returns:
A string containing the firmware version of the component
"""
return self.version
def install_firmware(self, image_path):
"""
Installs firmware to the component
Args:
image_path: A string, path to firmware image
Returns:
A boolean, True if install was successful, False if not
"""
return False

View File

@ -0,0 +1,139 @@
#!/usr/bin/env python
#############################################################################
# DellEmc S5212F
#
# Platform and model specific eeprom subclass, inherits from the base class,
# and provides the followings:
# - the eeprom format definition
# - specific encoder/decoder if there is special need
#############################################################################
try:
import os.path
from sonic_eeprom import eeprom_tlvinfo
import binascii
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class Eeprom(eeprom_tlvinfo.TlvInfoDecoder):
def __init__(self):
self.eeprom_path = None
for b in (0, 1):
f = '/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom'.format(b)
if os.path.exists(f):
self.eeprom_path = f
break
if self.eeprom_path is None:
return
super(Eeprom, self).__init__(self.eeprom_path, 0, '', True)
self.eeprom_tlv_dict = dict()
try:
self.eeprom_data = self.read_eeprom()
except:
self.eeprom_data = "N/A"
raise RuntimeError("Eeprom is not Programmed")
else:
eeprom = self.eeprom_data
if not self.is_valid_tlvinfo_header(eeprom):
return
total_length = eeprom[9] << 8 | eeprom[10]
tlv_index = self._TLV_INFO_HDR_LEN
tlv_end = self._TLV_INFO_HDR_LEN + total_length
while (tlv_index + 2) < len(eeprom) and tlv_index < tlv_end:
if not self.is_valid_tlv(eeprom[tlv_index:]):
break
tlv = eeprom[tlv_index:tlv_index + 2
+ eeprom[tlv_index + 1]]
code = "0x%02X" % tlv[0]
name, value = self.decoder(None, tlv)
self.eeprom_tlv_dict[code] = value
if eeprom[tlv_index] == self._TLV_CODE_CRC_32:
break
tlv_index += eeprom[tlv_index+1] + 2
def serial_number_str(self):
"""
Returns the serial number
"""
(is_valid, results) = self.get_tlv_field(
self.eeprom_data, self._TLV_CODE_SERIAL_NUMBER)
if not is_valid:
return "N/A"
return results[2].decode('ascii')
def base_mac_addr(self, e=None):
"""
Returns the base mac address found in the system EEPROM
"""
(is_valid, t) = self.get_tlv_field(
self.eeprom_data, self._TLV_CODE_MAC_BASE)
if not is_valid or t[1] != 6:
return super(TlvInfoDecoder, self).switchaddrstr(e)
return ":".join([binascii.b2a_hex(T) for T in t[2]])
def modelstr(self):
"""
Returns the Model name
"""
(is_valid, results) = self.get_tlv_field(
self.eeprom_data, self._TLV_CODE_PRODUCT_NAME)
if not is_valid:
return "N/A"
return results[2].decode('ascii')
def part_number_str(self):
"""
Returns the part number
"""
(is_valid, results) = self.get_tlv_field(
self.eeprom_data, self._TLV_CODE_PART_NUMBER)
if not is_valid:
return "N/A"
return results[2].decode('ascii')
def serial_str(self):
"""
Returns the servicetag number
"""
(is_valid, results) = self.get_tlv_field(
self.eeprom_data, self._TLV_CODE_SERVICE_TAG)
if not is_valid:
return "N/A"
return results[2].decode('ascii')
def revision_str(self):
"""
Returns the device revision
"""
(is_valid, results) = self.get_tlv_field(
self.eeprom_data, self._TLV_CODE_DEVICE_VERSION)
if not is_valid:
return "N/A"
return (binascii.b2a_hex(results[2])).decode('ascii')
def system_eeprom_info(self):
"""
Returns a dictionary, where keys are the type code defined in
ONIE EEPROM format and values are their corresponding values
found in the system EEPROM.
"""
return self.eeprom_tlv_dict

View File

@ -0,0 +1,181 @@
#!/usr/bin/env python
########################################################################
# DellEMC SS5212F
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Fans' information which are available in the platform.
#
########################################################################
try:
from sonic_platform_base.fan_base import FanBase
from sonic_platform.ipmihelper import IpmiSensor, IpmiFru
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
FAN1_MAX_SPEED_OFFSET = 71
FAN2_MAX_SPEED_OFFSET = 73
PSU_FAN_MAX_SPEED_OFFSET = 50
FAN_DIRECTION_OFFSET = 69
PSU_FAN_DIRECTION_OFFSET = 47
switch_sku = {
"0K6MG9":('AC', 'exhaust'),
"0GKK8W":('AC', 'intake'),
"0VK93C":('AC', 'exhaust'),
"05JHDM":('AC', 'intake'),
"0D72R7":('AC', 'exhaust'),
"02PC9F":('AC', 'exhaust'),
"0JM5DX":('AC', 'intake'),
"0TPDP8":('AC', 'exhaust'),
"0WND1V":('AC', 'exhaust'),
"05672M":('DC', 'intake'),
"0CJV4K":('DC', 'intake'),
"0X41RN":('AC', 'exhaust'),
"0Y3N82":('AC', 'intake'),
"0W4CMG":('DC', 'exhaust'),
"04T94Y":('DC', 'intake')
}
class Fan(FanBase):
"""DellEMC Platform-specific Fan class"""
# { FAN-ID: { Sensor-Name: Sensor-ID } }
FAN_SENSOR_MAPPING = { 1: {"Prsnt": 0x57, "State": 0x57, "Speed": 0x24},
2: {"Prsnt": 0x5b, "State": 0x5b, "Speed": 0x20},
3: {"Prsnt": 0x58, "State": 0x58, "Speed": 0x25},
4: {"Prsnt": 0x5c, "State": 0x5c, "Speed": 0x21},
5: {"Prsnt": 0x59, "State": 0x59, "Speed": 0x26},
6: {"Prsnt": 0x5d, "State": 0x5d, "Speed": 0x22},
7: {"Prsnt": 0x5a, "State": 0x5a, "Speed": 0x27},
8: {"Prsnt": 0x5e, "State": 0x5e, "Speed": 0x23} }
PSU_FAN_SENSOR_MAPPING = { 1: {"State": 0x31, "Speed": 0x2e},
2: {"State": 0x32, "Speed": 0x2f} }
# { FANTRAY-ID: FRU-ID }
FAN_FRU_MAPPING = { 1: 0, 2: 0, 3: 0, 4: 0 }
PSU_FRU_MAPPING = { 1: 0, 2: 0 }
def __init__(self, fantray_index=1, fan_index=1, psu_fan=False,
dependency=None):
self.is_psu_fan = psu_fan
if not self.is_psu_fan:
# API index is starting from 0, DellEMC platform index is
# starting from 1
self.fantrayindex = fantray_index + 1
self.fanindex = fan_index + 1
if (self.fanindex == 1):
self.max_speed_offset = FAN1_MAX_SPEED_OFFSET
else:
self.max_speed_offset = FAN2_MAX_SPEED_OFFSET
self.index = (self.fantrayindex - 1) * 2 + self.fanindex
self.prsnt_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Prsnt"],
is_discrete=True)
self.state_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["State"],
is_discrete=True)
self.speed_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Speed"])
self.fru = IpmiFru(self.FAN_FRU_MAPPING[self.fantrayindex])
else:
self.dependency = dependency
self.fanindex = fan_index
self.state_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["State"],
is_discrete=True)
self.speed_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["Speed"])
self.fru = IpmiFru(self.PSU_FRU_MAPPING[self.fanindex])
self.max_speed_offset = PSU_FAN_MAX_SPEED_OFFSET
self.max_speed = 16000
def get_name(self):
"""
Retrieves the name of the device
Returns:
String: The name of the device
"""
if self.is_psu_fan:
return "PSU{} Fan".format(self.fanindex)
else:
return "FanTray{}-Fan{}".format(self.fantrayindex, self.fanindex)
def get_model(self):
"""
Retrieves the part number of the FAN
Returns:
String: Part number of FAN
"""
return self.fru.get_board_part_number()
def get_serial(self):
"""
Retrieves the serial number of the FAN
Returns:
String: Serial number of FAN
"""
return self.fru.get_board_serial()
def get_presence(self):
"""
Retrieves the presence of the FAN
Returns:
bool: True if fan is present, False if not
"""
return True
def get_status(self):
"""
Retrieves the operational status of the FAN
Returns:
bool: True if FAN is operating properly, False if not
"""
status = False
is_valid, state = self.state_sensor.get_reading()
if is_valid:
if (state == 0x00):
status = True
return status
def get_direction(self):
"""
Retrieves the fan airfow direction
Returns:
A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST
depending on fan direction
Notes:
In DellEMC platforms,
- Forward/Exhaust : Air flows from Port side to Fan side.
- Reverse/Intake : Air flows from Fan side to Port side.
"""
board_info = self.fru.get_board_part_number()
if board_info is not None :
board_part_no = board_info[0:6]
if board_part_no in switch_sku:
return switch_sku[board_part_no][1]
return None
def get_speed(self):
"""
Retrieves the speed of the fan
Returns:
int: percentage of the max fan speed
"""
speed = None
if not self.is_psu_fan :
if self.max_speed == 0:
self.max_speed = self.fru.get_fru_data(self.max_speed_offset,2)[1]
self.max_speed = self.max_speed[1] << 8 | self.max_speed[0]
is_valid, fan_speed = self.speed_sensor.get_reading()
if is_valid and self.max_speed > 0:
speed = (100 * fan_speed)/self.max_speed
return speed
def get_speed_rpm(self):
"""
Retrieves the speed of the fan
Returns:
int: percentage of the max fan speed
"""
fan_speed = None
if not self.is_psu_fan :
is_valid, fan_speed = self.speed_sensor.get_reading()
return fan_speed

View File

@ -0,0 +1,37 @@
#!/usr/bin/env python
########################################################################
# DellEMC S5212F
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Fan-Drawers' information available in the platform.
#
########################################################################
try:
from sonic_platform_base.fan_drawer_base import FanDrawerBase
from sonic_platform.fan import Fan
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
S5212F_FANS_PER_FANTRAY = 2
class FanDrawer(FanDrawerBase):
"""DellEMC Platform-specific Fan class"""
def __init__(self, fantray_index):
FanDrawerBase.__init__(self)
# FanTray is 1-based in DellEMC platforms
self.fantrayindex = fantray_index + 1
for i in range(S5212F_FANS_PER_FANTRAY):
self._fan_list.append(Fan(fantray_index, i))
def get_name(self):
"""
Retrieves the fan drawer name
Returns:
string: The name of the device
"""
return "FanTray{}".format(self.fantrayindex)

View File

@ -0,0 +1 @@
../../common/sonic_platform/hwaccess.py

View File

@ -0,0 +1,269 @@
#!/usr/bin/python3
########################################################################
# DellEMC
#
# Module contains implementation of IpmiSensor and IpmiFru classes that
# provide Sensor's and FRU's information respectively.
#
########################################################################
import subprocess
import re
# IPMI Request Network Function Codes
NetFn_SensorEvent = 0x04
NetFn_Storage = 0x0A
# IPMI Sensor Device Commands
Cmd_GetSensorReadingFactors = 0x23
Cmd_GetSensorThreshold = 0x27
Cmd_GetSensorReading = 0x2D
# IPMI FRU Device Commands
Cmd_ReadFRUData = 0x11
def get_ipmitool_raw_output(args):
"""
Returns a list the elements of which are the individual bytes of
ipmitool raw <cmd> command output.
"""
result_bytes = list()
result = ""
command = "ipmitool raw {}".format(args)
try:
proc = subprocess.Popen(command.split(), stdout=subprocess.PIPE,
universal_newlines=True, stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
if not proc.returncode:
result = stdout.rstrip('\n')
except EnvironmentError:
pass
for i in result.split():
result_bytes.append(int(i, 16))
return result_bytes
class IpmiSensor(object):
# Sensor Threshold types and their respective bit masks
THRESHOLD_BIT_MASK = {
"LowerNonCritical" : 0,
"LowerCritical" : 1,
"LowerNonRecoverable" : 2,
"UpperNonCritical" : 3,
"UpperCritical" : 4,
"UpperNonRecoverable" : 5
}
def __init__(self, sensor_id, is_discrete=False):
self.id = sensor_id
self.is_discrete = is_discrete
def _get_converted_sensor_reading(self, raw_value):
"""
Returns a 2 element tuple(bool, int) in which first element
provides the validity of the reading and the second element is
the converted sensor reading
"""
# Get Sensor Reading Factors
cmd_args = "{} {} {} {}".format(NetFn_SensorEvent,
Cmd_GetSensorReadingFactors,
self.id, raw_value)
factors = get_ipmitool_raw_output(cmd_args)
if len(factors) != 7:
return False, 0
# Compute Twos complement
def get_twos_complement(val, bits):
if val & (1 << (bits - 1)):
val = val - (1 << bits)
return val
# Calculate actual sensor value from the raw sensor value
# using the sensor reading factors.
M = get_twos_complement(((factors[2] & 0xC0) << 8) | factors[1], 10)
B = get_twos_complement(((factors[4] & 0xC0) << 8) | factors[3], 10)
R_exp = get_twos_complement((factors[6] & 0xF0) >> 4, 4)
B_exp = get_twos_complement(factors[6] & 0x0F, 4)
converted_reading = ((M * raw_value) + (B * 10**B_exp)) * 10**R_exp
return True, converted_reading
def get_reading(self):
"""
For Threshold sensors, returns the sensor reading.
For Discrete sensors, returns the state value.
Returns:
A tuple (bool, int) where the first element provides the
validity of the reading and the second element provides the
sensor reading/state value.
"""
# Get Sensor Reading
cmd_args = "{} {} {}".format(NetFn_SensorEvent, Cmd_GetSensorReading,
self.id)
output = get_ipmitool_raw_output(cmd_args)
if len(output) != 4:
return False, 0
# Check reading/state unavailable
if output[1] & 0x20:
return False, 0
if self.is_discrete:
state = ((output[3] & 0x7F) << 8) | output[2]
return True, state
else:
return self._get_converted_sensor_reading(output[0])
def get_threshold(self, threshold_type):
"""
Returns the sensor's threshold value for a given threshold type.
Args:
threshold_type (str) - one of the below mentioned
threshold type strings
"LowerNonCritical"
"LowerCritical"
"LowerNonRecoverable"
"UpperNonCritical"
"UpperCritical"
"UpperNonRecoverable"
Returns:
A tuple (bool, int) where the first element provides the
validity of that threshold and second element provides the
threshold value.
"""
# Thresholds are not valid for discrete sensors
if self.is_discrete:
raise TypeError("Threshold is not applicable for Discrete Sensor")
if threshold_type not in list(self.THRESHOLD_BIT_MASK.keys()):
raise ValueError("Invalid threshold type {} provided. Valid types "
"are {}".format(threshold_type,
list(self.THRESHOLD_BIT_MASK.keys())))
bit_mask = self.THRESHOLD_BIT_MASK[threshold_type]
# Get Sensor Threshold
cmd_args = "{} {} {}".format(NetFn_SensorEvent, Cmd_GetSensorThreshold,
self.id)
thresholds = get_ipmitool_raw_output(cmd_args)
if len(thresholds) != 7:
return False, 0
valid_thresholds = thresholds.pop(0)
# Check whether particular threshold is readable
if valid_thresholds & (1 << bit_mask):
return self._get_converted_sensor_reading(thresholds[bit_mask])
else:
return False, 0
class IpmiFru(object):
def __init__(self, fru_id):
self.id = fru_id
def _get_ipmitool_fru_print(self):
result = ""
command = "ipmitool fru print {}".format(self.id)
try:
proc = subprocess.Popen(command.split(), stdout=subprocess.PIPE,
universal_newlines=True, stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
if not proc.returncode:
result = stdout.rstrip('\n')
except EnvironmentError:
pass
return result
def _get_from_fru(self, info):
"""
Returns a string containing the info from FRU
"""
fru_output = self._get_ipmitool_fru_print()
if not fru_output:
return "NA"
info_req = re.search(r"%s\s*:(.*)" % info, fru_output)
if not info_req:
return "NA"
return info_req.group(1).strip()
def get_board_serial(self):
"""
Returns a string containing the Serial Number of the device.
"""
return self._get_from_fru('Board Serial')
def get_board_part_number(self):
"""
Returns a string containing the Part Number of the device.
"""
return self._get_from_fru('Board Part Number')
def get_board_mfr_id(self):
"""
Returns a string containing the manufacturer id of the FRU.
"""
return self._get_from_fru('Board Mfg')
def get_board_product(self):
"""
Returns a string containing the manufacturer id of the FRU.
"""
return self._get_from_fru('Board Product')
def get_fru_data(self, offset, count=1):
"""
Reads and returns the FRU data at the provided offset.
Args:
offset (int) - FRU offset to read
count (int) - Number of bytes to read [optional, default = 1]
Returns:
A tuple (bool, list(int)) where the first element provides
the validity of the data read and the second element is a
list, the elements of which are the individual bytes of the
FRU data read.
"""
result_bytes = list()
is_valid = True
result = ""
offset_LSB = offset & 0xFF
offset_MSB = offset & 0xFF00
command = "ipmitool raw {} {} {} {} {} {}".format(NetFn_Storage,
Cmd_ReadFRUData,
self.id, offset_LSB,
offset_MSB, count)
try:
proc = subprocess.Popen(command.split(), stdout=subprocess.PIPE,
universal_newlines=True, stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
if not proc.returncode:
result = stdout.rstrip('\n')
except EnvironmentError:
is_valid = False
if (not result) or (not is_valid):
return False, result_bytes
for i in result.split():
result_bytes.append(int(i, 16))
read_count = result_bytes.pop(0)
if read_count != count:
return False, result_bytes
else:
return True, result_bytes

View File

@ -0,0 +1,13 @@
# Media settings key plugin
#
# Generate keys used for lookup in media_settings,json
def get_media_settings_key(physical_port, transceiver_dict):
d = transceiver_dict[physical_port]
media_interface = d['media_interface']
generic_key = '{}-{}'.format(d['form_factor'], media_interface)
if media_interface == 'CR':
generic_key = '{}-{}'.format(generic_key, d['cable_length_detailed'])
return ['{}-{}'.format(d['manufacturename'], d['modelname']),
generic_key
]

View File

@ -0,0 +1,24 @@
#!/usr/bin/env python
#############################################################################
#
# Module contains an implementation of SONiC Platform Base API and
# provides the platform information
#
#############################################################################
try:
from sonic_platform_base.platform_base import PlatformBase
from sonic_platform.chassis import Chassis
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class Platform(PlatformBase):
"""
DELLEMC Platform-specific class
"""
def __init__(self):
PlatformBase.__init__(self)
self._chassis = Chassis()

View File

@ -0,0 +1,180 @@
#!/usr/bin/env python
########################################################################
# DellEMC S5212F
#
# Module contains an implementation of SONiC Platform Base API and
# provides the PSUs' information which are available in the platform
#
########################################################################
try:
from sonic_platform_base.psu_base import PsuBase
from sonic_platform.ipmihelper import IpmiSensor, IpmiFru
from sonic_platform.fan import Fan
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
switch_sku = {
"0K6MG9":('AC', 'exhaust'),
"0GKK8W":('AC', 'intake'),
"0VK93C":('AC', 'exhaust'),
"05JHDM":('AC', 'intake'),
"0D72R7":('AC', 'exhaust'),
"02PC9F":('AC', 'exhaust'),
"0JM5DX":('AC', 'intake'),
"0TPDP8":('AC', 'exhaust'),
"0WND1V":('AC', 'exhaust'),
"05672M":('DC', 'intake'),
"0CJV4K":('DC', 'intake'),
"0X41RN":('AC', 'exhaust'),
"0Y3N82":('AC', 'intake'),
"0W4CMG":('DC', 'exhaust'),
"04T94Y":('DC', 'intake')
}
class Psu(PsuBase):
"""DellEMC Platform-specific PSU class"""
# { PSU-ID: { Sensor-Name: Sensor-ID } }
SENSOR_MAPPING = { 1: { "State": 0x31, "Current": 0x39,
"Power": 0x37, "Voltage": 0x38 },
2: { "State": 0x32, "Current": 0x3F,
"Power": 0x3D, "Voltage": 0x3E } }
# ( PSU-ID: FRU-ID }
FRU_MAPPING = { 1: 0, 2: 0 }
def __init__(self, psu_index):
PsuBase.__init__(self)
# PSU is 1-based in DellEMC platforms
self.index = psu_index + 1
self.state_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["State"],
is_discrete=True)
self.voltage_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Voltage"])
self.current_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Current"])
self.power_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Power"])
self.fru = IpmiFru(self.FRU_MAPPING[self.index])
self._fan_list.append(Fan(fan_index=self.index, psu_fan=True,
dependency=self))
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
return "PSU{}".format(self.index)
def get_presence(self):
"""
Retrieves the presence of the Power Supply Unit (PSU)
Returns:
bool: True if PSU is present, False if not
"""
presence = False
is_valid, state = self.state_sensor.get_reading()
if is_valid:
if (state & 0b1) == 1:
presence = True
return presence
def get_model(self):
"""
Retrieves the part number of the PSU
Returns:
string: Part number of PSU
"""
return self.fru.get_board_part_number()
def get_serial(self):
"""
Retrieves the serial number of the PSU
Returns:
string: Serial number of PSU
"""
return self.fru.get_board_serial()
def get_status(self):
"""
Retrieves the operational status of the PSU
Returns:
bool: True if PSU is operating properly, False if not
"""
status = False
is_valid, state = self.state_sensor.get_reading()
if is_valid:
if (state == 0x01):
status = True
return status
def get_voltage(self):
"""
Retrieves current PSU voltage output
Returns:
A float number, the output voltage in volts,
e.g. 12.1
"""
return None
def get_current(self):
"""
Retrieves present electric current supplied by PSU
Returns:
A float number, electric current in amperes,
e.g. 15.4
"""
return None
def get_power(self):
"""
Retrieves current energy supplied by PSU
Returns:
A float number, the power in watts,
e.g. 302.6
"""
return None
def get_powergood_status(self):
"""
Retrieves the powergood status of PSU
Returns:
A boolean, True if PSU has stablized its output voltages and
passed all its internal self-tests, False if not.
"""
status = False
is_valid, state = self.state_sensor.get_reading()
if is_valid:
if (state == 0x01):
status = True
return status
def get_type(self):
"""
Retrives the Power Type of PSU
Returns :
A string, PSU power type
"""
board_info = self.fru.get_board_part_number()
if board_info is not None :
board_part_no = board_info[0:6]
if board_part_no in switch_sku:
return switch_sku[board_part_no][0]
return None
def get_mfr_id(self):
return self.fru.get_board_mfr_id()

View File

@ -0,0 +1,882 @@
#!/usr/bin/env python
#############################################################################
# DELLEMC S5212F
#
# Module contains an implementation of SONiC Platform Base API and
# provides the platform information
#
#############################################################################
try:
import os
import time
import struct
import mmap
from sonic_platform_base.sfp_base import SfpBase
from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId
from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom
from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId
from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom
from sonic_platform_base.sonic_sfp.sff8472 import sffbase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
ext_media_module = None
try:
import ext_media_api as ext_media_module
except ImportError:
ext_media_module = None
PAGE_OFFSET = 0
KEY_OFFSET = 1
KEY_WIDTH = 2
FUNC_NAME = 3
QSFP_INFO_OFFSET = 128
QSFP_DOM_OFFSET = 0
QSFP_DOM_OFFSET1 = 384
SFP_INFO_OFFSET = 0
SFP_DOM_OFFSET = 256
SFP_STATUS_CONTROL_OFFSET = 110
SFP_STATUS_CONTROL_WIDTH = 7
SFP_TX_DISABLE_HARD_BIT = 7
SFP_TX_DISABLE_SOFT_BIT = 6
qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', 'Length OM2(m)',
'Length OM1(m)', 'Length Cable Assembly(m)')
qsfp_compliance_code_tup = (
'10/40G Ethernet Compliance Code',
'SONET Compliance codes',
'SAS/SATA compliance codes',
'Gigabit Ethernet Compliant codes',
'Fibre Channel link length/Transmitter Technology',
'Fibre Channel transmission media',
'Fibre Channel Speed')
sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)',
'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)',
'LengthOM3(UnitsOf10m)', 'LengthCable(UnitsOfm)')
sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCode',
'ESCONComplianceCodes', 'SONETComplianceCodes',
'EthernetComplianceCodes', 'FibreChannelLinkLength',
'FibreChannelTechnology', 'SFP+CableTechnology',
'FibreChannelTransmissionMedia', 'FibreChannelSpeed')
info_dict_keys = ['type', 'hardware_rev', 'serial',
'manufacturer', 'model', 'connector',
'encoding', 'ext_identifier', 'ext_rateselect_compliance',
'cable_type', 'cable_length', 'nominal_bit_rate',
'specification_compliance', 'type_abbrv_name','vendor_date', 'vendor_oui']
dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status',
'power_lpmode', 'tx_disable', 'tx_disable_channel',
'temperature', 'voltage', 'rx1power',
'rx2power', 'rx3power', 'rx4power',
'tx1bias', 'tx2bias', 'tx3bias',
'tx4bias', 'tx1power', 'tx2power',
'tx3power', 'tx4power']
threshold_dict_keys = ['temphighalarm', 'temphighwarning',
'templowalarm', 'templowwarning',
'vcchighalarm', 'vcchighwarning',
'vcclowalarm', 'vcclowwarning',
'rxpowerhighalarm', 'rxpowerhighwarning',
'rxpowerlowalarm', 'rxpowerlowwarning',
'txpowerhighalarm', 'txpowerhighwarning',
'txpowerlowalarm', 'txpowerlowwarning',
'txbiashighalarm', 'txbiashighwarning',
'txbiaslowalarm', 'txbiaslowwarning']
sff8436_parser = {
'reset_status': [QSFP_DOM_OFFSET, 2, 1, 'parse_dom_status_indicator'],
'rx_los': [QSFP_DOM_OFFSET, 3, 1, 'parse_dom_tx_rx_los'],
'tx_fault': [QSFP_DOM_OFFSET, 4, 1, 'parse_dom_tx_fault'],
'tx_disable': [QSFP_DOM_OFFSET, 86, 1, 'parse_dom_tx_disable'],
'power_lpmode': [QSFP_DOM_OFFSET, 93, 1, 'parse_dom_power_control'],
'power_override': [QSFP_DOM_OFFSET, 93, 1, 'parse_dom_power_control'],
'Temperature': [QSFP_DOM_OFFSET, 22, 2, 'parse_temperature'],
'Voltage': [QSFP_DOM_OFFSET, 26, 2, 'parse_voltage'],
'ChannelMonitor': [QSFP_DOM_OFFSET, 34, 16, 'parse_channel_monitor_params'],
'ChannelMonitor_TxPower':
[QSFP_DOM_OFFSET, 34, 24, 'parse_channel_monitor_params_with_tx_power'],
'cable_type': [QSFP_INFO_OFFSET, -1, -1, 'parse_sfp_info_bulk'],
'cable_length': [QSFP_INFO_OFFSET, -1, -1, 'parse_sfp_info_bulk'],
'connector': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'],
'type': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'],
'encoding': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'],
'ext_identifier': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'],
'ext_rateselect_compliance':
[QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'],
'nominal_bit_rate': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'],
'specification_compliance':
[QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'],
'type_abbrv_name': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'],
'manufacturer': [QSFP_INFO_OFFSET, 20, 16, 'parse_vendor_name'],
'vendor_oui': [QSFP_INFO_OFFSET, 37, 3, 'parse_vendor_oui'],
'model': [QSFP_INFO_OFFSET, 40, 16, 'parse_vendor_pn'],
'hardware_rev': [QSFP_INFO_OFFSET, 56, 2, 'parse_vendor_rev'],
'serial': [QSFP_INFO_OFFSET, 68, 16, 'parse_vendor_sn'],
'vendor_date': [QSFP_INFO_OFFSET, 84, 8, 'parse_vendor_date'],
'dom_capability': [QSFP_INFO_OFFSET, 92, 1, 'parse_qsfp_dom_capability'],
'dom_rev': [QSFP_DOM_OFFSET, 1, 1, 'parse_sfp_dom_rev'],
'ModuleThreshold': [QSFP_DOM_OFFSET1, 128, 24, 'parse_module_threshold_values'],
'ChannelThreshold': [QSFP_DOM_OFFSET1, 176, 16, 'parse_channel_threshold_values'],
}
sff8472_parser = {
'Temperature': [SFP_DOM_OFFSET, 96, 2, 'parse_temperature'],
'Voltage': [SFP_DOM_OFFSET, 98, 2, 'parse_voltage'],
'ChannelMonitor': [SFP_DOM_OFFSET, 100, 6, 'parse_channel_monitor_params'],
'cable_type': [SFP_INFO_OFFSET, -1, -1, 'parse_sfp_info_bulk'],
'cable_length': [SFP_INFO_OFFSET, -1, -1, 'parse_sfp_info_bulk'],
'connector': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'],
'type': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'],
'encoding': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'],
'ext_identifier': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'],
'ext_rateselect_compliance':
[SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'],
'nominal_bit_rate': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'],
'specification_compliance':
[SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'],
'type_abbrv_name': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'],
'manufacturer': [SFP_INFO_OFFSET, 20, 16, 'parse_vendor_name'],
'vendor_oui': [SFP_INFO_OFFSET, 37, 3, 'parse_vendor_oui'],
'model': [SFP_INFO_OFFSET, 40, 16, 'parse_vendor_pn'],
'hardware_rev': [SFP_INFO_OFFSET, 56, 4, 'parse_vendor_rev'],
'serial': [SFP_INFO_OFFSET, 68, 16, 'parse_vendor_sn'],
'vendor_date': [SFP_INFO_OFFSET, 84, 8, 'parse_vendor_date'],
'ModuleThreshold': [SFP_DOM_OFFSET, 0, 56, 'parse_alarm_warning_threshold'],
}
class Sfp(SfpBase):
"""
DELLEMC Platform-specific Sfp class
"""
BASE_RES_PATH = "/sys/bus/pci/devices/0000:03:00.0/resource0"
def __init__(self, index, sfp_type, eeprom_path):
SfpBase.__init__(self)
self.sfp_type = sfp_type
self.index = index
self.eeprom_path = eeprom_path
self.qsfpInfo = sff8436InterfaceId()
self.qsfpDomInfo = sff8436Dom()
self.sfpInfo = sff8472InterfaceId()
self.sfpDomInfo = sff8472Dom(None,1)
def get_eeprom_sysfs_path(self):
return self.eeprom_path
def pci_mem_read(self, mm, offset):
mm.seek(offset)
read_data_stream = mm.read(4)
reg_val = struct.unpack('I', read_data_stream)
mem_val = str(reg_val)[1:-2]
# print "reg_val read:%x"%reg_val
return mem_val
def pci_mem_write(self, mm, offset, data):
mm.seek(offset)
# print "data to write:%x"%data
mm.write(struct.pack('I', data))
def pci_set_value(self, resource, val, offset):
fd = os.open(resource, os.O_RDWR)
mm = mmap.mmap(fd, 0)
val = self.pci_mem_write(mm, offset, val)
mm.close()
os.close(fd)
return val
def pci_get_value(self, resource, offset):
fd = os.open(resource, os.O_RDWR)
mm = mmap.mmap(fd, 0)
val = self.pci_mem_read(mm, offset)
mm.close()
os.close(fd)
return val
def _read_eeprom_bytes(self, eeprom_path, offset, num_bytes):
eeprom_raw = []
try:
eeprom = open(eeprom_path, mode="rb", buffering=0)
except IOError:
return None
for i in range(0, num_bytes):
eeprom_raw.append("0x00")
try:
eeprom.seek(offset)
raw = eeprom.read(num_bytes)
except IOError:
eeprom.close()
return None
print(eeprom_path, num_bytes)
raw = bytearray(raw)
try:
for n in range(0, num_bytes):
eeprom_raw[n] = hex(raw[n])[2:].zfill(2)
except BaseException:
eeprom.close()
return None
eeprom.close()
return eeprom_raw
def _get_eeprom_data(self, eeprom_key):
eeprom_data = None
page_offset = None
if(self.sfp_type == 'QSFP'):
page_offset = sff8436_parser[eeprom_key][PAGE_OFFSET]
eeprom_data_raw = self._read_eeprom_bytes(
self.eeprom_path,
(sff8436_parser[eeprom_key][PAGE_OFFSET] +
sff8436_parser[eeprom_key][KEY_OFFSET]),
sff8436_parser[eeprom_key][KEY_WIDTH])
if (eeprom_data_raw is not None):
# Offset 128 is used to retrieve sff8436InterfaceId Info
# Offset 0 is used to retrieve sff8436Dom Info
if (page_offset == 128):
if ( self.qsfpInfo is None):
return None
eeprom_data = getattr(
self.qsfpInfo, sff8436_parser[eeprom_key][FUNC_NAME])(
eeprom_data_raw, 0)
else:
if ( self.qsfpDomInfo is None):
return None
eeprom_data = getattr(
self.qsfpDomInfo, sff8436_parser[eeprom_key][FUNC_NAME])(
eeprom_data_raw, 0)
else:
page_offset = sff8472_parser[eeprom_key][PAGE_OFFSET]
eeprom_data_raw = self._read_eeprom_bytes(
self.eeprom_path,
(sff8472_parser[eeprom_key][PAGE_OFFSET] +
sff8472_parser[eeprom_key][KEY_OFFSET]),
sff8472_parser[eeprom_key][KEY_WIDTH])
if (eeprom_data_raw is not None):
# Offset 0 is used to retrieve sff8472InterfaceId Info
# Offset 256 is used to retrieve sff8472Dom Info
if (page_offset == 0):
if ( self.sfpInfo is None):
return None
eeprom_data = getattr(
self.sfpInfo, sff8472_parser[eeprom_key][FUNC_NAME])(
eeprom_data_raw, 0)
else:
if ( self.sfpDomInfo is None):
return None
eeprom_data = getattr(
self.sfpDomInfo, sff8472_parser[eeprom_key][FUNC_NAME])(
eeprom_data_raw, 0)
return eeprom_data
def get_transceiver_info(self):
"""
Retrieves transceiver info of this SFP
"""
transceiver_info_dict = {}
compliance_code_dict = {}
transceiver_info_dict = dict.fromkeys(info_dict_keys, 'N/A')
# BaseInformation
try:
iface_data = self._get_eeprom_data('type')
connector = iface_data['data']['Connector']['value']
encoding = iface_data['data']['EncodingCodes']['value']
ext_id = iface_data['data']['Extended Identifier']['value']
rate_identifier = iface_data['data']['RateIdentifier']['value']
identifier = iface_data['data']['type']['value']
type_abbrv_name=iface_data['data']['type_abbrv_name']['value']
if(self.sfp_type == 'QSFP'):
bit_rate = str(
iface_data['data']['Nominal Bit Rate(100Mbs)']['value'])
for key in qsfp_compliance_code_tup:
if key in iface_data['data']['Specification compliance']['value']:
compliance_code_dict[key] = iface_data['data']['Specification compliance']['value'][key]['value']
for key in qsfp_cable_length_tup:
if key in iface_data['data']:
cable_type = key
cable_length = str(iface_data['data'][key]['value'])
else:
bit_rate = str(
iface_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value'])
for key in sfp_compliance_code_tup:
if key in iface_data['data']['Specification compliance']['value']:
compliance_code_dict[key] = iface_data['data']['Specification compliance']['value'][key]['value']
for key in sfp_cable_length_tup:
if key in iface_data['data']:
cable_type = key
cable_length = str(iface_data['data'][key]['value'])
transceiver_info_dict['type_abbrv_name']=type_abbrv_name
transceiver_info_dict['type'] = identifier
transceiver_info_dict['connector'] = connector
transceiver_info_dict['encoding'] = encoding
transceiver_info_dict['ext_identifier'] = ext_id
transceiver_info_dict['ext_rateselect_compliance'] = rate_identifier
transceiver_info_dict['cable_type'] = cable_type
transceiver_info_dict['cable_length'] = cable_length
transceiver_info_dict['nominal_bit_rate'] = bit_rate
transceiver_info_dict['specification_compliance'] = str(compliance_code_dict)
except (ValueError, TypeError) : pass
# Vendor Date
try:
vendor_date_data = self._get_eeprom_data('vendor_date')
vendor_date = vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value']
transceiver_info_dict['vendor_date'] = vendor_date
except (ValueError, TypeError) : pass
# Vendor Name
try:
vendor_name_data = self._get_eeprom_data('manufacturer')
vendor_name = vendor_name_data['data']['Vendor Name']['value']
transceiver_info_dict['manufacturer'] = vendor_name
except (ValueError, TypeError) : pass
# Vendor OUI
try:
vendor_oui_data = self._get_eeprom_data('vendor_oui')
vendor_oui = vendor_oui_data['data']['Vendor OUI']['value']
transceiver_info_dict['vendor_oui'] = vendor_oui
except (ValueError, TypeError) : pass
# Vendor PN
try:
vendor_pn_data = self._get_eeprom_data('model')
vendor_pn = vendor_pn_data['data']['Vendor PN']['value']
transceiver_info_dict['model'] = vendor_pn
except (ValueError, TypeError) : pass
# Vendor Revision
try:
vendor_rev_data = self._get_eeprom_data('hardware_rev')
vendor_rev = vendor_rev_data['data']['Vendor Rev']['value']
transceiver_info_dict['hardware_rev'] = vendor_rev
except (ValueError, TypeError) : pass
# Vendor Serial Number
try:
vendor_sn_data = self._get_eeprom_data('serial')
vendor_sn = vendor_sn_data['data']['Vendor SN']['value']
transceiver_info_dict['serial'] = vendor_sn
except (ValueError, TypeError) : pass
# Attempt ext_media read
if ext_media_module is not None:
ext_media_dict = ext_media_module.get_ext_media_info(self)
for key in ext_media_dict:
value = ext_media_dict[key]
if value in [None, 'None', 'none','n/a', '']:
value = 'N/A'
transceiver_info_dict[key] = str(value)
return transceiver_info_dict
def get_transceiver_threshold_info(self):
"""
Retrieves transceiver threshold info of this SFP
"""
transceiver_dom_threshold_dict = {}
transceiver_dom_threshold_dict = dict.fromkeys(
threshold_dict_keys, 'N/A')
try:
# Module Threshold
module_threshold_data = self._get_eeprom_data('ModuleThreshold')
if (self.sfp_type == 'QSFP'):
transceiver_dom_threshold_dict['temphighalarm'] = module_threshold_data['data']['TempHighAlarm']['value']
transceiver_dom_threshold_dict['temphighwarning'] = module_threshold_data['data']['TempHighWarning']['value']
transceiver_dom_threshold_dict['templowalarm'] = module_threshold_data['data']['TempLowAlarm']['value']
transceiver_dom_threshold_dict['templowwarning'] = module_threshold_data['data']['TempLowWarning']['value']
transceiver_dom_threshold_dict['vcchighalarm'] = module_threshold_data['data']['VccHighAlarm']['value']
transceiver_dom_threshold_dict['vcchighwarning'] = module_threshold_data['data']['VccHighWarning']['value']
transceiver_dom_threshold_dict['vcclowalarm'] = module_threshold_data['data']['VccLowAlarm']['value']
transceiver_dom_threshold_dict['vcclowwarning'] = module_threshold_data['data']['VccLowWarning']['value']
else: #SFP
transceiver_dom_threshold_dict['temphighalarm'] = module_threshold_data['data']['TempHighAlarm']['value']
transceiver_dom_threshold_dict['templowalarm'] = module_threshold_data['data']['TempLowAlarm']['value']
transceiver_dom_threshold_dict['temphighwarning'] = module_threshold_data['data']['TempHighWarning']['value']
transceiver_dom_threshold_dict['templowwarning'] = module_threshold_data['data']['TempLowWarning']['value']
transceiver_dom_threshold_dict['vcchighalarm'] = module_threshold_data['data']['VoltageHighAlarm']['value']
transceiver_dom_threshold_dict['vcclowalarm'] = module_threshold_data['data']['VoltageLowAlarm']['value']
transceiver_dom_threshold_dict['vcchighwarning'] = module_threshold_data['data']['VoltageHighWarning']['value']
transceiver_dom_threshold_dict['vcclowwarning'] = module_threshold_data['data']['VoltageLowWarning']['value']
transceiver_dom_threshold_dict['txbiashighalarm'] = module_threshold_data['data']['BiasHighAlarm']['value']
transceiver_dom_threshold_dict['txbiaslowalarm'] = module_threshold_data['data']['BiasLowAlarm']['value']
transceiver_dom_threshold_dict['txbiashighwarning'] = module_threshold_data['data']['BiasHighWarning']['value']
transceiver_dom_threshold_dict['txbiaslowwarning'] = module_threshold_data['data']['BiasLowWarning']['value']
transceiver_dom_threshold_dict['txpowerhighalarm'] = module_threshold_data['data']['TXPowerHighAlarm']['value']
transceiver_dom_threshold_dict['txpowerlowalarm'] = module_threshold_data['data']['TXPowerLowAlarm']['value']
transceiver_dom_threshold_dict['txpowerhighwarning'] = module_threshold_data['data']['TXPowerHighWarning']['value']
transceiver_dom_threshold_dict['txpowerlowwarning'] = module_threshold_data['data']['TXPowerLowWarning']['value']
transceiver_dom_threshold_dict['rxpowerhighalarm'] = module_threshold_data['data']['RXPowerHighAlarm']['value']
transceiver_dom_threshold_dict['rxpowerlowalarm'] = module_threshold_data['data']['RXPowerLowAlarm']['value']
transceiver_dom_threshold_dict['rxpowerhighwarning'] = module_threshold_data['data']['RXPowerHighWarning']['value']
transceiver_dom_threshold_dict['rxpowerlowwarning'] = module_threshold_data['data']['RXPowerLowWarning']['value']
except (ValueError, TypeError) : pass
try:
if (self.sfp_type == 'QSFP'):
channel_threshold_data = self._get_eeprom_data('ChannelThreshold')
transceiver_dom_threshold_dict['rxpowerhighalarm'] = channel_threshold_data['data']['RxPowerHighAlarm']['value']
transceiver_dom_threshold_dict['rxpowerhighwarning'] = channel_threshold_data['data']['RxPowerHighWarning']['value']
transceiver_dom_threshold_dict['rxpowerlowalarm'] = channel_threshold_data['data']['RxPowerLowAlarm']['value']
transceiver_dom_threshold_dict['rxpowerlowwarning'] = channel_threshold_data['data']['RxPowerLowWarning']['value']
transceiver_dom_threshold_dict['txbiashighalarm'] = channel_threshold_data['data']['TxBiasHighAlarm']['value']
transceiver_dom_threshold_dict['txbiashighwarning'] = channel_threshold_data['data']['TxBiasHighWarning']['value']
transceiver_dom_threshold_dict['txbiaslowalarm'] = channel_threshold_data['data']['TxBiasLowAlarm']['value']
transceiver_dom_threshold_dict['txbiaslowwarning'] = channel_threshold_data['data']['TxBiasLowWarning']['value']
except (ValueError, TypeError) : pass
return transceiver_dom_threshold_dict
def get_transceiver_bulk_status(self):
"""
Retrieves transceiver bulk status of this SFP
"""
tx_bias_list = []
rx_power_list = []
transceiver_dom_dict = {}
transceiver_dom_dict = dict.fromkeys(dom_dict_keys, 'N/A')
# RxLos
rx_los = self.get_rx_los()
# TxFault
tx_fault = self.get_tx_fault()
# ResetStatus
reset_state = self.get_reset_status()
# LowPower Mode
lp_mode = self.get_lpmode()
# TxDisable
tx_disable = self.get_tx_disable()
# TxDisable Channel
tx_disable_channel = self.get_tx_disable_channel()
# Temperature
temperature = self.get_temperature()
# Voltage
voltage = self.get_voltage()
# Channel Monitor
tx_power_list = self.get_tx_power()
# tx bias
tx_bias_list = self.get_tx_bias()
# rx power
rx_power_list = self.get_rx_power()
if tx_bias_list is not None:
transceiver_dom_dict['tx1bias'] = tx_bias_list[0]
transceiver_dom_dict['tx2bias'] = tx_bias_list[1]
transceiver_dom_dict['tx3bias'] = tx_bias_list[2]
transceiver_dom_dict['tx4bias'] = tx_bias_list[3]
if rx_power_list is not None:
transceiver_dom_dict['rx1power'] = rx_power_list[0]
transceiver_dom_dict['rx2power'] = rx_power_list[1]
transceiver_dom_dict['rx3power'] = rx_power_list[2]
transceiver_dom_dict['rx4power'] = rx_power_list[3]
if tx_power_list is not None:
transceiver_dom_dict['tx1power'] = tx_power_list[0]
transceiver_dom_dict['tx2power'] = tx_power_list[1]
transceiver_dom_dict['tx3power'] = tx_power_list[2]
transceiver_dom_dict['tx4power'] = tx_power_list[3]
transceiver_dom_dict['rx_los'] = rx_los
transceiver_dom_dict['tx_fault'] = tx_fault
transceiver_dom_dict['reset_status'] = reset_state
transceiver_dom_dict['power_lpmode'] = lp_mode
transceiver_dom_dict['tx_disable'] = tx_disable
transceiver_dom_dict['tx_disable_channel'] = tx_disable_channel
transceiver_dom_dict['temperature'] = temperature
transceiver_dom_dict['voltage'] = voltage
return transceiver_dom_dict
def get_name(self):
"""
Retrieves the name of the sfp
Returns : QSFP or QSFP+ or QSFP28
"""
try:
iface_data = self._get_eeprom_data('type')
identifier = iface_data['data']['type']['value']
print("IF Data " + identifier)
except (TypeError, ValueError):
return 'N/A'
return identifier
def get_presence(self):
"""
Retrieves the presence of the sfp
Returns : True if sfp is present and false if it is absent
"""
# Check for invalid port_num
mask = {'QSFP' : (1 << 4), 'SFP' : (1 << 0)}
# Port offset starts with 0x4004
port_offset = 16388 + ((self.index-1) * 16)
try:
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
reg_value = int(status)
# ModPrsL is active low
if reg_value & mask[self.sfp_type] == 0:
return True
except ValueError: pass
return False
def get_model(self):
"""
Retrieves the model number (or part number) of the sfp
"""
try:
vendor_pn_data = self._get_eeprom_data('model')
vendor_pn = vendor_pn_data['data']['Vendor PN']['value']
except (TypeError, ValueError):
return 'N/A'
return vendor_pn
def get_serial(self):
"""
Retrieves the serial number of the sfp
"""
try:
vendor_sn_data = self._get_eeprom_data('serial')
vendor_sn = vendor_sn_data['data']['Vendor SN']['value']
except (TypeError, ValueError):
return 'N/A'
return vendor_sn
def get_reset_status(self):
"""
Retrives the reset status of SFP
"""
reset_status = False
try:
if (self.sfp_type == 'QSFP'):
# Port offset starts with 0x4000
port_offset = 16384 + ((self.index-1) * 16)
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
reg_value = int(status)
# Mask off 4th bit for reset status
mask = (1 << 4)
reset_status = not (reg_value & mask)
except ValueError: pass
return reset_status
def get_rx_los(self):
"""
Retrieves the RX LOS (lost-of-signal) status of SFP
"""
rx_los = False
try:
if (self.sfp_type == 'QSFP'):
rx_los_data = self._get_eeprom_data('rx_los')
# As the function expects a single boolean, if any one channel experience LOS,
# is considered LOS for QSFP
for rx_los_id in ('Rx1LOS', 'Rx2LOS', 'Rx3LOS', 'Rx4LOS') :
rx_los |= (rx_los_data['data'][rx_los_id]['value'] is 'On')
else:
rx_los_data = self._read_eeprom_bytes(self.eeprom_path, SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH)
data = int(rx_los_data[0], 16)
rx_los = sffbase().test_bit(data, 1) != 0
except (TypeError, ValueError):
return 'N/A'
return rx_los
def get_tx_fault(self):
"""
Retrieves the TX fault status of SFP
"""
tx_fault = False
try:
if (self.sfp_type == 'QSFP'):
tx_fault_data = self._get_eeprom_data('tx_fault')
for tx_fault_id in ('Tx1Fault', 'Tx2Fault', 'Tx3Fault', 'Tx4Fault') :
tx_fault |= (tx_fault_data['data'][tx_fault_id]['value'] is 'On')
else:
tx_fault_data = self._read_eeprom_bytes(self.eeprom_path, SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH)
data = int(tx_fault_data[0], 16)
tx_fault = (sffbase().test_bit(data, 2) != 0)
except (TypeError, ValueError):
return 'N/A'
return tx_fault
def get_tx_disable(self):
"""
Retrieves the tx_disable status of this SFP
"""
tx_disable = False
try:
if (self.sfp_type == 'QSFP'):
tx_disable_data = self._get_eeprom_data('tx_disable')
for tx_disable_id in ('Tx1Disable', 'Tx2Disable', 'Tx3Disable', 'Tx4Disable'):
tx_disable |= (tx_disable_data['data'][tx_disable_id]['value'] is 'On')
else:
tx_disable_data = self._read_eeprom_bytes(self.eeprom_path, SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH)
data = int(tx_disable_data[0], 16)
tx_disable_hard = (sffbase().test_bit(data, SFP_TX_DISABLE_HARD_BIT) != 0)
tx_disable_soft = (sffbase().test_bit(data, SFP_TX_DISABLE_SOFT_BIT) != 0)
tx_disable = tx_disable_hard | tx_disable_soft
except (TypeError, ValueError):
return 'N/A'
return tx_disable
def get_tx_disable_channel(self):
"""
Retrieves the TX disabled channels in this SFP
"""
tx_disable_channel = 0
try:
if (self.sfp_type == 'QSFP'):
tx_disable_data = self._get_eeprom_data('tx_disable')
for tx_disable_id in ('Tx1Disable', 'Tx2Disable', 'Tx3Disable', 'Tx4Disable'):
tx_disable_channel <<= 1
tx_disable_channel |= (tx_disable_data['data']['Tx1Disable']['value'] is 'On')
except (TypeError, ValueError):
return 'N/A'
return tx_disable_channel
def get_lpmode(self):
"""
Retrieves the lpmode(low power mode) of this SFP
"""
lpmode_state = False
try:
if (self.sfp_type == 'QSFP'):
# Port offset starts with 0x4000
port_offset = 16384 + ((self.index-1) * 16)
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
reg_value = int(status)
# Mask off 6th bit for lpmode
mask = (1 << 6)
lpmode_state = (reg_value & mask)
except ValueError: pass
return lpmode_state
def get_power_override(self):
"""
Retrieves the power-override status of this SFP
"""
power_override_state = False
try:
if (self.sfp_type == 'QSFP'):
power_override_data = self._get_eeprom_data('power_override')
power_override = power_override_data['data']['PowerOverRide']['value']
power_override_state = (power_override is 'On')
except (TypeError, ValueError): pass
return power_override_state
def get_temperature(self):
"""
Retrieves the temperature of this SFP
"""
try :
temperature_data = self._get_eeprom_data('Temperature')
temperature = temperature_data['data']['Temperature']['value']
except (TypeError, ValueError):
return 'N/A'
return temperature
def get_voltage(self):
"""
Retrieves the supply voltage of this SFP
"""
try:
voltage_data = self._get_eeprom_data('Voltage')
voltage = voltage_data['data']['Vcc']['value']
except (TypeError, ValueError):
return 'N/A'
return voltage
def get_tx_bias(self):
"""
Retrieves the TX bias current of this SFP
"""
tx_bias_list = []
try:
tx_bias_data = self._get_eeprom_data('ChannelMonitor')
if (self.sfp_type == 'QSFP'):
for tx_bias_id in ('TX1Bias', 'TX2Bias', 'TX3Bias', 'TX4Bias') :
tx_bias = tx_bias_data['data'][tx_bias_id]['value']
tx_bias_list.append(tx_bias)
else:
tx1_bias = tx_bias_data['data']['TXBias']['value']
tx_bias_list = [tx1_bias, "N/A", "N/A", "N/A"]
except (TypeError, ValueError):
return None
return tx_bias_list
def get_rx_power(self):
"""
Retrieves the received optical power for this SFP
"""
rx_power_list = []
try:
rx_power_data = self._get_eeprom_data('ChannelMonitor')
if (self.sfp_type == 'QSFP'):
for rx_power_id in ('RX1Power', 'RX2Power', 'RX3Power', 'RX4Power'):
rx_power = rx_power_data['data'][rx_power_id]['value']
rx_power_list.append(rx_power)
else:
rx1_pw = rx_power_data['data']['RXPower']['value']
rx_power_list = [rx1_pw, "N/A", "N/A", "N/A"]
except (TypeError, ValueError):
return None
return rx_power_list
def get_tx_power(self):
"""
Retrieves the TX power of this SFP
"""
tx_power_list = []
try:
if(self.sfp_type == 'QSFP'):
# QSFP capability byte parse, through this byte can know whether it support tx_power or not.
# TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436,
# need to add more code for determining the capability and version compliance
# in SFF-8636 dom capability definitions evolving with the versions.
qspf_dom_capability_data = self._get_eeprom_data('dom_capability')
qsfp_dom_rev_data = self._get_eeprom_data('dom_rev')
qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value']
qsfp_tx_power_support = qspf_dom_capability_data['data']['Tx_power_support']['value']
# The tx_power monitoring is only available on QSFP which compliant with SFF-8636
# and claimed that it support tx_power with one indicator bit.
if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')):
return None
channel_monitor_data = self._get_eeprom_data('ChannelMonitor_TxPower')
for tx_power_id in ('TX1Power', 'TX2Power', 'TX3Power', 'TX4Power'):
tx_pw = channel_monitor_data['data'][tx_power_id]['value']
tx_power_list.append(tx_pw)
else:
channel_monitor_data = self._get_eeprom_data('ChannelMonitor')
tx1_pw = channel_monitor_data['data']['TXPower']['value']
tx_power_list = [tx1_pw, 'N/A', 'N/A', 'N/A']
except (TypeError, ValueError):
return None
return tx_power_list
def reset(self):
"""
Reset the SFP and returns all user settings to their default state
"""
try:
if (self.sfp_type == 'QSFP'):
# Port offset starts with 0x4000
port_offset = 16384 + ((self.index-1) * 16)
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
reg_value = int(status)
# Mask off 4th bit for reset
mask = (1 << 4)
# ResetL is active low
reg_value = reg_value & ~mask
# Convert our register value back to a hex string and write back
self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)
# Sleep 1 second to allow it to settle
time.sleep(1)
reg_value = reg_value | mask
# Convert our register value back to a hex string and write back
self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)
except ValueError:
return False
return True
def set_lpmode(self, lpmode):
"""
Sets the lpmode(low power mode) of this SFP
"""
try:
if (self.sfp_type == 'QSFP'):
# Port offset starts with 0x4000
port_offset = 16384 + ((self.index-1) * 16)
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
reg_value = int(status)
# Mask off 6th bit for lowpower mode
mask = (1 << 6)
# LPMode is active high; set or clear the bit accordingly
if lpmode is True:
reg_value = reg_value | mask
else:
reg_value = reg_value & ~mask
# Convert our register value back to a hex string and write back
self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)
except ValueError:
return False
return True
def tx_disable(self, tx_disable):
"""
Disable SFP TX for all channels
"""
return False
def tx_disable_channel(self, channel, disable):
"""
Sets the tx_disable for specified SFP channels
"""
return False
def set_power_override(self, power_override, power_set):
"""
Sets SFP power level using power_override and power_set
"""
return False
def get_status(self):
"""
Retrieves the operational status of the device
"""
reset = self.get_reset_status()
return (not reset)
def get_max_port_power(self):
"""
Retrieves the maximumum power allowed on the port in watts
"""
return (5.0 if self.sfp_type=='QSFP' else 2.5)

View File

@ -0,0 +1,168 @@
#!/usr/bin/env python
########################################################################
# DellEMC S5212F
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Thermals' information which are available in the platform
#
########################################################################
try:
from sonic_platform_base.thermal_base import ThermalBase
from sonic_platform.ipmihelper import IpmiSensor
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class Thermal(ThermalBase):
"""DellEMC Platform-specific Thermal class"""
# [ Sensor-Name, Sensor-ID ]
SENSOR_MAPPING = [
['Port Mid', 0x1],
['NPU Near', 0x2],
['Port Left', 0x3],
['Port Right', 0x4],
['Inlet Airflow Sensor', 0x5],
['CPU', 0xe],
]
def __init__(self, thermal_index):
ThermalBase.__init__(self)
self.index = thermal_index + 1
self.sensor = IpmiSensor(self.SENSOR_MAPPING[self.index - 1][1])
def get_name(self):
"""
Retrieves the name of the thermal
Returns:
string: The name of the thermal
"""
return self.SENSOR_MAPPING[self.index - 1][0]
def get_presence(self):
"""
Retrieves the presence of the thermal
Returns:
bool: True if thermal is present, False if not
"""
return True
def get_model(self):
"""
Retrieves the model number (or part number) of the Thermal
Returns:
string: Model/part number of Thermal
"""
return 'NA'
def get_serial(self):
"""
Retrieves the serial number of the Thermal
Returns:
string: Serial number of Thermal
"""
return 'NA'
def get_status(self):
"""
Retrieves the operational status of the thermal
Returns:
A boolean value, True if thermal is operating properly,
False if not
"""
return True
def get_temperature(self):
"""
Retrieves current temperature reading from thermal
Returns:
A float number of current temperature in Celsius up to
nearest thousandth of one degree Celsius, e.g. 30.125
"""
is_valid, temperature = self.sensor.get_reading()
if not is_valid:
temperature = 0
return "{:.3f}".format(temperature)
def get_high_threshold(self):
"""
Retrieves the high threshold temperature of thermal
Returns:
A float number, the high threshold temperature of thermal in
Celsius up to nearest thousandth of one degree Celsius,
e.g. 30.125
"""
is_valid, high_threshold = self.sensor.get_threshold("UpperNonCritical")
if not is_valid:
high_threshold = 0
return "{:.3f}".format(high_threshold)
def get_high_critical_threshold(self):
"""
Retrieves the high critical threshold temperature of thermal
Returns:
A float number, the high critical threshold temperature of thermal in
Celsius up to nearest thousandth of one degree Celsius,
e.g. 30.125
"""
is_valid, high_crit_threshold = self.sensor.get_threshold("UpperCritical")
if not is_valid:
high_crit_threshold = 0
return "{:.3f}".format(high_crit_threshold)
def get_low_threshold(self):
"""
Retrieves the low threshold temperature of thermal
Returns:
A float number, the low threshold temperature of thermal in
Celsius up to nearest thousandth of one degree Celsius,
e.g. 30.125
"""
is_valid, low_threshold = self.sensor.get_threshold("LowerNonRecoverable")
if not is_valid:
low_threshold = 0
return "{:.3f}".format(low_threshold)
def set_high_threshold(self, temperature):
"""
Sets the high threshold temperature of thermal
Args :
temperature: A float number up to nearest thousandth of one
degree Celsius, e.g. 30.125
Returns:
A boolean, True if threshold is set successfully, False if
not
"""
# Thermal threshold values are pre-defined based on HW.
return False
def set_low_threshold(self, temperature):
"""
Sets the low threshold temperature of thermal
Args :
temperature: A float number up to nearest thousandth of one
degree Celsius, e.g. 30.125
Returns:
A boolean, True if threshold is set successfully, False if
not
"""
# Thermal threshold values are pre-defined based on HW.
return False

View File

@ -0,0 +1,212 @@
#!/usr/bin/env python
########################################################################
#
# DELLEMC S5212f
#
# Abstract base class for implementing a platform-specific class with
# which to interact with a hardware watchdog module in SONiC
#
########################################################################
try:
import ctypes
import subprocess
import syslog
import sonic_platform.component as Component
from sonic_platform_base.watchdog_base import WatchdogBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class _timespec(ctypes.Structure):
_fields_ = [
('tv_sec', ctypes.c_long),
('tv_nsec', ctypes.c_long)
]
class Watchdog(WatchdogBase):
"""
Abstract base class for interfacing with a hardware watchdog module
"""
TIMERS = [15,20,30,40,50,60,65,70,80,100,120,140,160,180,210,240]
armed_time = 0
timeout = 0
CLOCK_MONOTONIC = 1
def __init__(self):
self._librt = ctypes.CDLL('librt.so.1', use_errno=True)
self._clock_gettime = self._librt.clock_gettime
self._clock_gettime.argtypes=[ctypes.c_int, ctypes.POINTER(_timespec)]
def _get_command_result(self, cmdline):
try:
proc = subprocess.Popen(cmdline.split(), stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
result = stdout.rstrip('\n')
except OSError:
result = None
return result
def _get_reg_val(self):
# 0x31 = CPLD I2C Base Address
# 0x07 = Watchdog Function Register
value = self._get_command_result("/usr/sbin/i2cget -y 601 0x31 0x07")
if not value:
return None
else:
return int(value, 16)
def _set_reg_val(self,val):
# 0x31 = CPLD I2C Base Address
# 0x07 = Watchdog Function Register
value = self._get_command_result("/usr/sbin/i2cset -y 601 0x31 0x07 %s"
% (val))
return value
def _get_time(self):
"""
To get clock monotonic time
"""
ts = _timespec()
if self._clock_gettime(self.CLOCK_MONOTONIC, ctypes.pointer(ts)) != 0:
self._errno = ctypes.get_errno()
return 0
return ts.tv_sec + ts.tv_nsec * 1e-9
def arm(self, seconds):
"""
Arm the hardware watchdog with a timeout of <seconds> seconds.
If the watchdog is currently armed, calling this function will
simply reset the timer to the provided value. If the underlying
hardware does not support the value provided in <seconds>, this
method should arm the watchdog with the *next greater*
available value.
Returns:
An integer specifying the *actual* number of seconds the
watchdog was armed with. On failure returns -1.
"""
timer_offset = -1
for key,timer_seconds in enumerate(self.TIMERS):
if seconds <= timer_seconds:
timer_offset = key
seconds = timer_seconds
break
if timer_offset == -1:
return -1
cpld_version = Component.get_cpld0_version()
wd_enabled_version = "0.8"
if cpld_version < wd_enabled_version:
syslog.syslog(syslog.LOG_ERR,
'Older System CPLD ver, Update to 0.8 to support watchdog ')
return -1
# Extracting 5th to 8th bits for WD timer values
reg_val = self._get_reg_val()
wd_timer_offset = (reg_val >> 4) & 0xf
if wd_timer_offset != timer_offset:
# Setting 5th to 7th bits
# value from timer_offset
self.disarm()
self._set_reg_val((reg_val & 0x07) | (timer_offset << 4))
if self.is_armed():
# Setting last bit to WD Timer punch
# Last bit = WD Timer punch
self._set_reg_val(reg_val & 0xFE)
self.armed_time = self._get_time()
self.timeout = seconds
return seconds
else:
# Setting 4th bit to enable WD
# 4th bit = Enable WD
reg_val = self._get_reg_val()
self._set_reg_val(reg_val | 0x8)
self.armed_time = self._get_time()
self.timeout = seconds
return seconds
def disarm(self):
"""
Disarm the hardware watchdog
Returns:
A boolean, True if watchdog is disarmed successfully, False
if not
"""
if self.is_armed():
# Setting 4th bit to disable WD
# 4th bit = Disable WD
reg_val = self._get_reg_val()
self._set_reg_val(reg_val & 0xF7)
self.armed_time = 0
self.timeout = 0
return True
return False
def is_armed(self):
"""
Retrieves the armed state of the hardware watchdog.
Returns:
A boolean, True if watchdog is armed, False if not
"""
# Extracting 4th bit to get WD Enable/Disable status
# 0 - Disabled WD
# 1 - Enabled WD
reg_val = self._get_reg_val()
wd_offset = (reg_val >> 3) & 1
return bool(wd_offset)
def get_remaining_time(self):
"""
If the watchdog is armed, retrieve the number of seconds
remaining on the watchdog timer
Returns:
An integer specifying the number of seconds remaining on
their watchdog timer. If the watchdog is not armed, returns
-1.
S5212f doesnot have hardware support to show remaining time.
Due to this limitation, this API is implemented in software.
This API would return correct software time difference if it
is called from the process which armed the watchdog timer.
If this API called from any other process, it would return
0. If the watchdog is not armed, this API would return -1.
"""
if not self.is_armed():
return -1
if self.armed_time > 0 and self.timeout != 0:
cur_time = self._get_time()
if cur_time <= 0:
return 0
diff_time = int(cur_time - self.armed_time)
if diff_time > self.timeout:
return self.timeout
else:
return self.timeout - diff_time
return 0

View File

@ -0,0 +1,13 @@
[Unit]
Description=Dell S5212f Platform modules
Before=pmon.service
DefaultDependencies=no
[Service]
Type=oneshot
ExecStart=/usr/local/bin/s5212f_platform.sh init
ExecStop=/usr/local/bin/s5212f_platform.sh deinit
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target