2
0
mirror of https://opendev.org/x/pyghmi synced 2026-03-29 06:13:30 +00:00

Implement Thinkserver OEM SEL decode

The Thinkserver platform may have a number of OEM entries.
Provide a reasonable decode of those events.

Change-Id: Ie4be9848293c00e8b0d3490075101ed8be1cf72e
This commit is contained in:
Jarrod Johnson
2015-05-20 09:50:56 -04:00
parent 3db5df1b4a
commit 8b94506ce9
3 changed files with 119 additions and 13 deletions

View File

@@ -303,11 +303,11 @@ def _fix_sel_time(records, ipmicmd):
record = records[index]
if 'timecode' not in record or record['timecode'] == 0xffffffff:
continue
if (record['event'] == 'Clock time change' and
if ('event' in record and record['event'] == 'Clock time change' and
record['event_data'] == 'After'):
newtimestamp = record['timecode']
trimindexes.append(index)
elif (record['event'] == 'Clock time change' and
elif ('event' in record and record['event'] == 'Clock time change' and
record['event_data'] == 'Before'):
if newtimestamp:
if record['timecode'] < 0x20000000:
@@ -453,7 +453,7 @@ class EventHandler(object):
# In this class of OEM message, all bytes are OEM, interpretation
# is wholly left up to the OEM layer, using the OEM ID of the BMC
event['oemdata'] = selentry[3:]
self._ipmicmd._oem.process_event(event)
self._ipmicmd._oem.process_event(event, self._ipmicmd, selentry)
if 'event_type_byte' in event:
del event['event_type_byte']
if 'event_data_bytes' in event:

View File

@@ -27,7 +27,7 @@ class OEMHandler(object):
def __init__(self, oemid, ipmicmd):
pass
def process_event(self, event):
def process_event(self, event, ipmicmd, seldata):
"""Modify an event according with OEM understanding.
Given an event, allow an OEM module to augment it. For example,

View File

@@ -14,9 +14,52 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import pyghmi.constants as pygconst
import pyghmi.ipmi.oem.generic as generic
import pyghmi.ipmi.private.constants as ipmiconst
import pyghmi.ipmi.private.util as util
firmware_types = {
1: 'Management Controller',
2: 'UEFI/BIOS',
3: 'CPLD',
4: 'Power Supply',
5: 'Storage Adapter',
6: 'Add-in Adapter',
}
firmware_event = {
0: ('Update failed', pygconst.Health.Failed),
1: ('Update succeeded', pygconst.Health.Ok),
2: ('Update aborted', pygconst.Health.Ok),
3: ('Unknown', pygconst.Health.Warning),
}
me_status = {
0: ('Recovery GPIO forced', pygconst.Health.Warning),
1: ('ME Image corrupt', pygconst.Health.Critical),
2: ('Flash erase error', pygconst.Health.Critical),
3: ('Unspecified flash state', pygconst.Health.Warning),
4: ('ME watchdog timeout', pygconst.Health.Critical),
5: ('ME platform reboot', pygconst.Health.Critical),
6: ('ME update', pygconst.Health.Ok),
7: ('Manufacturing error', pygconst.Health.Critical),
8: ('ME Flash storage integrity error', pygconst.Health.Critical),
9: ('ME firmware exception', pygconst.Health.Critical), # event data 3..
0xa: ('ME firmware worn', pygconst.Health.Warning),
0xc: ('Invalid SCMP state', pygconst.Health.Warning),
0xd: ('PECI over DMI failure', pygconst.Health.Warning),
0xe: ('MCTP interface failure', pygconst.Health.Warning),
0xf: ('Auto configuration completed', pygconst.Health.Ok),
}
me_flash_status = {
0: ('ME flash corrupted', pygconst.Health.Critical),
1: ('ME flash erase limit reached', pygconst.Health.Critical),
2: ('ME flash write limit reached', pygconst.Health.Critical),
3: ('ME flash write enabled', pygconst.Health.Ok),
}
class OEMHandler(generic.OEMHandler):
# noinspection PyUnusedLocal
@@ -25,11 +68,74 @@ class OEMHandler(generic.OEMHandler):
# variations. For example System X versus Thinkserver
self.oemid = oemid
def process_event(self, event):
def process_event(self, event, ipmicmd, seldata):
if 'oemdata' in event:
event['event'] = 'OEM event: {0}'.format(repr(event['oemdata']))
oemtype = seldata[2]
oemdata = event['oemdata']
if oemtype == 0xd0: # firmware update
event['component'] = firmware_types.get(oemdata[0], None)
event['component_type'] = ipmiconst.sensor_type_codes[0x2b]
slotnumber = (oemdata[1] & 0b11111000) >> 3
if slotnumber:
event['component'] += ' {0}'.format(slotnumber)
event['event'], event['severity'] = \
firmware_event[oemdata[1] & 0b111]
event['event_data'] = '{0}.{1}'.format(oemdata[2], oemdata[3])
elif oemtype == 0xd1: # BIOS recovery
event['severity'] = pygconst.Health.Warning
event['component'] = 'BIOS/UEFI'
event['component_type'] = ipmiconst.sensor_type_codes[0xf]
status = oemdata[0]
method = (status & 0b11110000) >> 4
status = (status & 0b1111)
if method == 1:
event['event'] = 'Automatic recovery'
elif method == 2:
event['event'] = 'Manual recovery'
if status == 0:
event['event'] += '- Failed'
event['severity'] = pygconst.Health.Failed
if oemdata[1] == 0x1:
event['event'] += '- BIOS recovery image not found'
event['event_data'] = '{0}.{1}'.format(oemdata[2], oemdata[3])
elif oemtype == 0xd2: # eMMC status
if oemdata[0] == 1:
event['component'] = 'eMMC'
event['component_type'] = ipmiconst.sensor_type_codes[0xc]
if oemdata[0] == 1:
event['event'] = 'eMMC Format error'
event['severity'] = pygconst.Health.Failed
elif oemtype == 0xd3:
if oemdata[0] == 1:
event['event'] = 'User privilege modification'
event['severity'] = pygconst.Health.Ok
event['component'] = 'User Privilege'
event['component_type'] = ipmiconst.sensor_type_codes[6]
event['event_data'] = \
'User {0} on channel {1} had privilege changed ' \
'from {2} to {3}'.format(
oemdata[2], oemdata[1], oemdata[3] & 0b1111,
(oemdata[3] & 0b11110000) >> 4
)
else:
event['event'] = 'OEM event: {0}'.format(
' '.join(format(x, '02x') for x in event['oemdata']))
del event['oemdata']
return
evdata = event['event_data_bytes']
if event['event_type_byte'] == 0x75: # ME event
event['component'] = 'ME Firmware'
event['component_type'] = ipmiconst.sensor_type_codes[0xf]
event['event'], event['severity'] = me_status.get(
evdata[1], ('Unknown', pygconst.Health.Warning))
if evdata[1] == 3:
event['event'], event['severity'] = me_flash_status.get(
evdata[2], ('Unknown state', pygconst.Health.Warning))
elif evdata[1] == 9:
event['event'] += ' (0x{0:2x})'.format(evdata[2])
elif evdata[1] == 0xf and evdata[2] & 0b10000000:
event['event'] = 'Auto configuration failed'
event['severity'] = pygconst.Health.Critical
# For HDD bay events, the event data 2 is the bay, modify
# the description to be more specific
if (event['event_type_byte'] == 0x6f and
@@ -55,14 +161,14 @@ class OEMHandler(generic.OEMHandler):
if mac2 not in ('00:00:00:00:00:00', ''):
fru['MAC Address 2'] = mac2
try:
# The product_extra field is UUID as the system would present
# in DMI. This is different than the two UUIDs that
# it returns for get device and get system uuid...
# The product_extra field is UUID as the system would present
# in DMI. This is different than the two UUIDs that
# it returns for get device and get system uuid...
byteguid = fru['product_extra'][0]
# It can present itself as claiming to be ASCII when it
# is actually raw hex. As a result it triggers the mechanism
# to strip \x00 from the end of text strings. Work around this
# by padding with \x00 to the right if the string is not 16 long
# It can present itself as claiming to be ASCII when it
# is actually raw hex. As a result it triggers the mechanism
# to strip \x00 from the end of text strings. Work around this
# by padding with \x00 to the right if less than 16 long
byteguid.extend('\x00' * (16 - len(byteguid)))
fru['UUID'] = util.decode_wireformat_uuid(byteguid)
except (AttributeError, KeyError):