[Mellanox]support led for fan/psu and fan's direction (#3795)
This commit is contained in:
parent
cda61290ac
commit
d5aa0d4382
@ -14,6 +14,7 @@ try:
|
||||
from sonic_daemon_base.daemon_base import Logger
|
||||
from os import listdir
|
||||
from os.path import isfile, join
|
||||
from glob import glob
|
||||
import sys
|
||||
import io
|
||||
import re
|
||||
@ -33,6 +34,10 @@ EEPROM_CACHE_FILE = 'syseeprom_cache'
|
||||
|
||||
HWMGMT_SYSTEM_ROOT = '/var/run/hw-management/system/'
|
||||
|
||||
MST_DEVICE_NAME_PATTERN = '/dev/mst/mt[0-9]*_pciconf0'
|
||||
MST_DEVICE_RE_PATTERN = '/dev/mst/mt([0-9]*)_pciconf0'
|
||||
SPECTRUM1_CHIP_ID = '52100'
|
||||
|
||||
#reboot cause related definitions
|
||||
REBOOT_CAUSE_ROOT = HWMGMT_SYSTEM_ROOT
|
||||
|
||||
@ -87,11 +92,21 @@ class Chassis(ChassisBase):
|
||||
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
|
||||
mst_dev_list = glob(MST_DEVICE_NAME_PATTERN)
|
||||
if not mst_dev_list:
|
||||
raise RuntimeError("Can't get chip type due to {} not found".format(MST_DEVICE_NAME_PATTERN))
|
||||
m = re.search(MST_DEVICE_RE_PATTERN, mst_dev_list[0])
|
||||
if m.group(1) == SPECTRUM1_CHIP_ID:
|
||||
has_fan_dir = False
|
||||
else:
|
||||
has_fan_dir = True
|
||||
|
||||
for index in range(num_of_fan):
|
||||
if multi_rotor_in_drawer:
|
||||
fan = Fan(index, index/2)
|
||||
fan = Fan(has_fan_dir, index, index/2)
|
||||
else:
|
||||
fan = Fan(index, index)
|
||||
fan = Fan(has_fan_dir, index, index)
|
||||
self._fan_list.append(fan)
|
||||
|
||||
|
||||
|
@ -15,17 +15,22 @@ try:
|
||||
except ImportError as e:
|
||||
raise ImportError (str(e) + "- required module not found")
|
||||
|
||||
LED_ON = 1
|
||||
LED_OFF = 0
|
||||
LED_ON = '1'
|
||||
LED_OFF = '0'
|
||||
|
||||
PWM_MAX = 255
|
||||
|
||||
FAN_PATH = "/var/run/hw-management/thermal/"
|
||||
LED_PATH = "/var/run/hw-management/led/"
|
||||
# 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"
|
||||
|
||||
class Fan(FanBase):
|
||||
"""Platform-specific Fan class"""
|
||||
def __init__(self, fan_index, drawer_index = 1, psu_fan = False):
|
||||
|
||||
STATUS_LED_COLOR_ORANGE = "orange"
|
||||
|
||||
def __init__(self, has_fan_dir, fan_index, drawer_index = 1, psu_fan = False):
|
||||
# API index is starting from 0, Mellanox platform index is starting from 1
|
||||
self.index = fan_index + 1
|
||||
self.drawer_index = drawer_index + 1
|
||||
@ -48,6 +53,45 @@ class Fan(FanBase):
|
||||
self.fan_orange_led_path = "led_fan{}_orange".format(self.drawer_index)
|
||||
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):
|
||||
"""
|
||||
Retrieves the fan's direction
|
||||
|
||||
Returns:
|
||||
A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST
|
||||
depending on fan direction
|
||||
|
||||
Notes:
|
||||
What Mellanox calls forward:
|
||||
Air flows from fans side to QSFP side, for example: MSN2700-CS2F
|
||||
which means intake in community
|
||||
What Mellanox calls reverse:
|
||||
Air flow from QSFP side to fans side, for example: MSN2700-CS2R
|
||||
which means exhaust in community
|
||||
According to hw-mgmt:
|
||||
1 stands for forward, in other words intake
|
||||
0 stands for reverse, in other words exhaust
|
||||
"""
|
||||
if not self.fan_dir or self.is_psu_fan:
|
||||
return self.FAN_DIRECTION_NOT_APPLICABLE
|
||||
|
||||
try:
|
||||
with open(os.path.join(self.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 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_status(self):
|
||||
"""
|
||||
@ -68,6 +112,7 @@ class Fan(FanBase):
|
||||
|
||||
return status == 1
|
||||
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence status of fan
|
||||
@ -90,6 +135,7 @@ class Fan(FanBase):
|
||||
|
||||
return status == 1
|
||||
|
||||
|
||||
def _get_min_speed_in_rpm(self):
|
||||
speed = 0
|
||||
try:
|
||||
@ -100,6 +146,7 @@ class Fan(FanBase):
|
||||
|
||||
return speed
|
||||
|
||||
|
||||
def _get_max_speed_in_rpm(self):
|
||||
speed = 0
|
||||
try:
|
||||
@ -110,6 +157,7 @@ class Fan(FanBase):
|
||||
|
||||
return speed
|
||||
|
||||
|
||||
def get_speed(self):
|
||||
"""
|
||||
Retrieves the speed of fan
|
||||
@ -129,6 +177,7 @@ class Fan(FanBase):
|
||||
|
||||
return speed
|
||||
|
||||
|
||||
def get_target_speed(self):
|
||||
"""
|
||||
Retrieves the expected speed of fan
|
||||
@ -151,6 +200,7 @@ class Fan(FanBase):
|
||||
|
||||
return speed
|
||||
|
||||
|
||||
def set_speed(self, speed):
|
||||
"""
|
||||
Set fan speed to expected value
|
||||
@ -177,6 +227,7 @@ class Fan(FanBase):
|
||||
|
||||
return status
|
||||
|
||||
|
||||
def _get_led_capability(self):
|
||||
cap_list = None
|
||||
try:
|
||||
@ -188,6 +239,7 @@ class Fan(FanBase):
|
||||
|
||||
return cap_list
|
||||
|
||||
|
||||
def set_status_led(self, color):
|
||||
"""
|
||||
Set led to expected color
|
||||
@ -208,32 +260,70 @@ class Fan(FanBase):
|
||||
return False
|
||||
status = False
|
||||
try:
|
||||
if color == 'green':
|
||||
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(str(LED_ON))
|
||||
elif color == 'red':
|
||||
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 'red' in led_cap_list:
|
||||
if self.STATUS_LED_COLOR_RED in led_cap_list:
|
||||
led_path = os.path.join(LED_PATH, self.fan_red_led_path)
|
||||
elif 'orange' in led_cap_list:
|
||||
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(str(LED_ON))
|
||||
|
||||
elif color == 'off':
|
||||
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):
|
||||
"""
|
||||
Gets the state of the fan status LED
|
||||
|
||||
Returns:
|
||||
A string, one of the predefined STATUS_LED_COLOR_* strings above
|
||||
"""
|
||||
led_cap_list = self._get_led_capability()
|
||||
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):
|
||||
"""
|
||||
Retrieves the speed tolerance of the fan
|
||||
|
@ -16,6 +16,9 @@ try:
|
||||
except ImportError as e:
|
||||
raise ImportError (str(e) + "- required module not found")
|
||||
|
||||
LED_ON = '1'
|
||||
LED_OFF = '0'
|
||||
|
||||
# Global logger class instance
|
||||
logger = Logger()
|
||||
|
||||
@ -25,6 +28,8 @@ PSU_CURRENT = "current"
|
||||
PSU_VOLTAGE = "voltage"
|
||||
PSU_POWER = "power"
|
||||
|
||||
LED_PATH = "/var/run/hw-management/led/"
|
||||
|
||||
# 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
|
||||
@ -50,6 +55,9 @@ psu_profile_list = [
|
||||
|
||||
class Psu(PsuBase):
|
||||
"""Platform-specific Psu class"""
|
||||
|
||||
STATUS_LED_COLOR_ORANGE = "orange"
|
||||
|
||||
def __init__(self, psu_index, sku):
|
||||
global psu_list
|
||||
PsuBase.__init__(self)
|
||||
@ -90,10 +98,16 @@ class Psu(PsuBase):
|
||||
psu_presence = os.path.join(self.psu_path, psu_presence)
|
||||
self.psu_presence = psu_presence
|
||||
|
||||
fan = Fan(psu_index, psu_index, True)
|
||||
fan = Fan(sku, psu_index, psu_index, True)
|
||||
if fan.get_presence():
|
||||
self._fan = fan
|
||||
|
||||
self.psu_green_led_path = "led_psu_green"
|
||||
self.psu_red_led_path = "led_psu_red"
|
||||
self.psu_orange_led_path = "led_psu_orange"
|
||||
self.psu_led_cap_path = "led_psu_capability"
|
||||
|
||||
|
||||
def _read_generic_file(self, filename, len):
|
||||
"""
|
||||
Read a generic file, returns the contents of the file
|
||||
@ -106,6 +120,7 @@ class Psu(PsuBase):
|
||||
logger.log_info("Fail to read file {} due to {}".format(filename, repr(e)))
|
||||
return result
|
||||
|
||||
|
||||
def get_powergood_status(self):
|
||||
"""
|
||||
Retrieves the operational status of power supply unit (PSU) defined
|
||||
@ -117,6 +132,7 @@ class Psu(PsuBase):
|
||||
|
||||
return status == 1
|
||||
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence status of power supply unit (PSU) defined
|
||||
@ -130,6 +146,7 @@ class Psu(PsuBase):
|
||||
status = self._read_generic_file(self.psu_presence, 0)
|
||||
return status == 1
|
||||
|
||||
|
||||
def get_voltage(self):
|
||||
"""
|
||||
Retrieves current PSU voltage output
|
||||
@ -144,6 +161,7 @@ class Psu(PsuBase):
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def get_current(self):
|
||||
"""
|
||||
Retrieves present electric current supplied by PSU
|
||||
@ -169,3 +187,99 @@ class Psu(PsuBase):
|
||||
return float(power) / 1000000
|
||||
else:
|
||||
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):
|
||||
"""
|
||||
Sets the state of the PSU status LED
|
||||
|
||||
Args:
|
||||
color: A string representing the color with which to set the
|
||||
PSU status LED
|
||||
|
||||
Returns:
|
||||
bool: True if status LED state is set successfully, False if not
|
||||
|
||||
Notes:
|
||||
Only one led for all PSUs.
|
||||
"""
|
||||
led_cap_list = self._get_led_capability()
|
||||
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):
|
||||
"""
|
||||
Gets the state of the PSU status LED
|
||||
|
||||
Returns:
|
||||
A string, one of the predefined STATUS_LED_COLOR_* strings above
|
||||
"""
|
||||
led_cap_list = self._get_led_capability()
|
||||
if led_cap_list is None:
|
||||
return self.STATUS_LED_COLOR_OFF
|
||||
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user