[Mellanox] add PSU fan direction support (#14508)
- Why I did it Add PSU fan direction support - How I did it Implement fan.get_direction for PSU fan - How to verify it Manual test Unit test
This commit is contained in:
parent
602b945f76
commit
7962a5c0fa
@ -31,6 +31,7 @@ try:
|
|||||||
from .led import ComponentFaultyIndicator
|
from .led import ComponentFaultyIndicator
|
||||||
from . import utils
|
from . import utils
|
||||||
from .thermal import Thermal
|
from .thermal import Thermal
|
||||||
|
from .fan_drawer import VirtualDrawer
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
raise ImportError (str(e) + "- required module not found")
|
raise ImportError (str(e) + "- required module not found")
|
||||||
|
|
||||||
@ -45,7 +46,10 @@ CONFIG_PATH = "/var/run/hw-management/config"
|
|||||||
FAN_DIR = "/var/run/hw-management/thermal/fan{}_dir"
|
FAN_DIR = "/var/run/hw-management/thermal/fan{}_dir"
|
||||||
FAN_DIR_VALUE_EXHAUST = 0
|
FAN_DIR_VALUE_EXHAUST = 0
|
||||||
FAN_DIR_VALUE_INTAKE = 1
|
FAN_DIR_VALUE_INTAKE = 1
|
||||||
|
FAN_DIR_MAPPING = {
|
||||||
|
FAN_DIR_VALUE_EXHAUST: FanBase.FAN_DIRECTION_EXHAUST,
|
||||||
|
FAN_DIR_VALUE_INTAKE: FanBase.FAN_DIRECTION_INTAKE,
|
||||||
|
}
|
||||||
|
|
||||||
class MlnxFan(FanBase):
|
class MlnxFan(FanBase):
|
||||||
def __init__(self, fan_index, position):
|
def __init__(self, fan_index, position):
|
||||||
@ -125,6 +129,20 @@ class MlnxFan(FanBase):
|
|||||||
"""
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_fan_direction(cls, dir_path):
|
||||||
|
try:
|
||||||
|
fan_dir = utils.read_int_from_file(dir_path, raise_exception=True)
|
||||||
|
ret = FAN_DIR_MAPPING.get(fan_dir)
|
||||||
|
if ret is None:
|
||||||
|
logger.log_error(f"Got wrong value {fan_dir} for fan direction {dir_path}")
|
||||||
|
return FanBase.FAN_DIRECTION_NOT_APPLICABLE
|
||||||
|
else:
|
||||||
|
return ret
|
||||||
|
except (ValueError, IOError) as e:
|
||||||
|
logger.log_error(f"Failed to read fan direction from {dir_path} - {e}")
|
||||||
|
return FanBase.FAN_DIRECTION_NOT_APPLICABLE
|
||||||
|
|
||||||
|
|
||||||
class PsuFan(MlnxFan):
|
class PsuFan(MlnxFan):
|
||||||
# PSU fan speed vector
|
# PSU fan speed vector
|
||||||
@ -145,6 +163,7 @@ class PsuFan(MlnxFan):
|
|||||||
self.psu_i2c_bus_path = os.path.join(CONFIG_PATH, 'psu{0}_i2c_bus'.format(self.index))
|
self.psu_i2c_bus_path = os.path.join(CONFIG_PATH, 'psu{0}_i2c_bus'.format(self.index))
|
||||||
self.psu_i2c_addr_path = os.path.join(CONFIG_PATH, 'psu{0}_i2c_addr'.format(self.index))
|
self.psu_i2c_addr_path = os.path.join(CONFIG_PATH, 'psu{0}_i2c_addr'.format(self.index))
|
||||||
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.psu_fan_dir_path = os.path.join(FAN_PATH, "psu{}_fan_dir".format(self.index))
|
||||||
|
|
||||||
def get_direction(self):
|
def get_direction(self):
|
||||||
"""
|
"""
|
||||||
@ -165,8 +184,11 @@ class PsuFan(MlnxFan):
|
|||||||
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 os.path.exists(self.psu_fan_dir_path) or not self.get_presence():
|
||||||
return self.FAN_DIRECTION_NOT_APPLICABLE
|
return self.FAN_DIRECTION_NOT_APPLICABLE
|
||||||
|
|
||||||
|
return MlnxFan.get_fan_direction(self.psu_fan_dir_path)
|
||||||
|
|
||||||
def get_status(self):
|
def get_status(self):
|
||||||
"""
|
"""
|
||||||
Retrieves the operational status of fan
|
Retrieves the operational status of fan
|
||||||
@ -263,7 +285,10 @@ class Fan(MlnxFan):
|
|||||||
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 isinstance(self.fan_drawer, VirtualDrawer):
|
||||||
return self.fan_drawer.get_direction()
|
return self.fan_drawer.get_direction()
|
||||||
|
else:
|
||||||
|
return MlnxFan.get_fan_direction(FAN_DIR.format(self.index))
|
||||||
|
|
||||||
def get_status(self):
|
def get_status(self):
|
||||||
"""
|
"""
|
||||||
|
@ -58,19 +58,8 @@ class MellanoxFanDrawer(FanDrawerBase):
|
|||||||
if not self.get_presence():
|
if not self.get_presence():
|
||||||
return FanBase.FAN_DIRECTION_NOT_APPLICABLE
|
return FanBase.FAN_DIRECTION_NOT_APPLICABLE
|
||||||
|
|
||||||
try:
|
from .fan import FAN_DIR, MlnxFan
|
||||||
from .fan import FAN_DIR, FAN_DIR_VALUE_INTAKE, FAN_DIR_VALUE_EXHAUST
|
return MlnxFan.get_fan_direction(FAN_DIR.format(self._index))
|
||||||
fan_dir = utils.read_int_from_file(FAN_DIR.format(self._index), raise_exception=True)
|
|
||||||
if fan_dir == FAN_DIR_VALUE_INTAKE:
|
|
||||||
return FanBase.FAN_DIRECTION_INTAKE
|
|
||||||
elif fan_dir == FAN_DIR_VALUE_EXHAUST:
|
|
||||||
return FanBase.FAN_DIRECTION_EXHAUST
|
|
||||||
else:
|
|
||||||
logger.log_error("Got wrong value {} for fan direction {}".format(fan_dir, self._index))
|
|
||||||
return FanBase.FAN_DIRECTION_NOT_APPLICABLE
|
|
||||||
except (ValueError, IOError) as e:
|
|
||||||
logger.log_error("Failed to read fan direction status to {}".format(repr(e)))
|
|
||||||
return FanBase.FAN_DIRECTION_NOT_APPLICABLE
|
|
||||||
|
|
||||||
def set_status_led(self, color):
|
def set_status_led(self, color):
|
||||||
"""
|
"""
|
||||||
|
@ -25,7 +25,7 @@ modules_path = os.path.dirname(test_path)
|
|||||||
sys.path.insert(0, modules_path)
|
sys.path.insert(0, modules_path)
|
||||||
|
|
||||||
from sonic_platform import utils
|
from sonic_platform import utils
|
||||||
from sonic_platform.fan import Fan, PsuFan
|
from sonic_platform.fan import Fan, PsuFan, FAN_DIR_VALUE_INTAKE, FAN_DIR_VALUE_EXHAUST
|
||||||
from sonic_platform.fan_drawer import RealDrawer, VirtualDrawer
|
from sonic_platform.fan_drawer import RealDrawer, VirtualDrawer
|
||||||
from sonic_platform.psu import Psu
|
from sonic_platform.psu import Psu
|
||||||
|
|
||||||
@ -107,11 +107,12 @@ class TestFan:
|
|||||||
fan.set_speed(60)
|
fan.set_speed(60)
|
||||||
mock_write_file.assert_called_with(fan.fan_speed_set_path, 153, raise_exception=True)
|
mock_write_file.assert_called_with(fan.fan_speed_set_path, 153, raise_exception=True)
|
||||||
|
|
||||||
|
@patch('sonic_platform.utils.read_int_from_file')
|
||||||
@patch('sonic_platform.thermal.Thermal.get_cooling_level')
|
@patch('sonic_platform.thermal.Thermal.get_cooling_level')
|
||||||
@patch('sonic_platform.psu.Psu.get_presence')
|
@patch('sonic_platform.psu.Psu.get_presence')
|
||||||
@patch('sonic_platform.psu.Psu.get_powergood_status')
|
@patch('sonic_platform.psu.Psu.get_powergood_status')
|
||||||
@patch('os.path.exists')
|
@patch('os.path.exists')
|
||||||
def test_psu_fan_basic(self, mock_path_exists, mock_powergood, mock_presence, mock_cooling_level):
|
def test_psu_fan_basic(self, mock_path_exists, mock_powergood, mock_presence, mock_cooling_level, mock_read_int):
|
||||||
mock_path_exists.return_value = False
|
mock_path_exists.return_value = False
|
||||||
psu = Psu(0)
|
psu = Psu(0)
|
||||||
fan = PsuFan(0, 1, psu)
|
fan = PsuFan(0, 1, psu)
|
||||||
@ -126,6 +127,12 @@ class TestFan:
|
|||||||
assert fan.get_presence() is True
|
assert fan.get_presence() is True
|
||||||
mock_cooling_level.return_value = 7
|
mock_cooling_level.return_value = 7
|
||||||
assert fan.get_target_speed() == 70
|
assert fan.get_target_speed() == 70
|
||||||
|
mock_read_int.return_value = FAN_DIR_VALUE_INTAKE
|
||||||
|
assert fan.get_direction() == Fan.FAN_DIRECTION_INTAKE
|
||||||
|
mock_read_int.return_value = FAN_DIR_VALUE_EXHAUST
|
||||||
|
assert fan.get_direction() == Fan.FAN_DIRECTION_EXHAUST
|
||||||
|
mock_read_int.return_value = -1 # invalid value
|
||||||
|
assert fan.get_direction() == Fan.FAN_DIRECTION_NOT_APPLICABLE
|
||||||
|
|
||||||
def test_psu_fan_set_speed(self):
|
def test_psu_fan_set_speed(self):
|
||||||
psu = Psu(0)
|
psu = Psu(0)
|
||||||
|
Loading…
Reference in New Issue
Block a user