[Mellanox] Enhancement for fan led management (#4437)
This commit is contained in:
parent
d3c28a45d9
commit
5e6c20481d
1
device/mellanox/x86_64-mlnx_msn3420-r0/thermal_policy.json
Symbolic link
1
device/mellanox/x86_64-mlnx_msn3420-r0/thermal_policy.json
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../x86_64-mlnx_msn2700-r0/thermal_policy.json
|
1
device/mellanox/x86_64-mlnx_msn4600c-r0/thermal_policy.json
Symbolic link
1
device/mellanox/x86_64-mlnx_msn4600c-r0/thermal_policy.json
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../x86_64-mlnx_msn2700-r0/thermal_policy.json
|
1
device/mellanox/x86_64-mlnx_msn4700-r0/thermal_policy.json
Symbolic link
1
device/mellanox/x86_64-mlnx_msn4700-r0/thermal_policy.json
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../x86_64-mlnx_msn2700-r0/thermal_policy.json
|
@ -12,10 +12,10 @@ try:
|
|||||||
from sonic_platform_base.chassis_base import ChassisBase
|
from sonic_platform_base.chassis_base import ChassisBase
|
||||||
from sonic_platform_base.component_base import ComponentBase
|
from sonic_platform_base.component_base import ComponentBase
|
||||||
from sonic_device_util import get_machine_info
|
from sonic_device_util import get_machine_info
|
||||||
|
from sonic_device_util import get_platform_info
|
||||||
from sonic_daemon_base.daemon_base import Logger
|
from sonic_daemon_base.daemon_base import Logger
|
||||||
from os import listdir
|
from os import listdir
|
||||||
from os.path import isfile, join
|
from os.path import isfile, join
|
||||||
from glob import glob
|
|
||||||
import sys
|
import sys
|
||||||
import io
|
import io
|
||||||
import re
|
import re
|
||||||
@ -61,12 +61,14 @@ class Chassis(ChassisBase):
|
|||||||
|
|
||||||
# Initialize SKU name
|
# Initialize SKU name
|
||||||
self.sku_name = self._get_sku_name()
|
self.sku_name = self._get_sku_name()
|
||||||
self.platform_name = self._get_platform_name()
|
|
||||||
mi = get_machine_info()
|
mi = get_machine_info()
|
||||||
if mi is not None:
|
if mi is not None:
|
||||||
self.name = mi['onie_platform']
|
self.name = mi['onie_platform']
|
||||||
|
self.platform_name = get_platform_info(mi)
|
||||||
else:
|
else:
|
||||||
self.name = self.sku_name
|
self.name = self.sku_name
|
||||||
|
self.platform_name = self._get_platform_name()
|
||||||
|
|
||||||
# move the initialization of each components to their dedicated initializer
|
# move the initialization of each components to their dedicated initializer
|
||||||
# which will be called from platform
|
# which will be called from platform
|
||||||
@ -86,36 +88,29 @@ class Chassis(ChassisBase):
|
|||||||
# Initialize PSU list
|
# Initialize PSU list
|
||||||
self.psu_module = Psu
|
self.psu_module = Psu
|
||||||
for index in range(MLNX_NUM_PSU):
|
for index in range(MLNX_NUM_PSU):
|
||||||
psu = Psu(index, self.sku_name)
|
psu = Psu(index, self.platform_name)
|
||||||
self._psu_list.append(psu)
|
self._psu_list.append(psu)
|
||||||
|
|
||||||
|
|
||||||
def initialize_fan(self):
|
def initialize_fan(self):
|
||||||
|
from .device_data import DEVICE_DATA
|
||||||
from sonic_platform.fan import Fan
|
from sonic_platform.fan import Fan
|
||||||
from sonic_platform.fan import FAN_PATH
|
from .fan_drawer import RealDrawer, VirtualDrawer
|
||||||
self.fan_module = Fan
|
|
||||||
self.fan_path = FAN_PATH
|
|
||||||
# Initialize FAN list
|
|
||||||
multi_rotor_in_drawer = False
|
|
||||||
num_of_fan, num_of_drawer = self._extract_num_of_fans_and_fan_drawers()
|
|
||||||
multi_rotor_in_drawer = num_of_fan > num_of_drawer
|
|
||||||
|
|
||||||
# Fan's direction isn't supported on spectrum 1 devices for now
|
fan_data = DEVICE_DATA[self.platform_name]['fans']
|
||||||
mst_dev_list = glob(MST_DEVICE_NAME_PATTERN)
|
drawer_num = fan_data['drawer_num']
|
||||||
if not mst_dev_list:
|
drawer_type = fan_data['drawer_type']
|
||||||
raise RuntimeError("Can't get chip type due to {} not found".format(MST_DEVICE_NAME_PATTERN))
|
fan_num_per_drawer = fan_data['fan_num_per_drawer']
|
||||||
m = re.search(MST_DEVICE_RE_PATTERN, mst_dev_list[0])
|
drawer_ctor = RealDrawer if drawer_type == 'real' else VirtualDrawer
|
||||||
if m.group(1) == SPECTRUM1_CHIP_ID:
|
fan_index = 0
|
||||||
has_fan_dir = False
|
for drawer_index in range(drawer_num):
|
||||||
else:
|
drawer = drawer_ctor(drawer_index, fan_data)
|
||||||
has_fan_dir = True
|
self._fan_drawer_list.append(drawer)
|
||||||
|
for index in range(fan_num_per_drawer):
|
||||||
for index in range(num_of_fan):
|
fan = Fan(fan_index, drawer)
|
||||||
if multi_rotor_in_drawer:
|
fan_index += 1
|
||||||
fan = Fan(has_fan_dir, index, index/2, False, self.platform_name)
|
drawer._fan_list.append(fan)
|
||||||
else:
|
self._fan_list.append(fan)
|
||||||
fan = Fan(has_fan_dir, index, index, False, self.platform_name)
|
|
||||||
self._fan_list.append(fan)
|
|
||||||
|
|
||||||
|
|
||||||
def initialize_sfp(self):
|
def initialize_sfp(self):
|
||||||
|
@ -5,6 +5,19 @@ DEVICE_DATA = {
|
|||||||
"unk_trust": {"-127:30":13, "31:40":14 , "41:120":15},
|
"unk_trust": {"-127:30":13, "31:40":14 , "41:120":15},
|
||||||
"unk_untrust": {"-127:25":13, "26:30":14 , "31:35":15, "36:120":16}
|
"unk_untrust": {"-127:25":13, "26:30":14 , "31:35":15, "36:120":16}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
'fans': {
|
||||||
|
'drawer_num': 4,
|
||||||
|
'drawer_type': 'real',
|
||||||
|
'fan_num_per_drawer': 2,
|
||||||
|
'support_fan_direction': False,
|
||||||
|
'hot_swappable': True
|
||||||
|
},
|
||||||
|
'psus': {
|
||||||
|
'psu_num': 2,
|
||||||
|
'fan_num_per_psu': 1,
|
||||||
|
'hot_swappable': True,
|
||||||
|
'led_num': 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'x86_64-mlnx_msn2740-r0': {
|
'x86_64-mlnx_msn2740-r0': {
|
||||||
@ -13,6 +26,19 @@ DEVICE_DATA = {
|
|||||||
"unk_trust": {"-127:120":13},
|
"unk_trust": {"-127:120":13},
|
||||||
"unk_untrust": {"-127:15":13, "16:25":14 , "26:30":15, "31:120":17},
|
"unk_untrust": {"-127:15":13, "16:25":14 , "26:30":15, "31:120":17},
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
'fans': {
|
||||||
|
'drawer_num': 4,
|
||||||
|
'drawer_type': 'real',
|
||||||
|
'fan_num_per_drawer': 1,
|
||||||
|
'support_fan_direction': False,
|
||||||
|
'hot_swappable': True
|
||||||
|
},
|
||||||
|
'psus': {
|
||||||
|
'psu_num': 2,
|
||||||
|
'fan_num_per_psu': 1,
|
||||||
|
'hot_swappable': True,
|
||||||
|
'led_num': 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'x86_64-mlnx_msn2100-r0': {
|
'x86_64-mlnx_msn2100-r0': {
|
||||||
@ -21,6 +47,19 @@ DEVICE_DATA = {
|
|||||||
"unk_trust": {"-127:40":12, "41:120":13},
|
"unk_trust": {"-127:40":12, "41:120":13},
|
||||||
"unk_untrust": {"-127:15":12, "16:25":13, "26:30":14, "31:35":15, "36:120":16}
|
"unk_untrust": {"-127:15":12, "16:25":13, "26:30":14, "31:35":15, "36:120":16}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
'fans': {
|
||||||
|
'drawer_num': 1,
|
||||||
|
'drawer_type': 'virtual',
|
||||||
|
'fan_num_per_drawer': 4,
|
||||||
|
'support_fan_direction': False,
|
||||||
|
'hot_swappable': False
|
||||||
|
},
|
||||||
|
'psus': {
|
||||||
|
'psu_num': 2,
|
||||||
|
'fan_num_per_psu': 1,
|
||||||
|
'hot_swappable': False,
|
||||||
|
'led_num': 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'x86_64-mlnx_msn2410-r0': {
|
'x86_64-mlnx_msn2410-r0': {
|
||||||
@ -29,6 +68,19 @@ DEVICE_DATA = {
|
|||||||
"unk_trust": {"-127:30":13, "31:40":14 , "41:120":15},
|
"unk_trust": {"-127:30":13, "31:40":14 , "41:120":15},
|
||||||
"unk_untrust": {"-127:25":13, "26:30":14 , "31:35":15, "36:120":16}
|
"unk_untrust": {"-127:25":13, "26:30":14 , "31:35":15, "36:120":16}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
'fans': {
|
||||||
|
'drawer_num': 4,
|
||||||
|
'drawer_type': 'real',
|
||||||
|
'fan_num_per_drawer': 2,
|
||||||
|
'support_fan_direction': False,
|
||||||
|
'hot_swappable': True
|
||||||
|
},
|
||||||
|
'psus': {
|
||||||
|
'psu_num': 2,
|
||||||
|
'fan_num_per_psu': 1,
|
||||||
|
'hot_swappable': True,
|
||||||
|
'led_num': 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'x86_64-mlnx_msn2010-r0': {
|
'x86_64-mlnx_msn2010-r0': {
|
||||||
@ -37,6 +89,19 @@ DEVICE_DATA = {
|
|||||||
"unk_trust": {"-127:120":12},
|
"unk_trust": {"-127:120":12},
|
||||||
"unk_untrust": {"-127:15":12, "16:20":13 , "21:30":14, "31:35":15, "36:120":16}
|
"unk_untrust": {"-127:15":12, "16:20":13 , "21:30":14, "31:35":15, "36:120":16}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
'fans': {
|
||||||
|
'drawer_num': 1,
|
||||||
|
'drawer_type': 'virtual',
|
||||||
|
'fan_num_per_drawer': 4,
|
||||||
|
'support_fan_direction': False,
|
||||||
|
'hot_swappable': False
|
||||||
|
},
|
||||||
|
'psus': {
|
||||||
|
'psu_num': 2,
|
||||||
|
'fan_num_per_psu': 1,
|
||||||
|
'hot_swappable': False,
|
||||||
|
'led_num': 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'x86_64-mlnx_msn3700-r0': {
|
'x86_64-mlnx_msn3700-r0': {
|
||||||
@ -45,6 +110,19 @@ DEVICE_DATA = {
|
|||||||
"unk_trust": {"-127:25":12, "26:40":13 , "41:120":14},
|
"unk_trust": {"-127:25":12, "26:40":13 , "41:120":14},
|
||||||
"unk_untrust": {"-127:15":12, "16:30":13 , "31:35":14, "36:40":15, "41:120":16},
|
"unk_untrust": {"-127:15":12, "16:30":13 , "31:35":14, "36:40":15, "41:120":16},
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
'fans': {
|
||||||
|
'drawer_num': 6,
|
||||||
|
'drawer_type': 'real',
|
||||||
|
'fan_num_per_drawer': 2,
|
||||||
|
'support_fan_direction': True,
|
||||||
|
'hot_swappable': True
|
||||||
|
},
|
||||||
|
'psus': {
|
||||||
|
'psu_num': 2,
|
||||||
|
'fan_num_per_psu': 1,
|
||||||
|
'hot_swappable': True,
|
||||||
|
'led_num': 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'x86_64-mlnx_msn3700c-r0': {
|
'x86_64-mlnx_msn3700c-r0': {
|
||||||
@ -53,6 +131,19 @@ DEVICE_DATA = {
|
|||||||
"unk_trust": {"-127:40":12, "41:120":13},
|
"unk_trust": {"-127:40":12, "41:120":13},
|
||||||
"unk_untrust": {"-127:10":12, "11:20":13 , "21:30":14, "31:35":15, "36:120":16},
|
"unk_untrust": {"-127:10":12, "11:20":13 , "21:30":14, "31:35":15, "36:120":16},
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
'fans': {
|
||||||
|
'drawer_num': 4,
|
||||||
|
'drawer_type': 'real',
|
||||||
|
'fan_num_per_drawer': 2,
|
||||||
|
'support_fan_direction': True,
|
||||||
|
'hot_swappable': True
|
||||||
|
},
|
||||||
|
'psus': {
|
||||||
|
'psu_num': 2,
|
||||||
|
'fan_num_per_psu': 1,
|
||||||
|
'hot_swappable': True,
|
||||||
|
'led_num': 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'x86_64-mlnx_msn3800-r0': {
|
'x86_64-mlnx_msn3800-r0': {
|
||||||
@ -61,14 +152,82 @@ DEVICE_DATA = {
|
|||||||
"unk_trust": {"-127:30":12, "31:40":13 , "41:120":14},
|
"unk_trust": {"-127:30":12, "31:40":13 , "41:120":14},
|
||||||
"unk_untrust": {"-127:0":12, "1:10":13 , "11:15":14, "16:20":15, "21:35":16, "36:120":17},
|
"unk_untrust": {"-127:0":12, "1:10":13 , "11:15":14, "16:20":15, "21:35":16, "36:120":17},
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
'fans': {
|
||||||
|
'drawer_num': 3,
|
||||||
|
'drawer_type': 'real',
|
||||||
|
'fan_num_per_drawer': 1,
|
||||||
|
'support_fan_direction': True,
|
||||||
|
'hot_swappable': True
|
||||||
|
},
|
||||||
|
'psus': {
|
||||||
|
'psu_num': 2,
|
||||||
|
'fan_num_per_psu': 1,
|
||||||
|
'hot_swappable': True,
|
||||||
|
'led_num': 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'x86_64-mlnx_msn4700-r0': {
|
'x86_64-mlnx_msn4700-r0': {
|
||||||
|
'thermal': {
|
||||||
|
'minimum_table': {
|
||||||
|
"unk_trust": {"-127:120":16},
|
||||||
|
"unk_untrust": {"-127:120":16},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'fans': {
|
||||||
|
'drawer_num': 6,
|
||||||
|
'drawer_type': 'real',
|
||||||
|
'fan_num_per_drawer': 2,
|
||||||
|
'support_fan_direction': True,
|
||||||
|
'hot_swappable': True
|
||||||
|
},
|
||||||
|
'psus': {
|
||||||
|
'psu_num': 2,
|
||||||
|
'fan_num_per_psu': 1,
|
||||||
|
'hot_swappable': True,
|
||||||
|
'led_num': 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'x86_64-mlnx_msn3420-r0': {
|
||||||
'thermal': {
|
'thermal': {
|
||||||
'minimum_table': {
|
'minimum_table': {
|
||||||
"unk_trust": {"-127:120":16},
|
"unk_trust": {"-127:120":16},
|
||||||
"unk_untrust": {"-127:120":16},
|
"unk_untrust": {"-127:120":16},
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
'fans': {
|
||||||
|
'drawer_num': 5,
|
||||||
|
'drawer_type': 'real',
|
||||||
|
'fan_num_per_drawer': 2,
|
||||||
|
'support_fan_direction': True,
|
||||||
|
'hot_swappable': True
|
||||||
|
},
|
||||||
|
'psus': {
|
||||||
|
'psu_num': 2,
|
||||||
|
'fan_num_per_psu': 1,
|
||||||
|
'hot_swappable': True,
|
||||||
|
'led_num': 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'x86_64-mlnx_msn4600c-r0': {
|
||||||
|
'thermal': {
|
||||||
|
'minimum_table': {
|
||||||
|
"unk_trust": {"-127:120":16},
|
||||||
|
"unk_untrust": {"-127:120":16},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'fans': {
|
||||||
|
'drawer_num': 3,
|
||||||
|
'drawer_type': 'real',
|
||||||
|
'fan_num_per_drawer': 1,
|
||||||
|
'support_fan_direction': True,
|
||||||
|
'hot_swappable': True
|
||||||
|
},
|
||||||
|
'psus': {
|
||||||
|
'psu_num': 2,
|
||||||
|
'fan_num_per_psu': 1,
|
||||||
|
'hot_swappable': True,
|
||||||
|
'led_num': 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,25 +13,18 @@ import subprocess
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
from sonic_platform_base.fan_base import FanBase
|
from sonic_platform_base.fan_base import FanBase
|
||||||
|
from .led import FanLed, ComponentFaultyIndicator
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
raise ImportError (str(e) + "- required module not found")
|
raise ImportError (str(e) + "- required module not found")
|
||||||
|
|
||||||
LED_ON = '1'
|
|
||||||
LED_OFF = '0'
|
|
||||||
|
|
||||||
PWM_MAX = 255
|
PWM_MAX = 255
|
||||||
|
|
||||||
FAN_PATH = "/var/run/hw-management/thermal/"
|
FAN_PATH = "/var/run/hw-management/thermal/"
|
||||||
LED_PATH = "/var/run/hw-management/led/"
|
|
||||||
CONFIG_PATH = "/var/run/hw-management/config"
|
CONFIG_PATH = "/var/run/hw-management/config"
|
||||||
# fan_dir isn't supported on Spectrum 1. It is supported on Spectrum 2 and later switches
|
# fan_dir isn't supported on Spectrum 1. It is supported on Spectrum 2 and later switches
|
||||||
FAN_DIR = "/var/run/hw-management/system/fan_dir"
|
FAN_DIR = "/var/run/hw-management/system/fan_dir"
|
||||||
COOLING_STATE_PATH = "/var/run/hw-management/thermal/cooling_cur_state"
|
COOLING_STATE_PATH = "/var/run/hw-management/thermal/cooling_cur_state"
|
||||||
|
|
||||||
# Platforms with unplugable FANs:
|
|
||||||
# 1. don't have fanX_status and should be treated as always present
|
|
||||||
platform_with_unplugable_fan = ['x86_64-mlnx_msn2010-r0', 'x86_64-mlnx_msn2100-r0']
|
|
||||||
|
|
||||||
|
|
||||||
class Fan(FanBase):
|
class Fan(FanBase):
|
||||||
"""Platform-specific Fan class"""
|
"""Platform-specific Fan class"""
|
||||||
@ -44,21 +37,28 @@ class Fan(FanBase):
|
|||||||
PSU_FAN_SPEED = ['0x3c', '0x3c', '0x3c', '0x3c', '0x3c',
|
PSU_FAN_SPEED = ['0x3c', '0x3c', '0x3c', '0x3c', '0x3c',
|
||||||
'0x3c', '0x3c', '0x46', '0x50', '0x5a', '0x64']
|
'0x3c', '0x3c', '0x46', '0x50', '0x5a', '0x64']
|
||||||
|
|
||||||
def __init__(self, has_fan_dir, fan_index, drawer_index = 1, psu_fan = False, platform = None):
|
def __init__(self, fan_index, fan_drawer, psu_fan = False):
|
||||||
|
super(Fan, self).__init__()
|
||||||
|
|
||||||
# API index is starting from 0, Mellanox platform index is starting from 1
|
# API index is starting from 0, Mellanox platform index is starting from 1
|
||||||
self.index = fan_index + 1
|
self.index = fan_index + 1
|
||||||
self.drawer_index = drawer_index + 1
|
self.fan_drawer = fan_drawer
|
||||||
|
|
||||||
self.is_psu_fan = psu_fan
|
self.is_psu_fan = psu_fan
|
||||||
self.always_presence = False if platform not in platform_with_unplugable_fan else True
|
if self.fan_drawer:
|
||||||
|
self.led = ComponentFaultyIndicator(self.fan_drawer.get_led())
|
||||||
|
elif self.is_psu_fan:
|
||||||
|
from .psu import Psu
|
||||||
|
self.led = ComponentFaultyIndicator(Psu.get_shared_led())
|
||||||
|
else:
|
||||||
|
self.led = FanLed(self.index)
|
||||||
|
|
||||||
self.fan_min_speed_path = "fan{}_min".format(self.index)
|
self.fan_min_speed_path = "fan{}_min".format(self.index)
|
||||||
if not self.is_psu_fan:
|
if not self.is_psu_fan:
|
||||||
self.fan_speed_get_path = "fan{}_speed_get".format(self.index)
|
self.fan_speed_get_path = "fan{}_speed_get".format(self.index)
|
||||||
self.fan_speed_set_path = "fan{}_speed_set".format(self.index)
|
self.fan_speed_set_path = "fan{}_speed_set".format(self.index)
|
||||||
self.fan_presence_path = "fan{}_status".format(self.drawer_index)
|
|
||||||
self.fan_max_speed_path = "fan{}_max".format(self.index)
|
self.fan_max_speed_path = "fan{}_max".format(self.index)
|
||||||
self._name = "fan{}".format(fan_index + 1)
|
self._name = "fan{}".format(self.index)
|
||||||
else:
|
else:
|
||||||
self.fan_speed_get_path = "psu{}_fan1_speed_get".format(self.index)
|
self.fan_speed_get_path = "psu{}_fan1_speed_get".format(self.index)
|
||||||
self.fan_presence_path = "psu{}_fan1_speed_get".format(self.index)
|
self.fan_presence_path = "psu{}_fan1_speed_get".format(self.index)
|
||||||
@ -69,15 +69,7 @@ class Fan(FanBase):
|
|||||||
self.psu_i2c_command_path = os.path.join(CONFIG_PATH, 'fan_command')
|
self.psu_i2c_command_path = os.path.join(CONFIG_PATH, 'fan_command')
|
||||||
|
|
||||||
self.fan_status_path = "fan{}_fault".format(self.index)
|
self.fan_status_path = "fan{}_fault".format(self.index)
|
||||||
self.fan_green_led_path = "led_fan{}_green".format(self.drawer_index)
|
|
||||||
self.fan_red_led_path = "led_fan{}_red".format(self.drawer_index)
|
|
||||||
self.fan_orange_led_path = "led_fan{}_orange".format(self.drawer_index)
|
|
||||||
self.fan_pwm_path = "pwm1"
|
self.fan_pwm_path = "pwm1"
|
||||||
self.fan_led_cap_path = "led_fan{}_capability".format(self.drawer_index)
|
|
||||||
if has_fan_dir:
|
|
||||||
self.fan_dir = FAN_DIR
|
|
||||||
else:
|
|
||||||
self.fan_dir = None
|
|
||||||
|
|
||||||
|
|
||||||
def get_direction(self):
|
def get_direction(self):
|
||||||
@ -99,20 +91,10 @@ class Fan(FanBase):
|
|||||||
1 stands for forward, in other words intake
|
1 stands for forward, in other words intake
|
||||||
0 stands for reverse, in other words exhaust
|
0 stands for reverse, in other words exhaust
|
||||||
"""
|
"""
|
||||||
if not self.fan_dir or self.is_psu_fan or not self.get_presence():
|
if self.is_psu_fan:
|
||||||
return self.FAN_DIRECTION_NOT_APPLICABLE
|
return self.FAN_DIRECTION_NOT_APPLICABLE
|
||||||
|
else:
|
||||||
try:
|
return self.fan_drawer.get_direction()
|
||||||
with open(os.path.join(self.fan_dir), 'r') as fan_dir:
|
|
||||||
fan_dir_bits = int(fan_dir.read().strip())
|
|
||||||
fan_mask = 1 << self.drawer_index - 1
|
|
||||||
if fan_dir_bits & fan_mask:
|
|
||||||
return self.FAN_DIRECTION_INTAKE
|
|
||||||
else:
|
|
||||||
return self.FAN_DIRECTION_EXHAUST
|
|
||||||
except (ValueError, IOError) as e:
|
|
||||||
raise RuntimeError("Failed to read fan direction status to {}".format(repr(e)))
|
|
||||||
|
|
||||||
|
|
||||||
def get_name(self):
|
def get_name(self):
|
||||||
return self._name
|
return self._name
|
||||||
@ -150,17 +132,9 @@ class Fan(FanBase):
|
|||||||
status = 1
|
status = 1
|
||||||
else:
|
else:
|
||||||
status = 0
|
status = 0
|
||||||
|
return status == 1
|
||||||
else:
|
else:
|
||||||
if self.always_presence:
|
return self.fan_drawer.get_presence()
|
||||||
status = 1
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
with open(os.path.join(FAN_PATH, self.fan_presence_path), 'r') as presence_status:
|
|
||||||
status = int(presence_status.read().strip())
|
|
||||||
except (ValueError, IOError):
|
|
||||||
status = 0
|
|
||||||
|
|
||||||
return status == 1
|
|
||||||
|
|
||||||
|
|
||||||
def _get_min_speed_in_rpm(self):
|
def _get_min_speed_in_rpm(self):
|
||||||
@ -281,18 +255,6 @@ class Fan(FanBase):
|
|||||||
return status
|
return status
|
||||||
|
|
||||||
|
|
||||||
def _get_led_capability(self):
|
|
||||||
cap_list = None
|
|
||||||
try:
|
|
||||||
with open(os.path.join(LED_PATH, self.fan_led_cap_path), 'r') as fan_led_cap:
|
|
||||||
caps = fan_led_cap.read()
|
|
||||||
cap_list = caps.split()
|
|
||||||
except (ValueError, IOError):
|
|
||||||
status = 0
|
|
||||||
|
|
||||||
return cap_list
|
|
||||||
|
|
||||||
|
|
||||||
def set_status_led(self, color):
|
def set_status_led(self, color):
|
||||||
"""
|
"""
|
||||||
Set led to expected color
|
Set led to expected color
|
||||||
@ -304,48 +266,7 @@ class Fan(FanBase):
|
|||||||
Returns:
|
Returns:
|
||||||
bool: True if set success, False if fail.
|
bool: True if set success, False if fail.
|
||||||
"""
|
"""
|
||||||
led_cap_list = self._get_led_capability()
|
return self.led.set_status(color)
|
||||||
if led_cap_list is None:
|
|
||||||
return False
|
|
||||||
|
|
||||||
if self.is_psu_fan:
|
|
||||||
# PSU fan led status is not able to set
|
|
||||||
return False
|
|
||||||
status = False
|
|
||||||
try:
|
|
||||||
if color == self.STATUS_LED_COLOR_GREEN:
|
|
||||||
with open(os.path.join(LED_PATH, self.fan_green_led_path), 'w') as fan_led:
|
|
||||||
fan_led.write(LED_ON)
|
|
||||||
status = True
|
|
||||||
elif color == self.STATUS_LED_COLOR_RED:
|
|
||||||
# Some fan don't support red led but support orange led, in this case we set led to orange
|
|
||||||
if self.STATUS_LED_COLOR_RED in led_cap_list:
|
|
||||||
led_path = os.path.join(LED_PATH, self.fan_red_led_path)
|
|
||||||
elif self.STATUS_LED_COLOR_ORANGE in led_cap_list:
|
|
||||||
led_path = os.path.join(LED_PATH, self.fan_orange_led_path)
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
with open(led_path, 'w') as fan_led:
|
|
||||||
fan_led.write(LED_ON)
|
|
||||||
status = True
|
|
||||||
elif color == self.STATUS_LED_COLOR_OFF:
|
|
||||||
if self.STATUS_LED_COLOR_GREEN in led_cap_list:
|
|
||||||
with open(os.path.join(LED_PATH, self.fan_green_led_path), 'w') as fan_led:
|
|
||||||
fan_led.write(str(LED_OFF))
|
|
||||||
if self.STATUS_LED_COLOR_RED in led_cap_list:
|
|
||||||
with open(os.path.join(LED_PATH, self.fan_red_led_path), 'w') as fan_led:
|
|
||||||
fan_led.write(str(LED_OFF))
|
|
||||||
if self.STATUS_LED_COLOR_ORANGE in led_cap_list:
|
|
||||||
with open(os.path.join(LED_PATH, self.fan_orange_led_path), 'w') as fan_led:
|
|
||||||
fan_led.write(str(LED_OFF))
|
|
||||||
|
|
||||||
status = True
|
|
||||||
else:
|
|
||||||
status = False
|
|
||||||
except (ValueError, IOError):
|
|
||||||
status = False
|
|
||||||
|
|
||||||
return status
|
|
||||||
|
|
||||||
|
|
||||||
def get_status_led(self):
|
def get_status_led(self):
|
||||||
@ -355,26 +276,7 @@ class Fan(FanBase):
|
|||||||
Returns:
|
Returns:
|
||||||
A string, one of the predefined STATUS_LED_COLOR_* strings above
|
A string, one of the predefined STATUS_LED_COLOR_* strings above
|
||||||
"""
|
"""
|
||||||
led_cap_list = self._get_led_capability()
|
return self.led.get_status()
|
||||||
if led_cap_list is None:
|
|
||||||
return self.STATUS_LED_COLOR_OFF
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(os.path.join(LED_PATH, self.fan_green_led_path), 'r') as fan_led:
|
|
||||||
if LED_OFF != fan_led.read().rstrip('\n'):
|
|
||||||
return self.STATUS_LED_COLOR_GREEN
|
|
||||||
if self.STATUS_LED_COLOR_RED in led_cap_list:
|
|
||||||
with open(os.path.join(LED_PATH, self.fan_red_led_path), 'r') as fan_led:
|
|
||||||
if LED_OFF != fan_led.read().rstrip('\n'):
|
|
||||||
return self.STATUS_LED_COLOR_RED
|
|
||||||
if self.STATUS_LED_COLOR_ORANGE in led_cap_list:
|
|
||||||
with open(os.path.join(LED_PATH, self.fan_orange_led_path), 'r') as fan_led:
|
|
||||||
if LED_OFF != fan_led.read().rstrip('\n'):
|
|
||||||
return self.STATUS_LED_COLOR_RED
|
|
||||||
except (ValueError, IOError) as e:
|
|
||||||
raise RuntimeError("Failed to read led status for fan {} due to {}".format(self.index, repr(e)))
|
|
||||||
|
|
||||||
return self.STATUS_LED_COLOR_OFF
|
|
||||||
|
|
||||||
|
|
||||||
def get_speed_tolerance(self):
|
def get_speed_tolerance(self):
|
||||||
|
104
platform/mellanox/mlnx-platform-api/sonic_platform/fan_drawer.py
Normal file
104
platform/mellanox/mlnx-platform-api/sonic_platform/fan_drawer.py
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Mellanox
|
||||||
|
#
|
||||||
|
# Module contains an implementation of SONiC Platform Base API and
|
||||||
|
# provides the Fan Drawer status which are available in the platform
|
||||||
|
#
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
try:
|
||||||
|
from sonic_platform_base.fan_drawer_base import FanDrawerBase
|
||||||
|
from sonic_platform_base.fan_base import FanBase
|
||||||
|
from .led import FanLed, SharedLed
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError (str(e) + "- required module not found")
|
||||||
|
|
||||||
|
|
||||||
|
class MellanoxFanDrawer(FanDrawerBase):
|
||||||
|
def __init__(self, index, fan_data):
|
||||||
|
from .fan import FAN_PATH
|
||||||
|
super(MellanoxFanDrawer, self).__init__()
|
||||||
|
self._index = index + 1
|
||||||
|
self._fan_data = fan_data
|
||||||
|
self._presence_path = os.path.join(FAN_PATH, 'fan{}_status'.format(self._index))
|
||||||
|
self._led = None
|
||||||
|
|
||||||
|
def get_index(self):
|
||||||
|
return self._index
|
||||||
|
|
||||||
|
def get_led(self):
|
||||||
|
return self._led
|
||||||
|
|
||||||
|
def get_presence(self):
|
||||||
|
if not self._fan_data['hot_swappable']:
|
||||||
|
return True
|
||||||
|
|
||||||
|
status = 0
|
||||||
|
try:
|
||||||
|
with open(self._presence_path, 'r') as presence_status:
|
||||||
|
status = int(presence_status.read())
|
||||||
|
except (ValueError, IOError) as e:
|
||||||
|
status = 0
|
||||||
|
|
||||||
|
return status == 1
|
||||||
|
|
||||||
|
def get_direction(self):
|
||||||
|
if not self._fan_data['support_fan_direction'] or not self.get_presence():
|
||||||
|
return FanBase.FAN_DIRECTION_NOT_APPLICABLE
|
||||||
|
|
||||||
|
try:
|
||||||
|
from .fan import FAN_DIR
|
||||||
|
with open(FAN_DIR, 'r') as fan_dir:
|
||||||
|
fan_dir_bits = int(fan_dir.read())
|
||||||
|
fan_mask = 1 << self._index - 1
|
||||||
|
if fan_dir_bits & fan_mask:
|
||||||
|
return FanBase.FAN_DIRECTION_INTAKE
|
||||||
|
else:
|
||||||
|
return FanBase.FAN_DIRECTION_EXHAUST
|
||||||
|
except (ValueError, IOError) as e:
|
||||||
|
raise RuntimeError("Failed to read fan direction status to {}".format(repr(e)))
|
||||||
|
|
||||||
|
def set_status_led(self, color):
|
||||||
|
"""
|
||||||
|
Sets the state of the fan drawer status LED
|
||||||
|
|
||||||
|
Args:
|
||||||
|
color: A string representing the color with which to set the
|
||||||
|
fan drawer status LED
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if status LED state is set successfully, False if not
|
||||||
|
"""
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_status_led(self):
|
||||||
|
"""
|
||||||
|
Gets the state of the fan drawer LED
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A string, one of the predefined STATUS_LED_COLOR_* strings above
|
||||||
|
"""
|
||||||
|
return self._led.get_status()
|
||||||
|
|
||||||
|
|
||||||
|
class RealDrawer(MellanoxFanDrawer):
|
||||||
|
def __init__(self, index, fan_data):
|
||||||
|
super(RealDrawer, self).__init__(index, fan_data)
|
||||||
|
self._name = 'drawer{}'.format(self._index)
|
||||||
|
self._led = SharedLed(FanLed(self._index))
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualDrawer(MellanoxFanDrawer):
|
||||||
|
def __init__(self, index, fan_data):
|
||||||
|
super(VirtualDrawer, self).__init__(index, fan_data)
|
||||||
|
self._led = SharedLed(FanLed(None))
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
return 'N/A'
|
201
platform/mellanox/mlnx-platform-api/sonic_platform/led.py
Normal file
201
platform/mellanox/mlnx-platform-api/sonic_platform/led.py
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
class Led(object):
|
||||||
|
STATUS_LED_COLOR_GREEN = 'green'
|
||||||
|
STATUS_LED_COLOR_RED = 'red'
|
||||||
|
STATUS_LED_COLOR_ORANGE = 'orange'
|
||||||
|
STATUS_LED_COLOR_OFF = 'off'
|
||||||
|
|
||||||
|
LED_ON = '1'
|
||||||
|
LED_OFF = '0'
|
||||||
|
|
||||||
|
LED_PATH = "/var/run/hw-management/led/"
|
||||||
|
|
||||||
|
def set_status(self, color):
|
||||||
|
led_cap_list = self.get_capability()
|
||||||
|
if led_cap_list is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
status = False
|
||||||
|
try:
|
||||||
|
if color == Led.STATUS_LED_COLOR_GREEN:
|
||||||
|
with open(self.get_green_led_path(), 'w') as led:
|
||||||
|
led.write(Led.LED_ON)
|
||||||
|
status = True
|
||||||
|
elif color == Led.STATUS_LED_COLOR_RED:
|
||||||
|
# Some led don't support red led but support orange led, in this case we set led to orange
|
||||||
|
if Led.STATUS_LED_COLOR_RED in led_cap_list:
|
||||||
|
led_path = self.get_red_led_path()
|
||||||
|
elif Led.STATUS_LED_COLOR_ORANGE in led_cap_list:
|
||||||
|
led_path = self.get_orange_led_path()
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
with open(led_path, 'w') as led:
|
||||||
|
led.write(Led.LED_ON)
|
||||||
|
status = True
|
||||||
|
elif color == Led.STATUS_LED_COLOR_OFF:
|
||||||
|
if Led.STATUS_LED_COLOR_GREEN in led_cap_list:
|
||||||
|
with open(self.get_green_led_path(), 'w') as led:
|
||||||
|
led.write(Led.LED_OFF)
|
||||||
|
if Led.STATUS_LED_COLOR_RED in led_cap_list:
|
||||||
|
with open(self.get_red_led_path(), 'w') as led:
|
||||||
|
led.write(Led.LED_OFF)
|
||||||
|
if Led.STATUS_LED_COLOR_ORANGE in led_cap_list:
|
||||||
|
with open(self.get_orange_led_path(), 'w') as led:
|
||||||
|
led.write(Led.LED_OFF)
|
||||||
|
|
||||||
|
status = True
|
||||||
|
else:
|
||||||
|
status = False
|
||||||
|
except (ValueError, IOError):
|
||||||
|
status = False
|
||||||
|
|
||||||
|
return status
|
||||||
|
|
||||||
|
def get_status(self):
|
||||||
|
led_cap_list = self.get_capability()
|
||||||
|
if led_cap_list is None:
|
||||||
|
return Led.STATUS_LED_COLOR_OFF
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(self.get_green_led_path(), 'r') as led:
|
||||||
|
if Led.LED_OFF != led.read().rstrip('\n'):
|
||||||
|
return Led.STATUS_LED_COLOR_GREEN
|
||||||
|
|
||||||
|
if Led.STATUS_LED_COLOR_RED in led_cap_list:
|
||||||
|
with open(self.get_red_led_path(), 'r') as led:
|
||||||
|
if Led.LED_OFF != led.read().rstrip('\n'):
|
||||||
|
return Led.STATUS_LED_COLOR_RED
|
||||||
|
if Led.STATUS_LED_COLOR_ORANGE in led_cap_list:
|
||||||
|
with open(self.get_orange_led_path(), 'r') as led:
|
||||||
|
if Led.LED_OFF != led.read().rstrip('\n'):
|
||||||
|
return Led.STATUS_LED_COLOR_RED
|
||||||
|
except (ValueError, IOError) as e:
|
||||||
|
raise RuntimeError("Failed to read led status due to {}".format(repr(e)))
|
||||||
|
|
||||||
|
return Led.STATUS_LED_COLOR_OFF
|
||||||
|
|
||||||
|
def get_capability(self):
|
||||||
|
cap_list = None
|
||||||
|
try:
|
||||||
|
with open(self.get_led_cap_path(), 'r') as led_cap:
|
||||||
|
caps = led_cap.read()
|
||||||
|
cap_list = caps.split()
|
||||||
|
except (ValueError, IOError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
return cap_list
|
||||||
|
|
||||||
|
def get_green_led_path(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_red_led_path(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_orange_led_path(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_led_cap_path(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class FanLed(Led):
|
||||||
|
LED_PATH = "/var/run/hw-management/led/"
|
||||||
|
|
||||||
|
def __init__(self, index):
|
||||||
|
if index is not None:
|
||||||
|
self._green_led_path = os.path.join(Led.LED_PATH, "led_fan{}_green".format(index))
|
||||||
|
self._red_led_path = os.path.join(Led.LED_PATH, "led_fan{}_red".format(index))
|
||||||
|
self._orange_led_path = os.path.join(Led.LED_PATH, "led_fan{}_orange".format(index))
|
||||||
|
self._led_cap_path = os.path.join(Led.LED_PATH, "led_fan{}_capability".format(index))
|
||||||
|
else:
|
||||||
|
self._green_led_path = os.path.join(Led.LED_PATH, "led_fan_green")
|
||||||
|
self._red_led_path = os.path.join(Led.LED_PATH, "led_fan_red")
|
||||||
|
self._orange_led_path = os.path.join(Led.LED_PATH, "led_fan_orange")
|
||||||
|
self._led_cap_path = os.path.join(Led.LED_PATH, "led_fan_capability")
|
||||||
|
|
||||||
|
self.set_status(Led.STATUS_LED_COLOR_GREEN)
|
||||||
|
|
||||||
|
def get_green_led_path(self):
|
||||||
|
return self._green_led_path
|
||||||
|
|
||||||
|
def get_red_led_path(self):
|
||||||
|
return self._red_led_path
|
||||||
|
|
||||||
|
def get_orange_led_path(self):
|
||||||
|
return self._orange_led_path
|
||||||
|
|
||||||
|
def get_led_cap_path(self):
|
||||||
|
return self._led_cap_path
|
||||||
|
|
||||||
|
|
||||||
|
class PsuLed(Led):
|
||||||
|
def __init__(self, index):
|
||||||
|
if index is not None:
|
||||||
|
self._green_led_path = os.path.join(Led.LED_PATH, "led_psu{}_green".format(index))
|
||||||
|
self._red_led_path = os.path.join(Led.LED_PATH, "led_psu{}_red".format(index))
|
||||||
|
self._orange_led_path = os.path.join(Led.LED_PATH, "led_psu{}_orange".format(index))
|
||||||
|
self._led_cap_path = os.path.join(Led.LED_PATH, "led_psu{}_capability".format(index))
|
||||||
|
else:
|
||||||
|
self._green_led_path = os.path.join(Led.LED_PATH, "led_psu_green")
|
||||||
|
self._red_led_path = os.path.join(Led.LED_PATH, "led_psu_red")
|
||||||
|
self._orange_led_path = os.path.join(Led.LED_PATH, "led_psu_orange")
|
||||||
|
self._led_cap_path = os.path.join(Led.LED_PATH, "led_psu_capability")
|
||||||
|
|
||||||
|
self.set_status(Led.STATUS_LED_COLOR_GREEN)
|
||||||
|
|
||||||
|
def get_green_led_path(self):
|
||||||
|
return self._green_led_path
|
||||||
|
|
||||||
|
def get_red_led_path(self):
|
||||||
|
return self._red_led_path
|
||||||
|
|
||||||
|
def get_orange_led_path(self):
|
||||||
|
return self._orange_led_path
|
||||||
|
|
||||||
|
def get_led_cap_path(self):
|
||||||
|
return self._led_cap_path
|
||||||
|
|
||||||
|
|
||||||
|
class SharedLed(object):
|
||||||
|
LED_PRIORITY = {
|
||||||
|
Led.STATUS_LED_COLOR_RED: 0,
|
||||||
|
Led.STATUS_LED_COLOR_GREEN: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, led):
|
||||||
|
self._led = led
|
||||||
|
self._virtual_leds = []
|
||||||
|
|
||||||
|
def add_virtual_leds(self, led):
|
||||||
|
self._virtual_leds.append(led)
|
||||||
|
|
||||||
|
def update_status_led(self):
|
||||||
|
target_color = Led.STATUS_LED_COLOR_GREEN
|
||||||
|
for virtual_led in self._virtual_leds:
|
||||||
|
if SharedLed.LED_PRIORITY[virtual_led.get_led_color()] < SharedLed.LED_PRIORITY[target_color]:
|
||||||
|
target_color = virtual_led.get_led_color()
|
||||||
|
|
||||||
|
return self._led.set_status(target_color)
|
||||||
|
|
||||||
|
def get_status(self):
|
||||||
|
return self._led.get_status()
|
||||||
|
|
||||||
|
|
||||||
|
class ComponentFaultyIndicator(object):
|
||||||
|
def __init__(self, shared_led):
|
||||||
|
self._color = Led.STATUS_LED_COLOR_GREEN
|
||||||
|
self._shared_led = shared_led
|
||||||
|
self._shared_led.add_virtual_leds(self)
|
||||||
|
|
||||||
|
def set_status(self, color):
|
||||||
|
self._color = color
|
||||||
|
return self._shared_led.update_status_led()
|
||||||
|
|
||||||
|
def get_led_color(self):
|
||||||
|
return self._color
|
||||||
|
|
||||||
|
def get_status(self):
|
||||||
|
return self._shared_led.get_status()
|
@ -13,11 +13,11 @@ try:
|
|||||||
from sonic_platform_base.psu_base import PsuBase
|
from sonic_platform_base.psu_base import PsuBase
|
||||||
from sonic_daemon_base.daemon_base import Logger
|
from sonic_daemon_base.daemon_base import Logger
|
||||||
from sonic_platform.fan import Fan
|
from sonic_platform.fan import Fan
|
||||||
|
from .led import PsuLed, SharedLed, ComponentFaultyIndicator
|
||||||
|
from .device_data import DEVICE_DATA
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
raise ImportError (str(e) + "- required module not found")
|
raise ImportError (str(e) + "- required module not found")
|
||||||
|
|
||||||
LED_ON = '1'
|
|
||||||
LED_OFF = '0'
|
|
||||||
|
|
||||||
# Global logger class instance
|
# Global logger class instance
|
||||||
logger = Logger()
|
logger = Logger()
|
||||||
@ -28,16 +28,11 @@ PSU_CURRENT = "current"
|
|||||||
PSU_VOLTAGE = "voltage"
|
PSU_VOLTAGE = "voltage"
|
||||||
PSU_POWER = "power"
|
PSU_POWER = "power"
|
||||||
|
|
||||||
LED_PATH = "/var/run/hw-management/led/"
|
# in most platforms the file psuX_curr, psuX_volt and psuX_power contain current, voltage and power data respectively.
|
||||||
|
|
||||||
# SKUs with unplugable PSUs:
|
|
||||||
# 1. don't have psuX_status and should be treated as always present
|
|
||||||
# 2. don't have voltage, current and power values
|
|
||||||
hwsku_dict_with_unplugable_psu = ['ACS-MSN2010', 'ACS-MSN2100']
|
|
||||||
|
|
||||||
# in most SKUs the file psuX_curr, psuX_volt and psuX_power contain current, voltage and power data respectively.
|
|
||||||
# but there are exceptions which will be handled by the following dictionary
|
# but there are exceptions which will be handled by the following dictionary
|
||||||
hwsku_dict_psu = {'ACS-MSN3700': 1, 'ACS-MSN3700C': 1, 'ACS-MSN3800': 1, 'Mellanox-SN3800-D112C8': 1, 'ACS-MSN4700': 1, 'ACS-MSN3420': 1, 'ACS-MSN4600C': 1}
|
|
||||||
|
platform_dict_psu = {'x86_64-mlnx_msn3700-r0': 1, 'x86_64-mlnx_msn3700c-r0': 1, 'x86_64-mlnx_msn3800-r0': 1, 'x86_64-mlnx_msn4700-r0': 1}
|
||||||
|
|
||||||
psu_profile_list = [
|
psu_profile_list = [
|
||||||
# default filename convention
|
# default filename convention
|
||||||
{
|
{
|
||||||
@ -56,9 +51,9 @@ psu_profile_list = [
|
|||||||
class Psu(PsuBase):
|
class Psu(PsuBase):
|
||||||
"""Platform-specific Psu class"""
|
"""Platform-specific Psu class"""
|
||||||
|
|
||||||
STATUS_LED_COLOR_ORANGE = "orange"
|
shared_led = None
|
||||||
|
|
||||||
def __init__(self, psu_index, sku):
|
def __init__(self, psu_index, platform):
|
||||||
global psu_list
|
global psu_list
|
||||||
PsuBase.__init__(self)
|
PsuBase.__init__(self)
|
||||||
# PSU is 1-based on Mellanox platform
|
# PSU is 1-based on Mellanox platform
|
||||||
@ -66,17 +61,19 @@ class Psu(PsuBase):
|
|||||||
psu_list.append(self.index)
|
psu_list.append(self.index)
|
||||||
self.psu_path = "/var/run/hw-management/"
|
self.psu_path = "/var/run/hw-management/"
|
||||||
psu_oper_status = "thermal/psu{}_pwr_status".format(self.index)
|
psu_oper_status = "thermal/psu{}_pwr_status".format(self.index)
|
||||||
#psu_oper_status should always be present for all SKUs
|
#psu_oper_status should always be present for all platforms
|
||||||
self.psu_oper_status = os.path.join(self.psu_path, psu_oper_status)
|
self.psu_oper_status = os.path.join(self.psu_path, psu_oper_status)
|
||||||
self._name = "PSU{}".format(psu_index + 1)
|
self._name = "PSU{}".format(psu_index + 1)
|
||||||
|
|
||||||
if sku in hwsku_dict_psu:
|
if platform in platform_dict_psu:
|
||||||
filemap = psu_profile_list[hwsku_dict_psu[sku]]
|
filemap = psu_profile_list[platform_dict_psu[platform]]
|
||||||
else:
|
else:
|
||||||
filemap = psu_profile_list[0]
|
filemap = psu_profile_list[0]
|
||||||
|
|
||||||
if sku in hwsku_dict_with_unplugable_psu:
|
self.psu_data = DEVICE_DATA[platform]['psus']
|
||||||
self.always_presence = True
|
|
||||||
|
if not self.psu_data['hot_swappable']:
|
||||||
|
self.always_present = True
|
||||||
self.psu_voltage = None
|
self.psu_voltage = None
|
||||||
self.psu_current = None
|
self.psu_current = None
|
||||||
self.psu_power = None
|
self.psu_power = None
|
||||||
@ -84,7 +81,7 @@ class Psu(PsuBase):
|
|||||||
self.psu_temp = None
|
self.psu_temp = None
|
||||||
self.psu_temp_threshold = None
|
self.psu_temp_threshold = None
|
||||||
else:
|
else:
|
||||||
self.always_presence = False
|
self.always_present = False
|
||||||
psu_voltage = filemap[PSU_VOLTAGE].format(self.index)
|
psu_voltage = filemap[PSU_VOLTAGE].format(self.index)
|
||||||
psu_voltage = os.path.join(self.psu_path, psu_voltage)
|
psu_voltage = os.path.join(self.psu_path, psu_voltage)
|
||||||
self.psu_voltage = psu_voltage
|
self.psu_voltage = psu_voltage
|
||||||
@ -105,14 +102,14 @@ class Psu(PsuBase):
|
|||||||
self.psu_temp_threshold = os.path.join(self.psu_path, 'thermal/psu{}_temp_max'.format(self.index))
|
self.psu_temp_threshold = os.path.join(self.psu_path, 'thermal/psu{}_temp_max'.format(self.index))
|
||||||
|
|
||||||
# unplugable PSU has no FAN
|
# unplugable PSU has no FAN
|
||||||
if sku not in hwsku_dict_with_unplugable_psu:
|
if self.psu_data['hot_swappable']:
|
||||||
fan = Fan(False, psu_index, psu_index, True)
|
fan = Fan(psu_index, None, True)
|
||||||
self._fan_list.append(fan)
|
self._fan_list.append(fan)
|
||||||
|
|
||||||
self.psu_green_led_path = "led_psu_green"
|
if self.psu_data['led_num'] == 1:
|
||||||
self.psu_red_led_path = "led_psu_red"
|
self.led = ComponentFaultyIndicator(Psu.get_shared_led())
|
||||||
self.psu_orange_led_path = "led_psu_orange"
|
else: # 2010/2100
|
||||||
self.psu_led_cap_path = "led_psu_capability"
|
self.led = PsuLed(self.index)
|
||||||
|
|
||||||
|
|
||||||
def get_name(self):
|
def get_name(self):
|
||||||
@ -151,8 +148,8 @@ class Psu(PsuBase):
|
|||||||
Returns:
|
Returns:
|
||||||
bool: True if PSU is present, False if not
|
bool: True if PSU is present, False if not
|
||||||
"""
|
"""
|
||||||
if self.always_presence:
|
if self.always_present:
|
||||||
return self.always_presence
|
return self.always_present
|
||||||
else:
|
else:
|
||||||
status = self._read_generic_file(self.psu_presence, 0)
|
status = self._read_generic_file(self.psu_presence, 0)
|
||||||
return status == 1
|
return status == 1
|
||||||
@ -199,19 +196,6 @@ class Psu(PsuBase):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _get_led_capability(self):
|
|
||||||
cap_list = None
|
|
||||||
try:
|
|
||||||
with open(os.path.join(LED_PATH, self.psu_led_cap_path), 'r') as psu_led_cap:
|
|
||||||
caps = psu_led_cap.read()
|
|
||||||
cap_list = caps.split()
|
|
||||||
except (ValueError, IOError):
|
|
||||||
status = 0
|
|
||||||
|
|
||||||
return cap_list
|
|
||||||
|
|
||||||
|
|
||||||
def set_status_led(self, color):
|
def set_status_led(self, color):
|
||||||
"""
|
"""
|
||||||
Sets the state of the PSU status LED
|
Sets the state of the PSU status LED
|
||||||
@ -226,45 +210,7 @@ class Psu(PsuBase):
|
|||||||
Notes:
|
Notes:
|
||||||
Only one led for all PSUs.
|
Only one led for all PSUs.
|
||||||
"""
|
"""
|
||||||
led_cap_list = self._get_led_capability()
|
return self.led.set_status(color)
|
||||||
if led_cap_list is None:
|
|
||||||
return False
|
|
||||||
|
|
||||||
status = False
|
|
||||||
try:
|
|
||||||
if color == self.STATUS_LED_COLOR_GREEN:
|
|
||||||
with open(os.path.join(LED_PATH, self.psu_green_led_path), 'w') as psu_led:
|
|
||||||
psu_led.write(LED_ON)
|
|
||||||
status = True
|
|
||||||
elif color == self.STATUS_LED_COLOR_RED:
|
|
||||||
# Some fan don't support red led but support orange led, in this case we set led to orange
|
|
||||||
if self.STATUS_LED_COLOR_RED in led_cap_list:
|
|
||||||
led_path = os.path.join(LED_PATH, self.psu_red_led_path)
|
|
||||||
elif self.STATUS_LED_COLOR_ORANGE in led_cap_list:
|
|
||||||
led_path = os.path.join(LED_PATH, self.psu_orange_led_path)
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
with open(led_path, 'w') as psu_led:
|
|
||||||
psu_led.write(LED_ON)
|
|
||||||
status = True
|
|
||||||
elif color == self.STATUS_LED_COLOR_OFF:
|
|
||||||
if self.STATUS_LED_COLOR_GREEN in led_cap_list:
|
|
||||||
with open(os.path.join(LED_PATH, self.psu_green_led_path), 'w') as psu_led:
|
|
||||||
psu_led.write(str(LED_OFF))
|
|
||||||
if self.STATUS_LED_COLOR_RED in led_cap_list:
|
|
||||||
with open(os.path.join(LED_PATH, self.psu_red_led_path), 'w') as psu_led:
|
|
||||||
psu_led.write(str(LED_OFF))
|
|
||||||
if self.STATUS_LED_COLOR_ORANGE in led_cap_list:
|
|
||||||
with open(os.path.join(LED_PATH, self.psu_orange_led_path), 'w') as psu_led:
|
|
||||||
psu_led.write(str(LED_OFF))
|
|
||||||
|
|
||||||
status = True
|
|
||||||
else:
|
|
||||||
status = False
|
|
||||||
except (ValueError, IOError):
|
|
||||||
status = False
|
|
||||||
|
|
||||||
return status
|
|
||||||
|
|
||||||
|
|
||||||
def get_status_led(self):
|
def get_status_led(self):
|
||||||
@ -274,26 +220,10 @@ class Psu(PsuBase):
|
|||||||
Returns:
|
Returns:
|
||||||
A string, one of the predefined STATUS_LED_COLOR_* strings above
|
A string, one of the predefined STATUS_LED_COLOR_* strings above
|
||||||
"""
|
"""
|
||||||
led_cap_list = self._get_led_capability()
|
if self.psu_data['led_num'] == 1:
|
||||||
if led_cap_list is None:
|
return Psu.get_shared_led().get_status()
|
||||||
return self.STATUS_LED_COLOR_OFF
|
else:
|
||||||
|
return self.led.get_status()
|
||||||
try:
|
|
||||||
with open(os.path.join(LED_PATH, self.psu_green_led_path), 'r') as psu_led:
|
|
||||||
if LED_OFF != psu_led.read().rstrip('\n'):
|
|
||||||
return self.STATUS_LED_COLOR_GREEN
|
|
||||||
if self.STATUS_LED_COLOR_RED in led_cap_list:
|
|
||||||
with open(os.path.join(LED_PATH, self.psu_red_led_path), 'r') as psu_led:
|
|
||||||
if LED_OFF != psu_led.read().rstrip('\n'):
|
|
||||||
return self.STATUS_LED_COLOR_RED
|
|
||||||
if self.STATUS_LED_COLOR_ORANGE in led_cap_list:
|
|
||||||
with open(os.path.join(LED_PATH, self.psu_orange_led_path), 'r') as psu_led:
|
|
||||||
if LED_OFF != psu_led.read().rstrip('\n'):
|
|
||||||
return self.STATUS_LED_COLOR_RED
|
|
||||||
except (ValueError, IOError) as e:
|
|
||||||
raise RuntimeError("Failed to read led status for psu due to {}".format(repr(e)))
|
|
||||||
|
|
||||||
return self.STATUS_LED_COLOR_OFF
|
|
||||||
|
|
||||||
|
|
||||||
def get_power_available_status(self):
|
def get_power_available_status(self):
|
||||||
@ -312,6 +242,12 @@ class Psu(PsuBase):
|
|||||||
else:
|
else:
|
||||||
return True, ""
|
return True, ""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_shared_led(cls):
|
||||||
|
if not cls.shared_led:
|
||||||
|
cls.shared_led = SharedLed(PsuLed(None))
|
||||||
|
return cls.shared_led
|
||||||
|
|
||||||
def get_temperature(self):
|
def get_temperature(self):
|
||||||
"""
|
"""
|
||||||
Retrieves current temperature reading from PSU
|
Retrieves current temperature reading from PSU
|
||||||
@ -367,4 +303,3 @@ class Psu(PsuBase):
|
|||||||
"""
|
"""
|
||||||
# hw-management doesn't expose those sysfs for now
|
# hw-management doesn't expose those sysfs for now
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ thermal_api_names = [
|
|||||||
THERMAL_API_GET_HIGH_THRESHOLD
|
THERMAL_API_GET_HIGH_THRESHOLD
|
||||||
]
|
]
|
||||||
|
|
||||||
hwsku_dict_thermal = {'ACS-MSN2700': 0, 'LS-SN2700':0, 'ACS-MSN2740': 3, 'ACS-MSN2100': 1, 'ACS-MSN2410': 2, 'ACS-MSN2010': 4, 'ACS-MSN3700': 5, 'ACS-MSN3700C': 6, 'Mellanox-SN2700': 0, 'Mellanox-SN2700-D48C8': 0, 'ACS-MSN3800': 7, 'Mellanox-SN3800-D112C8': 7, 'ACS-MSN4700': 8, 'ACS-MSN3420': 9, 'ACS-MSN4600C': 9}
|
hwsku_dict_thermal = {'ACS-MSN2700': 0, 'LS-SN2700':0, 'ACS-MSN2740': 3, 'ACS-MSN2100': 1, 'ACS-MSN2410': 2, 'ACS-MSN2010': 4, 'ACS-MSN3700': 5, 'ACS-MSN3700C': 6, 'Mellanox-SN2700': 0, 'Mellanox-SN2700-D48C8': 0, 'ACS-MSN3800': 7, 'Mellanox-SN3800-D112C8': 7, 'ACS-MSN4700': 8, 'ACS-MSN3420': 9, 'ACS-MSN4600C': 10}
|
||||||
thermal_profile_list = [
|
thermal_profile_list = [
|
||||||
# 2700
|
# 2700
|
||||||
{
|
{
|
||||||
@ -267,7 +267,7 @@ thermal_profile_list = [
|
|||||||
},
|
},
|
||||||
# 3420
|
# 3420
|
||||||
{
|
{
|
||||||
THERMAL_DEV_CATEGORY_CPU_CORE:(0, 4),
|
THERMAL_DEV_CATEGORY_CPU_CORE:(0, 2),
|
||||||
THERMAL_DEV_CATEGORY_MODULE:(1, 60),
|
THERMAL_DEV_CATEGORY_MODULE:(1, 60),
|
||||||
THERMAL_DEV_CATEGORY_PSU:(1, 2),
|
THERMAL_DEV_CATEGORY_PSU:(1, 2),
|
||||||
THERMAL_DEV_CATEGORY_CPU_PACK:(0,1),
|
THERMAL_DEV_CATEGORY_CPU_PACK:(0,1),
|
||||||
|
@ -2,6 +2,7 @@ class MockFan:
|
|||||||
speed = 60
|
speed = 60
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.presence = True
|
self.presence = True
|
||||||
|
self.name = None
|
||||||
self.status = True
|
self.status = True
|
||||||
|
|
||||||
def get_presence(self):
|
def get_presence(self):
|
||||||
@ -16,6 +17,9 @@ class MockFan:
|
|||||||
def get_target_speed(self):
|
def get_target_speed(self):
|
||||||
return MockFan.speed
|
return MockFan.speed
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
class MockPsu:
|
class MockPsu:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -1,17 +1,57 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import pytest
|
||||||
from mock import MagicMock
|
from mock import MagicMock
|
||||||
|
from .mock_platform import MockFan
|
||||||
|
|
||||||
test_path = os.path.dirname(os.path.abspath(__file__))
|
test_path = os.path.dirname(os.path.abspath(__file__))
|
||||||
modules_path = os.path.dirname(test_path)
|
modules_path = os.path.dirname(test_path)
|
||||||
sys.path.insert(0, modules_path)
|
sys.path.insert(0, modules_path)
|
||||||
|
|
||||||
from sonic_platform.fan import Fan
|
from sonic_platform.fan import Fan
|
||||||
|
from sonic_platform.led import FanLed
|
||||||
|
from sonic_platform.fan_drawer import RealDrawer
|
||||||
|
from sonic_platform.device_data import DEVICE_DATA
|
||||||
|
|
||||||
|
|
||||||
def test_get_absence_fan_direction():
|
def test_get_absence_fan_direction():
|
||||||
fan = Fan(True, 0, 0)
|
fan_drawer = RealDrawer(0, DEVICE_DATA['x86_64-mlnx_msn2700-r0']['fans'])
|
||||||
fan.get_presence = MagicMock(return_value=False)
|
fan = Fan(0, fan_drawer)
|
||||||
assert fan.fan_dir is not None
|
fan_drawer.get_presence = MagicMock(return_value=False)
|
||||||
|
|
||||||
assert not fan.is_psu_fan
|
assert not fan.is_psu_fan
|
||||||
assert fan.get_direction() == Fan.FAN_DIRECTION_NOT_APPLICABLE
|
assert fan.get_direction() == Fan.FAN_DIRECTION_NOT_APPLICABLE
|
||||||
|
|
||||||
|
|
||||||
|
def test_fan_drawer_set_status_led():
|
||||||
|
fan_drawer = RealDrawer(0, DEVICE_DATA['x86_64-mlnx_msn2700-r0']['fans'])
|
||||||
|
with pytest.raises(Exception):
|
||||||
|
fan_drawer.set_status_led(None, 'Invalid color')
|
||||||
|
|
||||||
|
with pytest.raises(Exception):
|
||||||
|
fan_drawer.set_status_led(None, Fan.STATUS_LED_COLOR_RED)
|
||||||
|
|
||||||
|
fan1 = Fan(0, fan_drawer)
|
||||||
|
fan2 = Fan(1, fan_drawer)
|
||||||
|
fan_list = fan_drawer.get_all_fans()
|
||||||
|
fan_list.append(fan1)
|
||||||
|
fan_list.append(fan2)
|
||||||
|
|
||||||
|
FanLed.set_status = MagicMock()
|
||||||
|
|
||||||
|
fan1.set_status_led(Fan.STATUS_LED_COLOR_RED)
|
||||||
|
fan_drawer.set_status_led(Fan.STATUS_LED_COLOR_RED)
|
||||||
|
FanLed.set_status.assert_called_with(Fan.STATUS_LED_COLOR_RED)
|
||||||
|
|
||||||
|
fan2.set_status_led(Fan.STATUS_LED_COLOR_GREEN)
|
||||||
|
fan_drawer.set_status_led(Fan.STATUS_LED_COLOR_GREEN)
|
||||||
|
FanLed.set_status.assert_called_with(Fan.STATUS_LED_COLOR_RED)
|
||||||
|
|
||||||
|
fan1.set_status_led(Fan.STATUS_LED_COLOR_GREEN)
|
||||||
|
fan_drawer.set_status_led(Fan.STATUS_LED_COLOR_GREEN)
|
||||||
|
FanLed.set_status.assert_called_with(Fan.STATUS_LED_COLOR_GREEN)
|
||||||
|
|
||||||
|
fan1.set_status_led(Fan.STATUS_LED_COLOR_RED)
|
||||||
|
fan_drawer.set_status_led(Fan.STATUS_LED_COLOR_RED)
|
||||||
|
FanLed.set_status.assert_called_with(Fan.STATUS_LED_COLOR_RED)
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 28c39c55666dcaef10f62492906c1399eec4ccba
|
Subproject commit 75698a8dd8f5a9ea2a0e72c5f7e2b3196d22571a
|
Loading…
Reference in New Issue
Block a user