Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
47 changes: 45 additions & 2 deletions device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,19 @@
#
#############################################################################
import glob
import os.path

try:
from sonic_platform_base.fan_base import FanBase
from .helper import APIHelper
except ImportError as e:
raise ImportError(str(e) + "- required module not found")

PSU_FAN_MAX_RPM = 25500
SPEED_TOLERANCE = 15
HOST_FAN_TOLERANCE_FILE = "/usr/share/sonic/device/{}/tolerance_flag"
PMON_FAN_TOLERANCE_FILE = "/usr/share/sonic/platform/tolerance_flag"

PSU_FAN_MAX_RPM = 25500

FAN_HWMON_I2C_PATH = "/sys/devices/platform/as4625_fan/hwmon/hwmon*/fan"

Expand Down Expand Up @@ -44,10 +49,13 @@ class Fan(FanBase):
"""Platform-specific Fan class"""

def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0):
self._api_helper = APIHelper()
self.fan_index = fan_index
self.fan_tray_index = fan_tray_index
self.is_psu_fan = is_psu_fan
self.is_host = self._api_helper.is_host()

# sysfs path
if not self.is_psu_fan:
self.hwmon_path = FAN_HWMON_I2C_PATH
else:
Expand All @@ -60,6 +68,11 @@ def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0):
i2c_addr = PSU_EEPROM_I2C_MAPPING[self.psu_index]['addr']
self.psu_eeprom_path = I2C_PATH.format(i2c_num, i2c_addr)

# tolerance path
self.tolerance_flag = PMON_FAN_TOLERANCE_FILE
if self.is_host:
self.tolerance_flag = HOST_FAN_TOLERANCE_FILE.format(self._api_helper.get_platform())

FanBase.__init__(self)

def __read_txt_file(self, file_path):
Expand Down Expand Up @@ -164,14 +177,44 @@ def get_target_speed(self):
else:
return self.get_speed()

def set_tolerance_mode(self, mode):
"""
Set the fan tolerance mode using a flag file.
Args:
mode:
- "off": tolerance off → create flag file
- "on": tolerance activate → delete flag file
Returns:
bool: True if the operation succeeded, False otherwise.
"""
try:
if mode == "off":
open(self.tolerance_flag, "a").close()
elif mode == "on":
if os.path.exists(self.tolerance_flag):
os.remove(self.tolerance_flag)
else:
return False
return True

except OSError:
return False

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
"""
return SPEED_TOLERANCE
tolerance = SPEED_TOLERANCE
if self.is_psu_fan:
return tolerance

if os.path.exists(self.tolerance_flag):
raise NotImplementedError

return tolerance

def set_speed(self, speed):
"""
Expand Down
13 changes: 13 additions & 0 deletions device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from typing import cast

HOST_CHK_CMD = ["docker"]
MACHINE_CONF_FILE = "/host/machine.conf"
EMPTY_STRING = ""

class APIHelper():
Expand Down Expand Up @@ -63,6 +64,18 @@ def write_txt_file(self, file_path, value):
except IOError:
return False
return True

def get_platform(self):
platform = None

with open(MACHINE_CONF_FILE, 'r') as file:
for line in file:
if 'onie_platform=' in line:
platform = line.strip().split('=')[1]
break
Comment on lines +71 to +75
Copy link

Copilot AI Dec 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The get_platform method does not handle the case where the MACHINE_CONF_FILE cannot be opened or does not exist. This will cause an unhandled exception when the file is missing or inaccessible, potentially crashing the fan monitoring service.

Suggested change
with open(MACHINE_CONF_FILE, 'r') as file:
for line in file:
if 'onie_platform=' in line:
platform = line.strip().split('=')[1]
break
try:
with open(MACHINE_CONF_FILE, 'r') as file:
for line in file:
if 'onie_platform=' in line:
platform = line.strip().split('=')[1]
break
except (OSError, IOError):
# If the machine configuration file is missing or cannot be opened,
# return None to avoid raising an unhandled exception.
pass

Copilot uses AI. Check for mistakes.

return platform

class FileLock:

def __init__(self, lock_file):
Expand Down
46 changes: 43 additions & 3 deletions device/accton/x86_64-accton_as4630_54npe-r0/sonic_platform/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# provides the fan status which are available in the platform
#
#############################################################################

import os.path


try:
Expand All @@ -14,8 +14,11 @@
except ImportError as e:
raise ImportError(str(e) + "- required module not found")

PSU_FAN_MAX_RPM = 26688
SPEED_TOLERANCE = 15
HOST_FAN_TOLERANCE_FILE = "/usr/share/sonic/device/{}/tolerance_flag"
PMON_FAN_TOLERANCE_FILE = "/usr/share/sonic/platform/tolerance_flag"

PSU_FAN_MAX_RPM = 26688
CPLD_FAN_I2C_PATH = "/sys/bus/i2c/devices/3-0060/fan_"
I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/"
PSU_HWMON_I2C_MAPPING = {
Expand Down Expand Up @@ -51,7 +54,9 @@ def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0):
self.fan_index = fan_index
self.fan_tray_index = fan_tray_index
self.is_psu_fan = is_psu_fan
self.is_host = self._api_helper.is_host()

# sysfs path
if self.is_psu_fan:
self.psu_index = psu_index
self.psu_i2c_num = PSU_HWMON_I2C_MAPPING[self.psu_index]['num']
Expand All @@ -64,6 +69,11 @@ def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0):
self.psu_cpld_path = I2C_PATH.format(
self.psu_i2c_num, self.psu_i2c_addr)

# tolerance path
self.tolerance_flag = PMON_FAN_TOLERANCE_FILE
if self.is_host:
self.tolerance_flag = HOST_FAN_TOLERANCE_FILE.format(self._api_helper.get_platform())

FanBase.__init__(self)


Expand Down Expand Up @@ -138,14 +148,44 @@ def get_target_speed(self):
"""
return self.get_speed()

def set_tolerance_mode(self, mode):
"""
Set the fan tolerance mode using a flag file.
Args:
mode:
- "off": tolerance off → create flag file
- "on": tolerance activate → delete flag file
Returns:
bool: True if the operation succeeded, False otherwise.
"""
try:
if mode == "off":
open(self.tolerance_flag, "a").close()
elif mode == "on":
if os.path.exists(self.tolerance_flag):
os.remove(self.tolerance_flag)
else:
return False
return True

except OSError:
return False

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
"""
return SPEED_TOLERANCE
tolerance = SPEED_TOLERANCE
if self.is_psu_fan:
return tolerance

if os.path.exists(self.tolerance_flag):
raise NotImplementedError

return tolerance

def set_speed(self, speed):
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from sonic_py_common.general import getstatusoutput_noshell

HOST_CHK_CMD = ["docker"]
MACHINE_CONF_FILE = "/host/machine.conf"
EMPTY_STRING = ""


Expand Down Expand Up @@ -107,6 +108,16 @@ def ipmi_set_ss_thres(self, id, threshold_key, value):
status = False
return status, result

def get_platform(self):
platform = None

with open(MACHINE_CONF_FILE, 'r') as file:
for line in file:
if 'onie_platform=' in line:
platform = line.strip().split('=')[1]
break
Comment on lines +114 to +118
Copy link

Copilot AI Dec 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The get_platform method does not handle the case where the MACHINE_CONF_FILE cannot be opened or does not exist. This will cause an unhandled exception when the file is missing or inaccessible, potentially crashing the fan monitoring service.

Suggested change
with open(MACHINE_CONF_FILE, 'r') as file:
for line in file:
if 'onie_platform=' in line:
platform = line.strip().split('=')[1]
break
try:
with open(MACHINE_CONF_FILE, 'r') as file:
for line in file:
if 'onie_platform=' in line:
platform = line.strip().split('=')[1]
break
except (OSError, IOError):
# If the machine configuration file cannot be read, return None
platform = None

Copilot uses AI. Check for mistakes.

return platform

class FileLock:
"""
Expand Down
46 changes: 43 additions & 3 deletions device/accton/x86_64-accton_as4630_54pe-r0/sonic_platform/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# provides the fan status which are available in the platform
#
#############################################################################

import os.path


try:
Expand All @@ -14,8 +14,11 @@
except ImportError as e:
raise ImportError(str(e) + "- required module not found")

PSU_FAN_MAX_RPM = 26688
SPEED_TOLERANCE = 15
HOST_FAN_TOLERANCE_FILE = "/usr/share/sonic/device/{}/tolerance_flag"
PMON_FAN_TOLERANCE_FILE = "/usr/share/sonic/platform/tolerance_flag"

PSU_FAN_MAX_RPM = 26688
CPLD_FAN_I2C_PATH = "/sys/bus/i2c/devices/3-0060/fan_"
I2C_PATH ="/sys/bus/i2c/devices/{}-00{}/"
PSU_HWMON_I2C_MAPPING = {
Expand Down Expand Up @@ -52,7 +55,9 @@ def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0):
self.fan_index = fan_index
self.fan_tray_index = fan_tray_index
self.is_psu_fan = is_psu_fan
self.is_host = self._api_helper.is_host()

# sysfs path
if self.is_psu_fan:
self.psu_index = psu_index
self.psu_i2c_num = PSU_HWMON_I2C_MAPPING[self.psu_index]['num']
Expand All @@ -65,6 +70,11 @@ def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0):
self.psu_cpld_path = I2C_PATH.format(
self.psu_i2c_num, self.psu_i2c_addr)

# tolerance path
self.tolerance_flag = PMON_FAN_TOLERANCE_FILE
if self.is_host:
self.tolerance_flag = HOST_FAN_TOLERANCE_FILE.format(self._api_helper.get_platform())

FanBase.__init__(self)


Expand Down Expand Up @@ -139,14 +149,44 @@ def get_target_speed(self):
"""
return self.get_speed()

def set_tolerance_mode(self, mode):
"""
Set the fan tolerance mode using a flag file.
Args:
mode:
- "off": tolerance off → create flag file
- "on": tolerance activate → delete flag file
Returns:
bool: True if the operation succeeded, False otherwise.
"""
try:
if mode == "off":
open(self.tolerance_flag, "a").close()
elif mode == "on":
if os.path.exists(self.tolerance_flag):
os.remove(self.tolerance_flag)
else:
return False
return True

except OSError:
return False

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
"""
return SPEED_TOLERANCE
tolerance = SPEED_TOLERANCE
if self.is_psu_fan:
return tolerance

if os.path.exists(self.tolerance_flag):
raise NotImplementedError

return tolerance

def set_speed(self, speed):
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from sonic_py_common.general import getstatusoutput_noshell

HOST_CHK_CMD = ["docker"]
MACHINE_CONF_FILE = "/host/machine.conf"
EMPTY_STRING = ""


Expand Down Expand Up @@ -50,3 +51,13 @@ def write_txt_file(self, file_path, value):
return False
return True

def get_platform(self):
platform = None

with open(MACHINE_CONF_FILE, 'r') as file:
for line in file:
if 'onie_platform=' in line:
platform = line.strip().split('=')[1]
break
Comment on lines +57 to +61
Copy link

Copilot AI Dec 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The get_platform method does not handle the case where the MACHINE_CONF_FILE cannot be opened or does not exist. This will cause an unhandled exception when the file is missing or inaccessible, potentially crashing the fan monitoring service.

Suggested change
with open(MACHINE_CONF_FILE, 'r') as file:
for line in file:
if 'onie_platform=' in line:
platform = line.strip().split('=')[1]
break
try:
with open(MACHINE_CONF_FILE, 'r') as file:
for line in file:
if 'onie_platform=' in line:
platform = line.strip().split('=')[1]
break
except (IOError, OSError):
# If the machine configuration file cannot be opened or read,
# return None to avoid raising an unhandled exception.
return None

Copilot uses AI. Check for mistakes.

return platform
Loading