-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Mellanox] Implement new fan platform API (#2747)
- Loading branch information
Showing
7 changed files
with
323 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
70 changes: 70 additions & 0 deletions
70
platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
#!/usr/bin/env python | ||
|
||
############################################################################# | ||
# Mellanox | ||
# | ||
# Module contains an implementation of SONiC Platform Base API and | ||
# provides the Chassis information which are available in the platform | ||
# | ||
############################################################################# | ||
|
||
import sys | ||
|
||
try: | ||
from sonic_platform_base.chassis_base import ChassisBase | ||
from sonic_platform.psu import Psu | ||
from sonic_platform.fan import Fan | ||
from sonic_platform.fan import FAN_PATH | ||
from sonic_platform.watchdog import get_watchdog | ||
from os import listdir | ||
from os.path import isfile, join | ||
import re | ||
except ImportError as e: | ||
raise ImportError (str(e) + "- required module not found") | ||
|
||
MLNX_NUM_PSU = 2 | ||
|
||
class Chassis(ChassisBase): | ||
"""Platform-specific Chassis class""" | ||
|
||
def __init__(self): | ||
ChassisBase.__init__(self) | ||
|
||
# Initialize PSU list | ||
for index in range(MLNX_NUM_PSU): | ||
psu = Psu(index) | ||
self._psu_list.append(psu) | ||
|
||
# Initialize watchdog | ||
self._watchdog = get_watchdog() | ||
|
||
# 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 | ||
|
||
for index in range(num_of_fan): | ||
if multi_rotor_in_drawer: | ||
fan = Fan(index, index/2) | ||
else: | ||
fan = Fan(index, index) | ||
self._fan_list.append(fan) | ||
|
||
def _extract_num_of_fans_and_fan_drawers(self): | ||
num_of_fan = 0 | ||
num_of_drawer = 0 | ||
for f in listdir(FAN_PATH): | ||
if isfile(join(FAN_PATH, f)): | ||
match_obj = re.match('fan(\d+)_speed_get', f) | ||
if match_obj != None: | ||
if int(match_obj.group(1)) > num_of_fan: | ||
num_of_fan = int(match_obj.group(1)) | ||
else: | ||
match_obj = re.match('fan(\d+)_status', f) | ||
if match_obj != None and int(match_obj.group(1)) > num_of_drawer: | ||
num_of_drawer = int(match_obj.group(1)) | ||
|
||
return num_of_fan, num_of_drawer | ||
|
||
|
||
|
246 changes: 246 additions & 0 deletions
246
platform/mellanox/mlnx-platform-api/sonic_platform/fan.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,246 @@ | ||
#!/usr/bin/env python | ||
|
||
############################################################################# | ||
# Mellanox | ||
# | ||
# Module contains an implementation of SONiC Platform Base API and | ||
# provides the FANs status which are available in the platform | ||
# | ||
############################################################################# | ||
|
||
import os.path | ||
|
||
try: | ||
from sonic_platform_base.fan_base import FanBase | ||
except ImportError as e: | ||
raise ImportError (str(e) + "- required module not found") | ||
|
||
LED_ON = 1 | ||
LED_OFF = 0 | ||
|
||
PWM_MAX = 255 | ||
|
||
FAN_PATH = "/var/run/hw-management/thermal/" | ||
LED_PATH = "/var/run/hw-management/led/" | ||
|
||
class Fan(FanBase): | ||
"""Platform-specific Fan class""" | ||
def __init__(self, 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) | ||
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) | ||
else: | ||
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_max_speed_path = "psu{}_max".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_led_cap_path = "led_fan{}_capability".format(self.drawer_index) | ||
|
||
def get_status(self): | ||
""" | ||
Retrieves the operational status of fan | ||
Returns: | ||
bool: True if fan is operating properly, False if not | ||
""" | ||
status = 0 | ||
if self.is_psu_fan: | ||
status = 1 | ||
else: | ||
try: | ||
with open(os.path.join(FAN_PATH, self.fan_status_path), 'r') as fault_status: | ||
status = int(fault_status.read()) | ||
except (ValueError, IOError): | ||
status = 0 | ||
|
||
return status == 1 | ||
|
||
def get_presence(self): | ||
""" | ||
Retrieves the presence status of fan | ||
Returns: | ||
bool: True if fan is present, False if not | ||
""" | ||
status = 0 | ||
if self.is_psu_fan: | ||
if os.path.exists(os.path.join(FAN_PATH, self.fan_presence_path)): | ||
status = 1 | ||
else: | ||
status = 0 | ||
else: | ||
try: | ||
with open(os.path.join(FAN_PATH, self.fan_presence_path), 'r') as presence_status: | ||
status = int(presence_status.read()) | ||
except (ValueError, IOError): | ||
status = 0 | ||
|
||
return status == 1 | ||
|
||
def _get_min_speed_in_rpm(self): | ||
speed = 0 | ||
try: | ||
with open(os.path.join(FAN_PATH, self.fan_min_speed_path), 'r') as min_fan_speed: | ||
speed = int(min_fan_speed.read()) | ||
except (ValueError, IOError): | ||
speed = 0 | ||
|
||
return speed | ||
|
||
def _get_max_speed_in_rpm(self): | ||
speed = 0 | ||
try: | ||
with open(os.path.join(FAN_PATH, self.fan_max_speed_path), 'r') as max_fan_speed: | ||
speed = int(max_fan_speed.read()) | ||
except (ValueError, IOError): | ||
speed = 0 | ||
|
||
return speed | ||
|
||
def get_speed(self): | ||
""" | ||
Retrieves the speed of fan | ||
Returns: | ||
int: percentage of the max fan speed | ||
""" | ||
speed = 0 | ||
try: | ||
with open(os.path.join(FAN_PATH, self.fan_speed_get_path), 'r') as fan_curr_speed: | ||
speed_in_rpm = int(fan_curr_speed.read()) | ||
except (ValueError, IOError): | ||
speed_in_rpm = 0 | ||
|
||
max_speed_in_rpm = self._get_max_speed_in_rpm() | ||
speed = 100*speed_in_rpm/max_speed_in_rpm | ||
|
||
return speed | ||
|
||
def get_target_speed(self): | ||
""" | ||
Retrieves the expected speed of fan | ||
Returns: | ||
int: percentage of the max fan speed | ||
""" | ||
speed = 0 | ||
|
||
if self.is_psu_fan: | ||
# Not like system fan, psu fan speed can not be modified, so target speed is N/A | ||
return speed | ||
try: | ||
with open(os.path.join(FAN_PATH, self.fan_speed_set_path), 'r') as fan_pwm: | ||
pwm = int(fan_pwm.read()) | ||
except (ValueError, IOError): | ||
pwm = 0 | ||
|
||
speed = int(round(pwm*100.0/PWM_MAX)) | ||
|
||
return speed | ||
|
||
def set_speed(self, speed): | ||
""" | ||
Set fan speed to expected value | ||
Args: | ||
speed: An integer, the percentage of full fan speed to set fan to, | ||
in the range 0 (off) to 100 (full speed) | ||
Returns: | ||
bool: True if set success, False if fail. | ||
""" | ||
status = True | ||
pwm = int(round(PWM_MAX*speed/100.0)) | ||
|
||
if self.is_psu_fan: | ||
#PSU fan speed is not setable. | ||
return False | ||
|
||
try: | ||
with open(os.path.join(FAN_PATH, self.fan_speed_set_path), 'w') as fan_pwm: | ||
fan_pwm.write(str(pwm)) | ||
except (ValueError, IOError): | ||
status = False | ||
|
||
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): | ||
""" | ||
Set led to expected color | ||
Args: | ||
color: A string representing the color with which to set the | ||
fan module status LED | ||
Returns: | ||
bool: True if set success, False if fail. | ||
""" | ||
led_cap_list = self._get_led_capability() | ||
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 == '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': | ||
# 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: | ||
led_path = os.path.join(LED_PATH, self.fan_red_led_path) | ||
elif '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)) | ||
else: | ||
status = False | ||
except (ValueError, IOError): | ||
status = False | ||
return status | ||
|
||
def get_speed_tolerance(self): | ||
""" | ||
Retrieves the speed tolerance of the fan | ||
Returns: | ||
An integer, the percentage of variance from target speed which is | ||
considered tolerable | ||
""" | ||
# The tolerance value is fixed as 20% for all the Mellanox platform | ||
return 20 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
35 changes: 0 additions & 35 deletions
35
platform/mellanox/mlnx-platform-api/sonic_platform_api/chassis.py
This file was deleted.
Oops, something went wrong.