diff --git a/pyghmi/ipmi/oem/lenovo/dimm.py b/pyghmi/ipmi/oem/lenovo/dimm.py index ae231774..b51f8205 100755 --- a/pyghmi/ipmi/oem/lenovo/dimm.py +++ b/pyghmi/ipmi/oem/lenovo/dimm.py @@ -47,6 +47,7 @@ def get_categories(): "netfn": 0x06, "command": 0x59, "data": (0x00, 0xc1, 0x02, 0x00) - } + }, + "workaround_bmc_bug": True } } diff --git a/pyghmi/ipmi/oem/lenovo/handler.py b/pyghmi/ipmi/oem/lenovo/handler.py index e98e8f2b..ae2ba543 100755 --- a/pyghmi/ipmi/oem/lenovo/handler.py +++ b/pyghmi/ipmi/oem/lenovo/handler.py @@ -25,6 +25,7 @@ import pyghmi.ipmi.private.util as util from pyghmi.ipmi.oem.lenovo import cpu from pyghmi.ipmi.oem.lenovo import dimm from pyghmi.ipmi.oem.lenovo import drive + from pyghmi.ipmi.oem.lenovo import firmware from pyghmi.ipmi.oem.lenovo import inventory from pyghmi.ipmi.oem.lenovo import pci @@ -254,31 +255,55 @@ class OEMHandler(generic.OEMHandler): def _collect_tsm_inventory(self): self.oem_inventory_info = {} for catid, catspec in inventory.categories.items(): - try: - rsp = self.ipmicmd.xraw_command(**catspec["command"]) - except pygexc.IpmiException: - continue + if (catspec.get("workaround_bmc_bug", False)): + rsp = None + tmp_command = dict(catspec["command"]) + tmp_command["data"] = list(tmp_command["data"]) + count = 0 + for i in xrange(0x01, 0xff): + tmp_command["data"][-1] = i + try: + partrsp = self.ipmicmd.xraw_command(**tmp_command) + if rsp is None: + rsp = partrsp + rsp["data"] = list(rsp["data"]) + else: + rsp["data"].extend(partrsp["data"][1:]) + count += 1 + except Exception: + break + # If we didn't get any response, assume we don't have + # this category and go on to the next one + if rsp is None: + continue + rsp["data"].insert(1, count) + rsp["data"] = buffer(bytearray(rsp["data"])) else: try: - items = inventory.parse_inventory_category( - catid, rsp, - countable=catspec.get("countable", True) - ) + rsp = self.ipmicmd.xraw_command(**catspec["command"]) + except pygexc.IpmiException: + continue + # Parse the response we got + try: + items = inventory.parse_inventory_category( + catid, rsp, + countable=catspec.get("countable", True) + ) + except Exception: + # If we can't parse an inventory category, ignore it + print traceback.print_exc() + continue + + for item in items: + try: + key = catspec["idstr"].format(item["index"]) + del item["index"] + self.oem_inventory_info[key] = item except Exception: - # If we can't parse an inventory category, ignore it + # If we can't parse an inventory item, ignore it print traceback.print_exc() continue - for item in items: - try: - key = catspec["idstr"].format(item["index"]) - del item["index"] - self.oem_inventory_info[key] = item - except Exception: - # If we can't parse an inventory item, ignore it - print traceback.print_exc() - continue - def get_leds(self): if self.has_tsm: for (name, id_) in leds.items(): @@ -348,10 +373,10 @@ class OEMHandler(generic.OEMHandler): :param enable: True for enable and False for disable """ - # 1 – Enable power capping(default) + # 1 - Enable power capping(default) if enable: statecode = 1 - # 0 – Disable power capping + # 0 - Disable power capping else: statecode = 0 if self.has_tsm: diff --git a/pyghmi/ipmi/oem/lenovo/inventory.py b/pyghmi/ipmi/oem/lenovo/inventory.py index 39c2b528..5cd1b4e9 100755 --- a/pyghmi/ipmi/oem/lenovo/inventory.py +++ b/pyghmi/ipmi/oem/lenovo/inventory.py @@ -38,15 +38,19 @@ class EntryField(object): output :param valuefunc: a function to be called to change the value in the last step of the build process. + :param presence: whether the field indicates presence. In this case, the + field will not be included. If the value is false, the + item will be discarded. """ def __init__(self, name, fmt, include=True, mapper=None, valuefunc=None, - multivaluefunc=False): + multivaluefunc=False, presence=False): self.name = name self.fmt = fmt self.include = include self.mapper = mapper self.valuefunc = valuefunc self.multivaluefunc = multivaluefunc + self.presence = presence # General parameter parsing functions @@ -71,11 +75,16 @@ def parse_inventory_category(name, info, countable=True): cur += 1 else: count = 0 + discarded = 0 entries = [] while cur < len(raw): read, cpu = categories[name]["parser"](raw[cur:]) cur = cur + read + # Account for discarded entries (because they are not present) + if cpu is None: + discarded += 1 + continue if not countable: # count by myself count += 1 @@ -88,7 +97,7 @@ def parse_inventory_category(name, info, countable=True): raise Exception # TODO(avidal): raise specific exception to point that the number of # entries is different than the expected - if count != len(entries): + if count - discarded != len(entries): raise Exception return entries @@ -108,11 +117,15 @@ def parse_inventory_category_entry(raw, fields): obj = {} bytes_read = 0 + discard = False for field in fields: value = struct.unpack_from(field.fmt, r)[0] read = struct.calcsize(field.fmt) bytes_read += read r = r[read:] + # If this entry is not actually present, just parse and then discard it + if field.presence and not bool(value): + discard = True if not field.include: continue @@ -129,4 +142,6 @@ def parse_inventory_category_entry(raw, fields): for key in value: obj[key] = value[key] + if discard: + obj = None return bytes_read, obj diff --git a/pyghmi/ipmi/oem/lenovo/psu.py b/pyghmi/ipmi/oem/lenovo/psu.py index e5079f4f..c982d803 100755 --- a/pyghmi/ipmi/oem/lenovo/psu.py +++ b/pyghmi/ipmi/oem/lenovo/psu.py @@ -83,7 +83,7 @@ def psu_status_word_parser(word): psu_fields = ( EntryField("index", "B"), - EntryField("Presence State", "B", include=False), + EntryField("Presence State", "B", presence=True), EntryField("Capacity W", "