#!/usr/bin/env python # # Copyright 2018-2019 Raptor Engineering, LLC # Released under the terms of the GPL v3 # # Get current istep with # busctl get-property org.openbmc.status.IPL /org/openbmc/status/IPL org.openbmc.status.IPL current_istep # Get current status with # busctl get-property org.openbmc.status.IPL /org/openbmc/status/IPL org.openbmc.status.IPL current_status import gobject import dbus import dbus.service import dbus.mainloop.glib import re import os import subprocess import time import subprocess import traceback from binascii import hexlify from fcntl import fcntl, F_GETFL, F_SETFL from os import O_NONBLOCK, read import obmc.dbuslib.propertycacher as PropertyCacher from obmc.dbuslib.bindings import DbusProperties, DbusObjectManager, get_dbus import obmc.enums import obmc_system_config as System import obmc.mapper.utils import obmc.inventory DBUS_NAME = 'org.openbmc.status.IPL' OBJ_NAME = u'/org/openbmc/status/IPL' IPL_FLAG_DIR = '/run/openbmc/' IPL_FLAG_FILE = 'host@0-ipl-complete' PORT81_SNOOP_FIFO = '/dev/aspeed-lpc-snoop0' PORT82_SNOOP_FIFO = '/dev/aspeed-lpc-snoop1' HOST_STATUS_RUNNING = "xyz.openbmc_project.State.Host.HostState.Running" IPL_SBE_START_ISTEP_MAJOR = 0 IPL_SBE_START_ISTEP_MINOR = 1 IPL_SBE_DONE_ISTEP_MAJOR = 5 IPL_SBE_DONE_ISTEP_MINOR = 2 IPL_HOSTBOOT_START_ISTEP_MAJOR = 6 IPL_HOSTBOOT_START_ISTEP_MINOR = 0 IPL_COMPLETE_ISTEP_MAJOR = 21 IPL_COMPLETE_ISTEP_MINOR = 3 SKIBOOT_RUNNING_ISTEP_MAJOR = 192 SKIBOOT_RUNNING_ISTEP_MINOR = 12 KERNEL_RUNNING_ISTEP_MAJOR = 240 KERNEL_RUNNING_ISTEP_MINOR = 16 KERNEL_COMPLETE_ISTEP_MAJOR = 254 KERNEL_COMPLETE_ISTEP_MINOR = 254 class IPLStatus(DbusProperties, DbusObjectManager): def __init__(self, bus, obj_name): super(IPLStatus, self).__init__( conn=bus, object_path=obj_name) self.bus = bus self.prev_access_fail_count = 0 self.activateMonitoring = False self.activateMonitoringPrev = False self.last_status = "" self.last_istep = "" self.current_istep_major = 0 self.current_istep_minor = 0 self.port_81_fifo = None self.port_82_fifo = None if not os.path.exists(IPL_FLAG_DIR): os.makedirs(IPL_FLAG_DIR) host_state_dev = self.bus.get_object("xyz.openbmc_project.State.Host", u'/xyz/openbmc_project/state/host0') host_state_iface = dbus.Interface(host_state_dev, 'org.freedesktop.DBus.Properties') host_state_value = host_state_iface.Get("xyz.openbmc_project.State.Host", "CurrentHostState") if host_state_value is not None: power_ctrl_flag = self.getChassisPowerRequestFlag() # FIXME # If this service is restarted after the host has completed IPL, we have no way # of knowing this. If the host has not completed IPL, then running the following # commands will probably cause a system fault requiring manual intervention to clear # (i.e. pflash -P GUARD -c once the second CPU faults out) if power_ctrl_flag == 1: self.current_istep_major = KERNEL_COMPLETE_ISTEP_MAJOR self.current_istep_minor = KERNEL_COMPLETE_ISTEP_MAJOR self.activateMonitoringPrev = True self.activateMonitoring = True if (host_state_value != HOST_STATUS_RUNNING) and (self.activateMonitoring == True): host_state_iface.Set("xyz.openbmc_project.State.Host", "CurrentHostState", HOST_STATUS_RUNNING) self.Set(DBUS_NAME, "current_istep", "") self.Set(DBUS_NAME, "current_status", "UNKNOWN") bus.add_signal_receiver( self.HostStatusChangeHandler, dbus_interface="org.freedesktop.DBus.Properties", signal_name="PropertiesChanged", path=u'/xyz/openbmc_project/state/host0') gobject.timeout_add(50, self.readIPLStatus) print "IPLStatus Init Done" def getChassisPowerRequestFlag(self): result = 0 try: proc = subprocess.Popen(["i2cget -y 12 0x31 0x7"], stdout=subprocess.PIPE, stderr=open(os.devnull, 'wb'), shell=True) (out, err) = proc.communicate() result = (int(out, 16) & 2) >> 1 except: pass return result def readIPLStatus(self): try: # Set up defaults current_status = "OFFLINE" current_istep = "" sbe_istep_major = 0 sbe_istep_minor = 0 if (self.activateMonitoring == False): # Publish offline status if (self.last_status != current_status): self.Set(DBUS_NAME, "current_status", current_status) self.IPLStatusChanged(current_status) self.last_status = current_status if (self.last_istep != current_istep): self.Set(DBUS_NAME, "current_istep", current_istep) self.IPLStepChanged(current_istep) self.last_istep = current_istep self.activateMonitoringPrev = self.activateMonitoring return True; if (self.activateMonitoring == True) and (self.activateMonitoringPrev == False): if (self.port_81_fifo is None): self.port_81_fifo = os.open(PORT81_SNOOP_FIFO, os.O_RDONLY | os.O_NONBLOCK, 0); if (self.port_82_fifo is None): self.port_82_fifo = os.open(PORT82_SNOOP_FIFO, os.O_RDONLY | os.O_NONBLOCK, 0); # Drain FIFOs while True: try: os.read(self.port_81_fifo, 1) except: break while True: try: os.read(self.port_82_fifo, 1) except: break current_status = "IPL_RUNNING" self.current_istep_major = IPL_SBE_START_ISTEP_MAJOR self.current_istep_minor = IPL_SBE_START_ISTEP_MINOR current_istep = str(self.current_istep_major) + "," + str(self.current_istep_minor) self.Set(DBUS_NAME, "current_istep", current_istep) self.IPLStepChanged(current_istep) self.last_istep = current_istep elif (self.activateMonitoring == False) and (self.activateMonitoringPrev == True): # Close FIFOs if still open if (self.port_81_fifo is not None): os.close(self.port_81_fifo); self.port_81_fifo = None; if (self.port_82_fifo is not None): os.close(self.port_82_fifo); self.port_82_fifo = None; self.current_istep_major = 0 self.current_istep_minor = 0 # Check for output if (self.port_82_fifo is not None): all_lines_processed = False while all_lines_processed == False: istep_major = None istep_minor = None try: value = os.read(self.port_82_fifo, 1) istep_minor = int(hexlify(value), 16) except: all_lines_processed = True if not all_lines_processed: try: value = os.read(self.port_81_fifo, 1) istep_major = int(hexlify(value), 16) except: all_lines_processed = True if not all_lines_processed: if (istep_major != None) and (istep_minor != None): # Figure out system status self.current_istep_major = istep_major self.current_istep_minor = istep_minor # Assemble status strings current_istep = str(self.current_istep_major) + "," + str(self.current_istep_minor) current_status = "OFFLINE" if ((self.current_istep_major > 0) or (self.current_istep_minor > 0 )): current_status = "IPL_RUNNING" if (self.current_istep_major >= IPL_COMPLETE_ISTEP_MAJOR): # Monitor remainder of IPL for completion if (self.current_istep_major == KERNEL_COMPLETE_ISTEP_MAJOR) and (self.current_istep_minor == KERNEL_COMPLETE_ISTEP_MINOR): current_status = "IPL_COMPLETE" # Check for status changes if (self.last_status != current_status): if (current_status == "IPL_COMPLETE"): # Signal systemd that IPL is complete try: with open(IPL_FLAG_DIR + IPL_FLAG_FILE, 'a'): os.utime(IPL_FLAG_DIR + IPL_FLAG_FILE, None) systemd_emit_dev = self.bus.get_object("org.freedesktop.systemd1", u"/org/freedesktop/systemd1") systemd_emit_iface = dbus.Interface(systemd_emit_dev, 'org.freedesktop.systemd1.Manager') systemd_emit_function = getattr(systemd_emit_iface, 'StartUnit') systemd_emit_function.call_async('obmc-host-ipl-complete@0.target', 'replace') except Exception as e: pass else: try: os.remove(IPL_FLAG_DIR + IPL_FLAG_FILE) except: pass # Publish status if (self.last_status != current_status): self.Set(DBUS_NAME, "current_status", current_status) self.IPLStatusChanged(current_status) self.last_status = current_status if (self.last_istep != current_istep): self.Set(DBUS_NAME, "current_istep", current_istep) self.IPLStepChanged(current_istep) self.last_istep = current_istep self.activateMonitoringPrev = self.activateMonitoring return True except Exception as e: print(e) traceback.print_exc() self.activateMonitoringPrev = self.activateMonitoring return True def HostStatusChangeHandler(self, interface_name, changed_properties, invalidated_properties): value = changed_properties.get('CurrentHostState') if value is not None: if (value == HOST_STATUS_RUNNING): self.activateMonitoring = True else: # Close FIFOs if still open if (self.port_81_fifo is not None): os.close(self.port_81_fifo); self.port_81_fifo = None; if (self.port_82_fifo is not None): os.close(self.port_82_fifo); self.port_82_fifo = None; self.current_istep_major = 0 self.current_istep_minor = 0 # Remove IPL complete flag if present try: os.remove(IPL_FLAG_DIR + IPL_FLAG_FILE) except: pass self.activateMonitoring = False @dbus.service.method(DBUS_NAME, in_signature='', out_signature='s') def getCurrentIPLStatus(self): return self.Get(DBUS_NAME, "current_status") @dbus.service.signal(DBUS_NAME) def IPLStatusChanged(self, message): # Signal is emitted on method return pass @dbus.service.method(DBUS_NAME, in_signature='', out_signature='s') def getCurrentIPLIStep(self): return self.Get(DBUS_NAME, "current_istep") @dbus.service.signal(DBUS_NAME) def IPLStepChanged(self, message): # Signal is emitted on method return pass def NewObjectHandler(self, obj_path, iprops, bus_name=None): current_istep = self.Get(DBUS_NAME, "current_istep") if obj_path in System.EXIT_STATE_DEPEND[current_istep]: print "New object: "+obj_path+" ("+bus_name+")" if __name__ == '__main__': dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) bus = get_dbus() obj = IPLStatus(bus, OBJ_NAME) mainloop = gobject.MainLoop() obj.unmask_signals() name = dbus.service.BusName(DBUS_NAME, bus) print "Running IPLStatus" mainloop.run() # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4