From patchwork Mon Dec 3 03:00:34 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sam Mendoza-Jonas X-Patchwork-Id: 1006633 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 437VBS19myz9s9G for ; Mon, 3 Dec 2018 14:01:20 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=mendozajonas.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=mendozajonas.com header.i=@mendozajonas.com header.b="Q1i/aXGZ"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="D/vHvC5P"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 437VBR5lXKzDqYP for ; Mon, 3 Dec 2018 14:01:19 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=mendozajonas.com Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=mendozajonas.com header.i=@mendozajonas.com header.b="Q1i/aXGZ"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="D/vHvC5P"; dkim-atps=neutral X-Original-To: petitboot@lists.ozlabs.org Delivered-To: petitboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=mendozajonas.com (client-ip=66.111.4.28; helo=out4-smtp.messagingengine.com; envelope-from=sam@mendozajonas.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=mendozajonas.com Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=mendozajonas.com header.i=@mendozajonas.com header.b="Q1i/aXGZ"; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="D/vHvC5P"; dkim-atps=neutral Received: from out4-smtp.messagingengine.com (out4-smtp.messagingengine.com [66.111.4.28]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 437VB201fFzDqXq for ; Mon, 3 Dec 2018 14:00:57 +1100 (AEDT) Received: from compute2.internal (compute2.nyi.internal [10.202.2.42]) by mailout.nyi.internal (Postfix) with ESMTP id 213BD21FC1; Sun, 2 Dec 2018 22:00:52 -0500 (EST) Received: from mailfrontend2 ([10.202.2.163]) by compute2.internal (MEProxy); Sun, 02 Dec 2018 22:00:52 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= mendozajonas.com; h=from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; s=fm1; bh=cDgdhIf4kte2vZxfaop3tIOemcZQl4+FIf39qgTvKSU=; b=Q1i/a XGZgG187iTv3PXDmMGuC9SfXETBfvtnGgc0gyo5h4cpzNO5MemdmeezF0DUzfSyU 6nSwrdVQ7Y4wbilT/82ByYZ+2EFZiKvxDchJj7bP3PiUrbTvh4OkPjQ8XJYbaOjh OdL6NL7lyXoUYOl4hPCgIFKawXyIlHxMznMlH+SpfIK1oj515CLkxb3Vaz8Byorb J5X3e+O8pfbp13V7+to8ROj9WidjmbAmE3UNEX43achcD1ioieqaPs6xl6gDNL8z fj7qNso2yRUi71sAQ1nQf9KmPofFlUZrV+fZ9ByYRJsSWbqNhRWQKAMoILD5joLb GSdD2PMOjmu2YJbAQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; bh=cDgdhIf4kte2vZxfaop3tIOemcZQl4+FIf39qgTvKSU=; b=D/vHvC5P wIf2Uck2DHoExj52Zv2toB8yb+aN87KUz7Du94T/uh9CC5A5aGuf6hH+SliLkvRS qXWaCOqMwAIB5n48CLl+kFDbUp8piIODidnzET0d1BL6i8lH49mZbQtMADeElE6X sKUdZDTP+yLUZZZ66yI3S0FsxWJry1KzNA9lex24vjysD2aYvWt2Ozt7fprXMrSk wx5RWiTKiDQfiF6zOBeutLrIWPsBPu8fpCvuEm/D74g19Q5iLGzwBYpaV4nzjSBN A+8YZmVKd92lTxrHTtYDbDFZxM2qQIQmiurEOlQMdpeQylMpyCrL0+Bckrdd7UB/ eoCXzAIHAWl3yw== X-ME-Sender: X-ME-Proxy: Received: from v4.ozlabs.ibm.com (unknown [122.99.82.10]) by mail.messagingengine.com (Postfix) with ESMTPA id F035B1039F; Sun, 2 Dec 2018 22:00:49 -0500 (EST) From: Samuel Mendoza-Jonas To: petitboot@lists.ozlabs.org Subject: [PATCH 2/3] utils: Add helper to send mailbox request Date: Mon, 3 Dec 2018 14:00:34 +1100 Message-Id: <20181203030035.26487-2-sam@mendozajonas.com> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181203030035.26487-1-sam@mendozajonas.com> References: <20181203030035.26487-1-sam@mendozajonas.com> MIME-Version: 1.0 X-BeenThere: petitboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Petitboot bootloader development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Samuel Mendoza-Jonas Errors-To: petitboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Petitboot" A simple script to set, display, and clear a BMC's boot initiator mailbox. Signed-off-by: Samuel Mendoza-Jonas --- utils/ipmi-mailbox-config.py | 167 +++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100755 utils/ipmi-mailbox-config.py diff --git a/utils/ipmi-mailbox-config.py b/utils/ipmi-mailbox-config.py new file mode 100755 index 00000000..b1060797 --- /dev/null +++ b/utils/ipmi-mailbox-config.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python3 + +import argparse +import subprocess + +def send_block_read_command(hostname, username, password, index, dry_run): + + if hostname is None and dry_run: + hostname = "" + + cmd = "ipmitool -I lanplus -H " + hostname + if username is not None: + cmd = cmd + " -U " + username + if password is not None: + cmd = cmd + " -P " + password + + # chassis netfn, get-sys-boot-options, parameter 7, set-sel, block-sel + cmd = cmd + " raw 0x00 0x09 0x07 " + hex(index) + " 0x00 " + + print(cmd) + if not dry_run: + rc = subprocess.call(cmd, shell=True) + if rc != 0: + print("Command returned error: {}".format(rc)) + +def send_block_command(hostname, username, password, block, index, dry_run): + + if hostname is None and dry_run: + hostname = "" + + cmd = "ipmitool -I lanplus -H " + hostname + if username is not None: + cmd = cmd + " -U " + username + if password is not None: + cmd = cmd + " -P " + password + + # chassis netfn, set-sys-boot-options, parameter 7, set-sel, block-sel + cmd = cmd + " raw 0x00 0x08 0x07 " + hex(index) + " " + block + + print(cmd) + if not dry_run: + rc = subprocess.call(cmd, shell=True) + if rc != 0: + print("Command returned error: {}".format(rc)) + +def construct_buffer(config, max_blocks): + + # Add IBM's IANA prefix + raw = bytes([0x02, 0x00, 0x00]) + config.encode('ascii') + + n_blocks = int(len(raw) / 16) + if len(raw) % 16 != 0: + n_blocks += 1 + + if n_blocks > 16: + print("ERROR: buffer would require {} blocks" + + "which is more than allowed (16)".format(n_blocks)) + return None + + if n_blocks > max_blocks: + print("ERROR: buffer would require {} blocks" + + "which is more than max_blocks ({})".format(n_blocks, max_blocks)) + return None + + if n_blocks > 5: + print("Warning: buffer would require {} blocks" + + "which is more than some BMCs support".format(n_blocks)) + + + blocks = [] + rem = len(raw) + for i in range(n_blocks): + block = "" + if rem >= 16: + last = 16 + else: + last = rem + + for j in range(16): + if j < last: + block += "{:#02x} ".format(raw[i * 16 + j]) + else: + # Pad out to 16 bytes + block += "0x00 " + + + blocks.append(block) + rem -= last + + if n_blocks < max_blocks: + for i in range(max_blocks - n_blocks): + blocks.append("0x00 0x00 0x00 0x00 " + + "0x00 0x00 0x00 0x00 " + + "0x00 0x00 0x00 0x00 " + + "0x00 0x00 0x00 0x00") + + return blocks + +def construct_empty_buffer(max_blocks): + + blocks = [] + for i in range(max_blocks): + blocks.append("0x00 0x00 0x00 0x00 " + + "0x00 0x00 0x00 0x00 " + + "0x00 0x00 0x00 0x00 " + + "0x00 0x00 0x00 0x00") + + return blocks + +def main(): + + parser = argparse.ArgumentParser() + parser.add_argument("-b", "--bmc-hostname") + parser.add_argument("-u", "--username") + parser.add_argument("-p", "--password") + parser.add_argument("-n", "--dry-run", action="store_true") + parser.add_argument("-c", "--config") + parser.add_argument("-x", "--clear", action="store_true") + parser.add_argument("-d", "--dump", action="store_true") + parser.add_argument("-m", "--max-blocks") + + args = parser.parse_args() + + if not args.dry_run and args.bmc_hostname is None: + print("No hostname specified!") + return -1 + + if args.config and args.clear: + print("Can't specify --config and --clear together") + return -1 + + if args.max_blocks: + n_blocks = int(args.max_blocks) + else: + n_blocks = 16 + + + if args.config or args.clear: + if args.config: + blocks = construct_buffer(args.config, int(args.max_blocks)) + if args.clear: + blocks = construct_empty_buffer(int(args.max_blocks)) + if blocks is None: + print("Failed to construct buffer") + return -1 + + print("{} blocks to send".format(len(blocks))) + print("---------------------------------------") + for i in range(len(blocks)): + try: + send_block_command(args.bmc_hostname, args.username, args.password, + blocks[i], i, args.dry_run) + except Exception as e: + print(e) + print("Error sending block {}".format(i)) + return -1 + i += 1 + + if args.dump: + print("\nReading {} blocks".format(n_blocks)) + print("---------------------------------------") + for i in range(n_blocks): + send_block_read_command(args.bmc_hostname, args.username, + args.password, i, args.dry_run) + +if __name__ == "__main__": + main()