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

DellEMC: Z9264-Platform2.0 Implementation [ipmihelper] #4060

Merged
merged 1 commit into from
Jan 29, 2020
Merged
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
259 changes: 259 additions & 0 deletions platform/broadcom/sonic-platform-modules-dell/common/ipmihelper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
#! /usr/bin/python

########################################################################
# DellEMC
#
# Module contains implementation of IpmiSensor and IpmiFru classes that
# provide Sensor's and FRU's information respectively.
#
########################################################################

import subprocess
import re

# IPMI Request Network Function Codes
NetFn_SensorEvent = 0x04
NetFn_Storage = 0x0A

# IPMI Sensor Device Commands
Cmd_GetSensorReadingFactors = 0x23
Cmd_GetSensorThreshold = 0x27
Cmd_GetSensorReading = 0x2D

# IPMI FRU Device Commands
Cmd_ReadFRUData = 0x11

class IpmiSensor(object):

# Sensor Threshold types and their respective bit masks
THRESHOLD_BIT_MASK = {
"LowerNonCritical" : 0,
"LowerCritical" : 1,
"LowerNonRecoverable" : 2,
"UpperNonCritical" : 3,
"UpperCritical" : 4,
"UpperNonRecoverable" : 5
}

def __init__(self, sensor_id, is_discrete=False):
self.id = sensor_id
self.is_discrete = is_discrete

def _get_ipmitool_raw_output(self, args):
"""
Returns a list the elements of which are the individual bytes of
ipmitool raw <cmd> command output.
"""
result_bytes = list()
result = ""
command = "ipmitool raw {}".format(args)
try:
proc = subprocess.Popen(command.split(), stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
if not proc.returncode:
result = stdout.rstrip('\n')
except:
pass

for i in result.split():
result_bytes.append(int(i, 16))

return result_bytes

def _get_converted_sensor_reading(self, raw_value):
"""
Returns a 2 element tuple(bool, int) in which first element
provides the validity of the reading and the second element is
the converted sensor reading
"""
# Get Sensor Reading Factors
cmd_args = "{} {} {} {}".format(NetFn_SensorEvent,
Cmd_GetSensorReadingFactors,
self.id, raw_value)
factors = self._get_ipmitool_raw_output(cmd_args)

if len(factors) != 7:
return False, 0

# Compute Twos complement
def get_twos_complement(val, bits):
if val & (1 << (bits - 1)):
val = val - (1 << bits)
return val

# Calculate actual sensor value from the raw sensor value
# using the sensor reading factors.
M = get_twos_complement(((factors[2] & 0xC0) << 8) | factors[1], 10)
B = get_twos_complement(((factors[4] & 0xC0) << 8) | factors[3], 10)
R_exp = get_twos_complement((factors[6] & 0xF0) >> 4, 4)
B_exp = get_twos_complement(factors[6] & 0x0F, 4)

converted_reading = ((M * raw_value) + (B * 10**B_exp)) * 10**R_exp

return True, converted_reading

def get_reading(self):
"""
For Threshold sensors, returns the sensor reading.
For Discrete sensors, returns the state value.

Returns:
A tuple (bool, int) where the first element provides the
validity of the reading and the second element provides the
sensor reading/state value.
"""
# Get Sensor Reading
cmd_args = "{} {} {}".format(NetFn_SensorEvent, Cmd_GetSensorReading,
self.id)
output = self._get_ipmitool_raw_output(cmd_args)
if len(output) != 4:
return False, 0

# Check reading/state unavailable
if output[1] & 0x20:
return False, 0

if self.is_discrete:
state = ((output[3] & 0x7F) << 8) | output[2]
return True, state
else:
return self._get_converted_sensor_reading(output[0])

def get_threshold(self, threshold_type):
"""
Returns the sensor's threshold value for a given threshold type.

Args:
threshold_type (str) - one of the below mentioned
threshold type strings

"LowerNonCritical"
"LowerCritical"
"LowerNonRecoverable"
"UpperNonCritical"
"UpperCritical"
"UpperNonRecoverable"
Returns:
A tuple (bool, int) where the first element provides the
validity of that threshold and second element provides the
threshold value.
"""
# Thresholds are not valid for discrete sensors
if self.is_discrete:
raise TypeError("Threshold is not applicable for Discrete Sensor")

if threshold_type not in self.THRESHOLD_BIT_MASK.keys():
raise ValueError("Invalid threshold type {} provided. Valid types "
"are {}".format(threshold_type,
self.THRESHOLD_BIT_MASK.keys()))

bit_mask = self.THRESHOLD_BIT_MASK[threshold_type]

# Get Sensor Threshold
cmd_args = "{} {} {}".format(NetFn_SensorEvent, Cmd_GetSensorThreshold,
self.id)
thresholds = self._get_ipmitool_raw_output(cmd_args)
if len(thresholds) != 7:
return False, 0

valid_thresholds = thresholds.pop(0)
# Check whether particular threshold is readable
if valid_thresholds & (1 << bit_mask):
return self._get_converted_sensor_reading(thresholds[bit_mask])
else:
return False, 0

class IpmiFru(object):

def __init__(self, fru_id):
self.id = fru_id

def _get_ipmitool_fru_print(self):
result = ""
command = "ipmitool fru print {}".format(self.id)
try:
proc = subprocess.Popen(command.split(), stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
if not proc.returncode:
result = stdout.rstrip('\n')
except:
pass

return result

def get_board_serial(self):
"""
Returns a string containing the Serial Number of the device.
"""
fru_output = self._get_ipmitool_fru_print()
if not fru_output:
return "NA"

board_serial = re.search(r'Board Serial\s*:(.*)', fru_output)
if not board_serial:
return "NA"

return board_serial.group(1).strip()

def get_board_part_number(self):
"""
Returns a string containing the Part Number of the device.
"""
fru_output = self._get_ipmitool_fru_print()
if not fru_output:
return "NA"

board_pn = re.search(r'Board Part Number\s*:(.*)', fru_output)
if not board_pn:
return "NA"

return board_pn.group(1).strip()

def get_fru_data(self, offset, count=1):
"""
Reads and returns the FRU data at the provided offset.

Args:
offset (int) - FRU offset to read
count (int) - Number of bytes to read [optional, default = 1]
Returns:
A tuple (bool, list(int)) where the first element provides
the validity of the data read and the second element is a
list, the elements of which are the individual bytes of the
FRU data read.
"""
result_bytes = list()
is_valid = True
result = ""

offset_LSB = offset & 0xFF
offset_MSB = offset & 0xFF00
command = "ipmitool raw {} {} {} {} {} {}".format(NetFn_Storage,
Cmd_ReadFRUData,
self.id, offset_LSB,
offset_MSB, count)
try:
proc = subprocess.Popen(command.split(), stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
if not proc.returncode:
result = stdout.rstrip('\n')
except:
is_valid = False

if (not result) or (not is_valid):
return False, result_bytes

for i in result.split():
result_bytes.append(int(i, 16))

read_count = result_bytes.pop(0)
if read_count != count:
return False, result_bytes
else:
return True, result_bytes
2 changes: 2 additions & 0 deletions platform/broadcom/sonic-platform-modules-dell/debian/rules
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ override_dh_auto_build:
python2.7 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \
cd $(MOD_SRC_DIR); \
elif [ $$mod = "z9264f" ]; then \
cp $(COMMON_DIR)/ipmihelper.py $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \
cd $(MOD_SRC_DIR)/$${mod}; \
python2.7 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \
cd $(MOD_SRC_DIR); \
Expand Down Expand Up @@ -72,6 +73,7 @@ override_dh_clean:
rm -rf $(MOD_SRC_DIR)/$${mod}/build; \
rm -rf $(MOD_SRC_DIR)/$${mod}/build/*.egg-info; \
elif [ $$mod = "z9264f" ]; then \
rm -f $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \
rm -f $(MOD_SRC_DIR)/$${mod}/modules/*.whl; \
rm -rf $(MOD_SRC_DIR)/$${mod}/build; \
rm -rf $(MOD_SRC_DIR)/$${mod}/build/*.egg-info; \
Expand Down