Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Mellanox]support led for fan/psu and fan direction #17

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
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
Expand All @@ -33,6 +34,10 @@

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'
stephenxs marked this conversation as resolved.
Show resolved Hide resolved
CHIP_SPECTRUM1 = '53100'
stephenxs marked this conversation as resolved.
Show resolved Hide resolved

#reboot cause related definitions
REBOOT_CAUSE_ROOT = HWMGMT_SYSTEM_ROOT

Expand Down Expand Up @@ -87,11 +92,21 @@ def initialize_fan(self):
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 is 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) == CHIP_SPECTRUM1:
has_fan_dir = True
else:
has_fan_dir = False

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)


Expand Down
132 changes: 111 additions & 21 deletions platform/mellanox/mlnx-platform-api/sonic_platform/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,28 @@
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 only exist Spectrum 2 switches
stephenxs marked this conversation as resolved.
Show resolved Hide resolved
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

self.is_psu_fan = psu_fan

self.fan_min_speed_path = "fan{}_min".format(self.index)
if not self.is_psu_fan:
self.fan_speed_get_path = "fan{}_speed_get".format(self.index)
Expand All @@ -48,6 +53,45 @@ def __init__(self, fan_index, drawer_index = 1, psu_fan = False):
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):
"""
Expand All @@ -68,6 +112,7 @@ def get_status(self):

return status == 1


def get_presence(self):
"""
Retrieves the presence status of fan
Expand All @@ -89,7 +134,8 @@ def get_presence(self):
status = 0

return status == 1



def _get_min_speed_in_rpm(self):
speed = 0
try:
Expand All @@ -99,7 +145,8 @@ def _get_min_speed_in_rpm(self):
speed = 0

return speed



def _get_max_speed_in_rpm(self):
speed = 0
try:
Expand All @@ -110,6 +157,7 @@ def _get_max_speed_in_rpm(self):

return speed


def get_speed(self):
"""
Retrieves the speed of fan
Expand All @@ -129,6 +177,7 @@ def get_speed(self):

return speed


def get_target_speed(self):
"""
Retrieves the expected speed of fan
Expand All @@ -151,6 +200,7 @@ def get_target_speed(self):

return speed


def set_speed(self, speed):
"""
Set fan speed to expected value
Expand All @@ -176,7 +226,8 @@ def set_speed(self, speed):
status = False

return status



def _get_led_capability(self):
cap_list = None
try:
Expand All @@ -188,6 +239,7 @@ def _get_led_capability(self):

return cap_list


def set_status_led(self, color):
"""
Set led to expected color
Expand All @@ -208,32 +260,70 @@ def set_status_led(self, color):
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':
with open(os.path.join(LED_PATH, self.fan_green_led_path), 'w') as fan_led:
fan_led.write(str(LED_OFF))

with open(os.path.join(LED_PATH, self.fan_red_led_path), 'w') as fan_led:
fan_led.write(str(LED_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
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
Expand Down
Loading