-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[platform/device] - Implement Silverstone platform API [PSU] (#3784)
Implement part of the Chassis and Fan related APIs. Psu APIs get_voltage() get_current() get_power() get_powergood_status() set_status_led() get_status_led() Update Fan APIs to support PSU FAN get_direction() get_speed() get_target_speed() get_speed_tolerance() get_target_speed() PSU APIs base on Device API get_name() get_presence() get_model() get_serial() get_status() - How I did it Implement PSU APIs Update FAN API to support PSU Fans Add PSU object to Chassis API
- Loading branch information
Showing
3 changed files
with
278 additions
and
5 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
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
243 changes: 243 additions & 0 deletions
243
device/celestica/x86_64-cel_silverstone-r0/sonic_platform/psu.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,243 @@ | ||
#!/usr/bin/env python | ||
|
||
############################################################################# | ||
# Celestica | ||
# | ||
# Module contains an implementation of SONiC Platform Base API and | ||
# provides the PSUs status which are available in the platform | ||
# | ||
############################################################################# | ||
|
||
import os | ||
import re | ||
import math | ||
import sonic_platform | ||
|
||
try: | ||
from sonic_platform_base.psu_base import PsuBase | ||
from helper import APIHelper | ||
from sonic_platform.fan import Fan | ||
except ImportError as e: | ||
raise ImportError(str(e) + "- required module not found") | ||
|
||
PSU_NAME_LIST = ["PSU-1", "PSU-2"] | ||
PSU_NUM_FAN = [1, 1] | ||
|
||
IPMI_SENSOR_NETFN = "0x04" | ||
IPMI_OEM_NETFN = "0x3A" | ||
IPMI_SS_READ_CMD = "0x2D {}" | ||
IPMI_SET_PSU_LED_CMD = "0x07 0x02 {}" | ||
IPMI_GET_PSU_LED_CMD = "0x08 0x02" | ||
IPMI_FRU_MODEL_KEY = "Board Part Number" | ||
IPMI_FRU_SERIAL_KEY = "Board Serial" | ||
|
||
PSU_LED_OFF_CMD = "0x00" | ||
PSU_LED_GREEN_CMD = "0x01" | ||
PSU_LED_AMBER_CMD = "0x02" | ||
|
||
PSU1_VOUT_SS_ID = "0x36" | ||
PSU1_COUT_SS_ID = "0x37" | ||
PSU1_POUT_SS_ID = "0x38" | ||
PSU1_STATUS_REG = "0x39" | ||
|
||
PSU2_VOUT_SS_ID = "0x40" | ||
PSU2_COUT_SS_ID = "0x41" | ||
PSU2_POUT_SS_ID = "0x42" | ||
PSU2_STATUS_REG = "0x2f" | ||
|
||
PSU1_FRU_ID = 3 | ||
|
||
SS_READ_OFFSET = 0 | ||
|
||
|
||
class Psu(PsuBase): | ||
"""Platform-specific Psu class""" | ||
|
||
def __init__(self, psu_index): | ||
PsuBase.__init__(self) | ||
self.index = psu_index | ||
for fan_index in range(0, PSU_NUM_FAN[self.index]): | ||
fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) | ||
self._fan_list.append(fan) | ||
self._api_helper = APIHelper() | ||
|
||
def find_value(self, in_string): | ||
result = re.search("^.+ ([0-9a-f]{2}) .+$", in_string) | ||
return result.group(1) if result else result | ||
|
||
def get_voltage(self): | ||
""" | ||
Retrieves current PSU voltage output | ||
Returns: | ||
A float number, the output voltage in volts, | ||
e.g. 12.1 | ||
""" | ||
psu_voltage = 0.0 | ||
psu_vout_key = globals()['PSU{}_VOUT_SS_ID'.format(self.index+1)] | ||
status, raw_ss_read = self._api_helper.ipmi_raw( | ||
IPMI_SENSOR_NETFN, IPMI_SS_READ_CMD.format(psu_vout_key)) | ||
ss_read = raw_ss_read.split()[SS_READ_OFFSET] | ||
# Formula: Rx1x10^-1 | ||
psu_voltage = int(ss_read, 16) * math.pow(10, -1) | ||
|
||
return psu_voltage | ||
|
||
def get_current(self): | ||
""" | ||
Retrieves present electric current supplied by PSU | ||
Returns: | ||
A float number, the electric current in amperes, e.g 15.4 | ||
""" | ||
psu_current = 0.0 | ||
psu_cout_key = globals()['PSU{}_COUT_SS_ID'.format(self.index+1)] | ||
status, raw_ss_read = self._api_helper.ipmi_raw( | ||
IPMI_SENSOR_NETFN, IPMI_SS_READ_CMD.format(psu_cout_key)) | ||
ss_read = raw_ss_read.split()[SS_READ_OFFSET] | ||
# Formula: Rx5x10^-1 | ||
psu_current = int(ss_read, 16) * 5 * math.pow(10, -1) | ||
|
||
return psu_current | ||
|
||
def get_power(self): | ||
""" | ||
Retrieves current energy supplied by PSU | ||
Returns: | ||
A float number, the power in watts, e.g. 302.6 | ||
""" | ||
psu_power = 0.0 | ||
psu_pout_key = globals()['PSU{}_POUT_SS_ID'.format(self.index+1)] | ||
status, raw_ss_read = self._api_helper.ipmi_raw( | ||
IPMI_SENSOR_NETFN, IPMI_SS_READ_CMD.format(psu_pout_key)) | ||
ss_read = raw_ss_read.split()[SS_READ_OFFSET] | ||
# Formula: Rx6x10^0 | ||
psu_power = int(ss_read, 16) * 6 | ||
return psu_power | ||
|
||
def get_powergood_status(self): | ||
""" | ||
Retrieves the powergood status of PSU | ||
Returns: | ||
A boolean, True if PSU has stablized its output voltages and passed all | ||
its internal self-tests, False if not. | ||
""" | ||
return self.get_status() | ||
|
||
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 | ||
Note: Only support green and off | ||
Returns: | ||
bool: True if status LED state is set successfully, False if not | ||
Note | ||
Set manual | ||
ipmitool raw 0x3a 0x09 0x2 0x0 | ||
""" | ||
led_cmd = { | ||
self.STATUS_LED_COLOR_GREEN: PSU_LED_GREEN_CMD, | ||
self.STATUS_LED_COLOR_AMBER: PSU_LED_AMBER_CMD, | ||
self.STATUS_LED_COLOR_OFF: PSU_LED_OFF_CMD | ||
}.get(color) | ||
|
||
status, set_led = self._api_helper.ipmi_raw( | ||
IPMI_OEM_NETFN, IPMI_SET_PSU_LED_CMD.format(led_cmd)) | ||
set_status_led = False if not status else True | ||
|
||
return set_status_led | ||
|
||
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 | ||
""" | ||
status, hx_color = self._api_helper.ipmi_raw( | ||
IPMI_OEM_NETFN, IPMI_GET_PSU_LED_CMD) | ||
|
||
status_led = { | ||
"00": self.STATUS_LED_COLOR_OFF, | ||
"01": self.STATUS_LED_COLOR_GREEN, | ||
"02": self.STATUS_LED_COLOR_AMBER, | ||
}.get(hx_color, self.STATUS_LED_COLOR_OFF) | ||
|
||
return status_led | ||
|
||
def get_name(self): | ||
""" | ||
Retrieves the name of the device | ||
Returns: | ||
string: The name of the device | ||
""" | ||
return PSU_NAME_LIST[self.index] | ||
|
||
def get_presence(self): | ||
""" | ||
Retrieves the presence of the PSU | ||
Returns: | ||
bool: True if PSU is present, False if not | ||
""" | ||
psu_presence = False | ||
psu_pstatus_key = globals()['PSU{}_STATUS_REG'.format(self.index+1)] | ||
status, raw_status_read = self._api_helper.ipmi_raw( | ||
IPMI_SENSOR_NETFN, IPMI_SS_READ_CMD.format(psu_pstatus_key)) | ||
status_byte = self.find_value(raw_status_read) | ||
|
||
if status: | ||
presence_int = (int(status_byte, 16) >> 0) & 1 | ||
psu_presence = True if presence_int else False | ||
|
||
return psu_presence | ||
|
||
def get_model(self): | ||
""" | ||
Retrieves the model number (or part number) of the device | ||
Returns: | ||
string: Model/part number of device | ||
""" | ||
model = "Unknown" | ||
ipmi_fru_idx = self.index + PSU1_FRU_ID | ||
status, raw_model = self._api_helper.ipmi_fru_id( | ||
ipmi_fru_idx, IPMI_FRU_MODEL_KEY) | ||
|
||
fru_pn_list = raw_model.split() | ||
if len(fru_pn_list) > 4: | ||
model = fru_pn_list[4] | ||
|
||
return model | ||
|
||
def get_serial(self): | ||
""" | ||
Retrieves the serial number of the device | ||
Returns: | ||
string: Serial number of device | ||
""" | ||
serial = "Unknown" | ||
ipmi_fru_idx = self.index + PSU1_FRU_ID | ||
status, raw_model = self._api_helper.ipmi_fru_id( | ||
ipmi_fru_idx, IPMI_FRU_SERIAL_KEY) | ||
|
||
fru_sr_list = raw_model.split() | ||
if len(fru_sr_list) > 3: | ||
serial = fru_sr_list[3] | ||
|
||
return serial | ||
|
||
def get_status(self): | ||
""" | ||
Retrieves the operational status of the device | ||
Returns: | ||
A boolean value, True if device is operating properly, False if not | ||
""" | ||
psu_status = False | ||
psu_pstatus_key = globals()['PSU{}_STATUS_REG'.format(self.index+1)] | ||
status, raw_status_read = self._api_helper.ipmi_raw( | ||
IPMI_SENSOR_NETFN, IPMI_SS_READ_CMD.format(psu_pstatus_key)) | ||
status_byte = self.find_value(raw_status_read) | ||
|
||
if status: | ||
failure_detected = (int(status_byte, 16) >> 1) & 1 | ||
input_lost = (int(status_byte, 16) >> 3) & 1 | ||
psu_status = False if (input_lost or failure_detected) else True | ||
|
||
return psu_status |