diff options
author | Andrew Jeffery <andrew@aj.id.au> | 2017-10-16 14:13:53 +1030 |
---|---|---|
committer | Andrew Jeffery <andrew@aj.id.au> | 2017-10-19 01:33:27 +1030 |
commit | 1be4fabdcb00d17f3b4dc2b563125e661692948d (patch) | |
tree | 546566e93e063d7ae60d033989ad856632817451 /pytools | |
parent | cf6a784d4e78ef77630e19cc73955ad60c244ee6 (diff) | |
download | talos-skeleton-1be4fabdcb00d17f3b4dc2b563125e661692948d.tar.gz talos-skeleton-1be4fabdcb00d17f3b4dc2b563125e661692948d.zip |
pytools: obmcutil: Add `chassiskill` command
Nick reported an issue where the BMC became unusable after the host hit
a bug and began "spewing a lot of messages to the console". Save
ourselves some DBus transactions and immediate execution of systemd
transitions by introducing a `chassiskill` command to directly deassert
the the power-up GPIO ourselves. This will immediately terminate the
host and free up resources for the BMC to become responsive. As a bonus,
the PGOOD monitoring will then execute to clean up the resulting
inconsistent BMC/Host state for us.
Change-Id: I106a4202b6544b8e78b04938230a4eeee5f132bb
Requested-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Diffstat (limited to 'pytools')
-rw-r--r-- | pytools/obmcutil | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/pytools/obmcutil b/pytools/obmcutil index e2b422a..30db80c 100644 --- a/pytools/obmcutil +++ b/pytools/obmcutil @@ -11,6 +11,9 @@ import signal import time from subprocess import Popen +import obmc_system_config +import obmc.system + descriptors = { 'power': { 'bus_name': 'org.openbmc.control.Power', @@ -178,9 +181,79 @@ def run_all_commands(dbus_bus, recipe, args): return True +def gpio_set_value(gpio_name, active_low, asserted): + gpio_id = obmc.system.convertGpio(gpio_name) + gpio_value_path = "/sys/class/gpio/gpio{}/value".format(gpio_id) + + with open(gpio_value_path, 'w') as gpio: + # Inversion behaviour needs to change with the resolution of + # https://github.com/openbmc/openbmc/issues/2489, where properly + # configuring the kernel will allow it to handle the inversion for us. + gpio.write(str(int(asserted ^ active_low))) + + return True + +def gpio_deassert(gpio_name, active_low, args): + # Deal with silly python2 exception handling as outlined in main + if args.verbose: + return gpio_set_value(gpio_name, active_low, False) + + try: + return gpio_set_value(gpio_name, active_low, False) + except IOError as e: + print >> sys.stderr, "Failed to access GPIO {}: {}".format(gpio_name, e.message) + return False + +def run_chassiskill(args): + # We shouldn't be able to invoke run_chassiskill() unless it's been + # explicitly added as a valid command to argparse in main() + assert can_chassiskill() + + # Multi-dimensional fetch is now exception-safe + gpios = obmc_system_config.GPIO_CONFIGS['power_config']['power_up_outs'] + + gc = obmc_system_config.GPIO_CONFIG + + for gpio in gpios: + function = gpio[0] + + if function not in gc or 'gpio_pin' not in gc[function]: + print >> sys.stderr, "Missing or invalid definition for '{}' in system GPIO_CONFIG".format(function) + continue + + name = gc[function]['gpio_pin'] + + # The second element of the tuples stashed in 'power_up_outs' + # represents the boolean condition of the statement 'active high'. To + # mirror the code at [1] we instead need the condition of the statement + # 'active low', thus we negate gpio[1]. + # + # [1] https://github.com/openbmc/skeleton/blob/93b84e42834893313616f96c70743369f26a7190/op-pwrctl/power_control_obj.c#L283 + active_low = not gpio[1] + + if not gpio_deassert(name, active_low, args): + return False + + return True + +def can_chassiskill(): + gcs = obmc_system_config.GPIO_CONFIGS + + if 'power_config' in gcs: + if 'power_up_outs' in gcs['power_config']: + # Just to be sure + return len(gcs['power_config']) > 0 + + return False + def main(): dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + # Conditionally add the `chassiskill` commmand based on whether the + # required GPIO configuration is present in the system description. + if can_chassiskill(): + descriptors['chassiskill'] = None + parser = argparse.ArgumentParser() parser.add_argument('--verbose', '-v', action='store_true', help="Verbose output") @@ -192,6 +265,11 @@ def main(): parser.add_argument('recipe', choices=sorted(descriptors.keys())) args = parser.parse_args() + # This is a special case: directly pull the power, don't do any D-Bus + # related stuff + if args.recipe == "chassiskill": + return run_chassiskill(args) + dbus_bus = dbus.SystemBus() # The only way to get a sensible backtrace with python 2 without stupid |