2
0
mirror of https://opendev.org/x/pyghmi synced 2026-03-31 15:23:31 +00:00

Implement OEM Inventory components

Provide a framework for OEM to add inventory devices
without requiring FRU locator records.  This enables
vendors to provide additional data in a more flexible
scheme.

Change-Id: I9ef9685de9150940321aecbf2cc275cfbbe8ce6a
This commit is contained in:
Jarrod Johnson
2015-06-02 09:49:02 -04:00
parent 9efd878fd5
commit 25edd1ac31
3 changed files with 129 additions and 2 deletions

View File

@@ -439,6 +439,9 @@ class Command(object):
self._sdr = sdr.SDR(self)
for fruid in self._sdr.fru:
yield self._sdr.fru[fruid].fru_name
self.oem_init()
for compname in self._oem.get_oem_inventory_descriptions():
yield compname
def get_inventory_of_component(self, component):
"""Retrieve inventory of a component
@@ -455,6 +458,7 @@ class Command(object):
if self._sdr.fru[fruid].fru_name == component:
return self._oem.process_fru(fru.FRU(
ipmicmd=self, fruid=fruid, sdr=self._sdr.fru[fruid]).info)
return self._oem.get_inventory_of_component(component)
def _get_zero_fru(self):
# It is expected that a manufacturer matches SMBIOS to IPMI
@@ -493,6 +497,8 @@ class Command(object):
if fruinf is not None:
fruinf = self._oem.process_fru(fruinf)
yield (self._sdr.fru[fruid].fru_name, fruinf)
for componentpair in self._oem.get_oem_inventory():
yield componentpair
def get_health(self):
"""Summarize health of managed system

View File

@@ -41,6 +41,35 @@ class OEMHandler(object):
if evdata[0] & 0b110000 == 0b100000:
event['oem_byte3'] = evdata[2]
def get_oem_inventory_descriptions(self):
"""Get descriptions of available additional inventory items
OEM implementation may provide additional records not indicated
by FRU locator SDR records. An implementation is expected to
implement this function to list component names that would map to
OEM behavior beyond the specification. It should return an iterable
of names
"""
return ()
def get_oem_inventory(self):
"""Get tuples of component names and inventory data.
This returns an iterable of tuples. The first member of each tuple
is a string description of the inventory item. The second member
is a dict of inventory information about the component.
"""
for desc in self.get_oem_inventory_descriptions():
yield (desc, self.get_inventory_of_component(desc))
def get_inventory_of_component(self, component):
"""Get inventory detail of an OEM defined component
Given a string that may be an OEM component, return the detail of that
component. If the component does not exist, returns None
"""
return None
def process_fru(self, fru):
"""Modify a fru entry with OEM understanding.

View File

@@ -17,7 +17,9 @@
import pyghmi.constants as pygconst
import pyghmi.ipmi.oem.generic as generic
import pyghmi.ipmi.private.constants as ipmiconst
import pyghmi.ipmi.private.spd as spd
import pyghmi.ipmi.private.util as util
import struct
firmware_types = {
1: 'Management Controller',
@@ -67,6 +69,8 @@ class OEMHandler(generic.OEMHandler):
# will need to retain data to differentiate
# variations. For example System X versus Thinkserver
self.oemid = oemid
self.ipmicmd = ipmicmd
self.oem_inventory_info = None
def process_event(self, event, ipmicmd, seldata):
if 'oemdata' in event:
@@ -143,11 +147,99 @@ class OEMHandler(generic.OEMHandler):
event['component_type_id'] == 13):
event['component'] += ' {0}'.format(evdata[1] & 0b11111)
@property
def has_tsm(self):
"""True if this particular server have a TSM based service processor
"""
return (self.oemid['manufacturer_id'] == 19046 and
self.oemid['device_id'] == 32)
def get_oem_inventory_descriptions(self):
if self.has_tsm:
# Thinkserver with TSM
if not self.oem_inventory_info:
self._collect_tsm_inventory()
return iter(self.oem_inventory_info)
return ()
def get_oem_inventory(self):
if self.has_tsm:
self._collect_tsm_inventory()
for compname in self.oem_inventory_info:
yield (compname, self.oem_inventory_info[compname])
def get_inventory_of_component(self, component):
if self.has_tsm:
self._collect_tsm_inventory()
return self.oem_inventory_info.get(component, None)
def _decode_tsm_cpu(self, offset, cpudata):
keytext = 'CPU {0}'.format(ord(cpudata[offset]))
self.oem_inventory_info[keytext] = {}
if cpudata[offset + 1] == '\x00':
self.oem_inventory_info[keytext] = None
return
self.oem_inventory_info[keytext]['cores'] = ord(
cpudata[offset + 1])
self.oem_inventory_info[keytext]['threads'] = ord(
cpudata[offset + 2])
self.oem_inventory_info[keytext]['manufacturer'] = \
cpudata[offset + 3:offset + 16].rstrip('\x00')
self.oem_inventory_info[keytext]['family'] = \
cpudata[offset + 16: offset + 46].rstrip('\x00')
self.oem_inventory_info[keytext]['model'] = \
cpudata[offset + 46: offset + 76].rstrip('\x00')
self.oem_inventory_info[keytext]['stepping'] = \
cpudata[offset + 76: offset + 79].rstrip('\x00')
self.oem_inventory_info[keytext]['frequency'] = \
'{0:.1f} GHz'.format(
struct.unpack('<I',
cpudata[offset + 79: offset + 83])[0] / 1000.0)
def _decode_tsm_dimm(self, offset, memdata):
keytext = 'DIMM {0}'.format(ord(memdata[offset]))
if memdata[offset + 1] == '\x00':
self.oem_inventory_info[keytext] = None
return
self.oem_inventory_info[keytext] = {}
self.oem_inventory_info[keytext]['module_type'] = \
memdata[offset + 3: offset + 13].rstrip('\x00')
self.oem_inventory_info[keytext]['voltage'] = \
memdata[offset + 13: offset + 23].rstrip('\x00')
clock = struct.unpack(
'<H', memdata[offset + 23:offset + 25])[0]
self.oem_inventory_info[keytext]['speed'] = spd.speed_by_clock.get(
clock, 'Unknown')
self.oem_inventory_info[keytext]['capacity_mb'] = struct.unpack(
'<H', memdata[offset + 25:offset + 27])[0] * 1024
self.oem_inventory_info[keytext]['manufacturer'] = \
memdata[offset + 27:offset + 57].rstrip('\x00')
self.oem_inventory_info[keytext]['serial'] = \
struct.unpack('>I', memdata[offset + 57:offset + 61])[0]
self.oem_inventory_info[keytext]['model'] = \
memdata[offset + 61:offset + 82].rstrip('\x00')
def _collect_tsm_inventory(self):
# Collect CPU inventory
self.oem_inventory_info = {}
rsp = self.ipmicmd.xraw_command(netfn=6, command=0x59,
data=(0, 0xc1, 1, 0))
compcount = ord(rsp['data'][1])
for cpu in xrange(0, compcount):
offset = 2 + (85 * cpu)
self._decode_tsm_cpu(offset, rsp['data'])
# Collect memory inventory
rsp = self.ipmicmd.xraw_command(netfn=6, command=0x59,
data=(0, 0xc1, 2, 0))
compcount = ord(rsp['data'][1])
for dimm in xrange(0, compcount):
offset = 2 + (dimm * 84)
self._decode_tsm_dimm(offset, rsp['data'])
def process_fru(self, fru):
if fru is None:
return fru
if (self.oemid['manufacturer_id'] == 19046 and
self.oemid['device_id'] == 32):
if self.has_tsm:
fru['oem_parser'] = 'lenovo'
# Thinkserver lays out specific interpretation of the
# board extra fields