[PATCH phosphor-host-ipmid v2] IPMI soft power off
Norman James
njames at us.ibm.com
Sun Nov 22 09:55:56 AEDT 2015
Softpoweroff is a method on chassis0. What dbus obj are u talking about?
Sent from my iPhone
> On Nov 21, 2015, at 12:43 PM, Chris Austen <austenc at us.ibm.com> wrote:
>
> what makes SoftPowerOff different enough to have its own dbus object? Shouldn't the soft power off simple be another method in the /or/openbmc/chassis/chassis0 interface?
>
>
>
> Chris Austen
> POWER Systems Enablement Manager
> (512) 286-5184 (T/L: 363-5184)
>
>
> ----- Original message -----
> From: OpenBMC Patches <openbmc-patches at stwcx.xyz>
> Sent by: "openbmc" <openbmc-bounces+austenc=us.ibm.com at lists.ozlabs.org>
> To: openbmc at lists.ozlabs.org
> Cc:
> Subject: [PATCH phosphor-host-ipmid v2] IPMI soft power off
> Date: Sat, Nov 21, 2015 12:10 PM
>
> From: vishwa <vishwanath at in.ibm.com>
>
> ---
> Makefile | 5 +--
> apphandler.C | 67 +++++++++++++++++++++++++++++--
> apphandler.h | 33 ++++++++++++++-
> chassishandler.C | 85 ++++++++++++++++++++++++++++++++++++++-
> chassishandler.h | 15 +++++++
> host-services.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> host-services.h | 3 ++
> ipmid-api.h | 4 +-
> ipmid.C | 6 ++-
> ipmid.H | 1 +
> 10 files changed, 325 insertions(+), 13 deletions(-)
> create mode 100644 host-services.c
> create mode 100644 host-services.h
>
> diff --git a/Makefile b/Makefile
> index 1a37c0f..1851c9f 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -5,8 +5,7 @@ TESTER = testit
> TESTADDSEL = testaddsel
>
> DAEMON = ipmid
> -DAEMON_OBJ = $(DAEMON).o
> -
> +DAEMON_OBJ = ipmid.o host-services.o
>
> LIB_APP_OBJ = apphandler.o \
> sensorhandler.o \
> @@ -28,7 +27,7 @@ LIB_APP = libapphandler.so
> INSTALLED_LIBS += $(LIB_APP)
> INSTALLED_HEADERS = ipmid-api.h
>
> -INC_FLAG += $(shell pkg-config --cflags --libs libsystemd) -I. -O2
> +INC_FLAG += $(shell pkg-config --cflags --libs libsystemd) -I. -O2
> LIB_FLAG += $(shell pkg-config --libs libsystemd) -rdynamic
> IPMID_PATH ?= -DHOST_IPMI_LIB_PATH=\"/usr/lib/host-ipmid/\"
>
> diff --git a/apphandler.C b/apphandler.C
> index 6467397..d3df330 100644
> --- a/apphandler.C
> +++ b/apphandler.C
> @@ -10,19 +10,75 @@ extern sd_bus *bus;
>
> void register_netfn_app_functions() __attribute__((constructor));
>
> +//---------------------------------------------------------------------
> +// Called by Host on seeing a SMS_ATN bit set. Return a hardcoded
> +// value of 0x2 indicating we need Host read some data.
> +//-------------------------------------------------------------------
> +ipmi_ret_t ipmi_app_get_msg_flags(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
> + ipmi_request_t request, ipmi_response_t response,
> + ipmi_data_len_t data_len, ipmi_context_t context)
> +{
> + // Generic return from IPMI commands.
> + ipmi_ret_t rc = IPMI_CC_OK;
> +
> + printf("IPMI APP GET MSG FLAGS returning with [bit:2] set\n");
> +
> + // From IPMI spec V2.0 for Get Message Flags Command :
> + // bit:[1] from LSB : 1b = Event Message Buffer Full.
> + // Return as 0 if Event Message Buffer is not supported,
> + // or when the Event Message buffer is disabled.
> + // TODO. For now. assume its not disabled and send "0x2" anyway:
> +
> + uint8_t set_event_msg_buffer_full = 0x2;
> + *data_len = sizeof(set_event_msg_buffer_full);
> +
> + // Pack the actual response
> + memcpy(response, &set_event_msg_buffer_full, *data_len);
> +
> + return rc;
> +}
>
> +//-------------------------------------------------------------------
> +// Called by Host post response from Get_Message_Flags
> +//-------------------------------------------------------------------
> ipmi_ret_t ipmi_app_read_event(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
> ipmi_request_t request, ipmi_response_t response,
> ipmi_data_len_t data_len, ipmi_context_t context)
> {
> ipmi_ret_t rc = IPMI_CC_OK;
> - *data_len = 0;
> + printf("IPMI APP READ EVENT command received\n");
>
> - printf("IPMI APP READ EVENT Ignoring for now\n");
> - return rc;
> + // TODO : For now, this is catering only to the Soft Power Off via OEM SEL
> + // mechanism. If we need to make this generically used for some
> + // other conditions, then we can take advantage of context pointer.
>
> -}
> + struct oem_sel_timestamped soft_off = {0};
> + *data_len = sizeof(struct oem_sel_timestamped);
> +
> + // either id[0] -or- id[1] can be filled in. We will use id[0]
> + soft_off.id[0] = SEL_OEM_ID_0;
> + soft_off.id[1] = SEL_OEM_ID_0;
> + soft_off.type = SEL_RECORD_TYPE_OEM;
> +
> + // Following 3 bytes are from IANA Manufactre_Id field. See below
> + soft_off.manuf_id[0]= 0x41;
> + soft_off.manuf_id[1]= 0xA7;
> + soft_off.manuf_id[2]= 0x00;
> +
> + // per IPMI spec NetFuntion for OEM
> + soft_off.netfun = 0x3A;
>
> + // Mechanism to kick start soft shutdown.
> + soft_off.cmd = CMD_POWER;
> + soft_off.data[0] = SOFT_OFF;
> +
> + // All '0xFF' since unused.
> + memset(&soft_off.data[1], 0xFF, 3);
> +
> + // Pack the actual response
> + memcpy(response, &soft_off, *data_len);
> + return rc;
> +}
>
> ipmi_ret_t ipmi_app_set_acpi_power_state(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
> ipmi_request_t request, ipmi_response_t response,
> @@ -359,6 +415,9 @@ void register_netfn_app_functions()
> ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_BMC_GLOBAL_ENABLES, NULL,
> ipmi_app_set_bmc_global_enables);
>
> + printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_APP, IPMI_CMD_GET_MSG_FLAGS);
> + ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_MSG_FLAGS, NULL, ipmi_app_get_msg_flags);
> +
> return;
> }
>
> diff --git a/apphandler.h b/apphandler.h
> index 35a2b20..aa2a55d 100644
> --- a/apphandler.h
> +++ b/apphandler.h
> @@ -1,6 +1,19 @@
> #ifndef __HOST_IPMI_APP_HANDLER_H__
> #define __HOST_IPMI_APP_HANDLER_H__
>
> +#include <stdint.h>
> +
> +// These are per skiboot ipmi-sel code
> +
> +// OEM_SEL type with Timestamp
> +#define SEL_OEM_ID_0 0x55
> +// SEL type is OEM and -not- general SEL
> +#define SEL_RECORD_TYPE_OEM 0xC0
> +// Minor command for soft shurdown
> +#define SOFT_OFF 0x00
> +// Major command for Any kind of power ops
> +#define CMD_POWER 0x04
> +
> // IPMI commands for App net functions.
> enum ipmi_netfn_app_cmds
> {
> @@ -11,9 +24,27 @@ enum ipmi_netfn_app_cmds
> IPMI_CMD_RESET_WD = 0x22,
> IPMI_CMD_SET_WD = 0x24,
> IPMI_CMD_SET_BMC_GLOBAL_ENABLES = 0x2E,
> + IPMI_CMD_GET_MSG_FLAGS = 0x31,
> IPMI_CMD_READ_EVENT = 0x35,
> IPMI_CMD_GET_CAP_BIT = 0x36,
> -
> };
>
> +// A Mechanism to tell host to shtudown hosts by sending this PEM SEL. Really
> +// the only used fields by skiboot are:
> +// id[0] / id[1] for ID_0 , ID_1
> +// type : SEL_RECORD_TYPE_OEM as standard SELs are ignored by skiboot
> +// cmd : CMD_POWER for power functions
> +// data[0], specific commands. example Soft power off. power cycle, etc.
> +struct oem_sel_timestamped
> +{
> + /* SEL header */
> + uint8_t id[2];
> + uint8_t type;
> + uint8_t manuf_id[3];
> + uint8_t timestamp[4];
> + /* OEM SEL data (6 bytes) follows */
> + uint8_t netfun;
> + uint8_t cmd;
> + uint8_t data[4];
> +};
> #endif
> diff --git a/chassishandler.C b/chassishandler.C
> index d00a124..56b8375 100644
> --- a/chassishandler.C
> +++ b/chassishandler.C
> @@ -4,6 +4,11 @@
> #include <string.h>
> #include <stdint.h>
>
> +// OpenBMC Chassis Manager dbus framework
> +const char *chassis_bus_name = "org.openbmc.control.Chassis";
> +const char *chassis_object_name = "/org/openbmc/control/chassis0";
> +const char *chassis_intf_name = "org.openbmc.control.Chassis";
> +
> void register_netfn_chassis_functions() __attribute__((constructor));
>
> struct get_sys_boot_options_t {
> @@ -23,6 +28,82 @@ ipmi_ret_t ipmi_chassis_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
> return rc;
> }
>
> +//------------------------------------------------------------
> +// Calls into Chassis Control Dbus object to do the power off
> +//------------------------------------------------------------
> +int ipmi_chassis_power_off()
> +{
> + // sd_bus error
> + int rc = 0;
> +
> + // SD Bus error report mechanism.
> + sd_bus_error bus_error = SD_BUS_ERROR_NULL;
> +
> + // Response from the call. Although there is no response for this call,
> + // obligated to mention this to make compiler happy.
> + sd_bus_message *response = NULL;
> +
> + // Gets a hook onto either a SYSTEM or SESSION bus
> + sd_bus *bus_type = ipmid_get_sd_bus_connection();
> +
> + rc = sd_bus_call_method(bus_type, // On the System Bus
> + chassis_bus_name, // Service to contact
> + chassis_object_name, // Object path
> + chassis_intf_name, // Interface name
> + "powerOff", // Method to be called
> + &bus_error, // object to return error
> + &response, // Response buffer if any
> + NULL); // No input arguments
> + if(rc < 0)
> + {
> + fprintf(stderr,"ERROR initiating Power Off:[%s]\n",bus_error.message);
> + }
> + else
> + {
> + printf("Chassis Power Off initiated successfully\n");
> + }
> +
> + sd_bus_error_free(&bus_error);
> + sd_bus_message_unref(response);
> +
> + return rc;
> +}
> +
> +//----------------------------------------------------------------------
> +// Chassis Control commands
> +//----------------------------------------------------------------------
> +ipmi_ret_t ipmi_chassis_control(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
> + ipmi_request_t request, ipmi_response_t response,
> + ipmi_data_len_t data_len, ipmi_context_t context)
> +{
> + // Error from power off.
> + int rc = 0;
> +
> + // No response for this command.
> + *data_len = 0;
> +
> + // Catch the actual operaton by peeking into request buffer
> + uint8_t chassis_ctrl_cmd = *(uint8_t *)request;
> + printf("Chassis Control Command: Operation:[0x%X]\n",chassis_ctrl_cmd);
> +
> + switch(chassis_ctrl_cmd)
> + {
> + case CMD_POWER_OFF:
> + case CMD_HARD_RESET:
> + {
> + rc = ipmi_chassis_power_off();
> + break;
> + }
> + default:
> + {
> + fprintf(stderr, "Invalid Chassis Control command:[0x%X] received\n",chassis_ctrl_cmd);
> + rc = -1;
> + }
> + }
> +
> + return ( (rc < 0) ? IPMI_CC_INVALID : IPMI_CC_OK);
> +}
> +
> ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
> ipmi_request_t request, ipmi_response_t response,
> ipmi_data_len_t data_len, ipmi_context_t context)
> @@ -58,5 +139,7 @@ void register_netfn_chassis_functions()
>
> printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_GET_SYS_BOOT_OPTIONS);
> ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_SYS_BOOT_OPTIONS, NULL, ipmi_chassis_get_sys_boot_options);
> -}
>
> + printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_CHASSIS_CONTROL);
> + ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_CHASSIS_CONTROL, NULL, ipmi_chassis_control);
> +}
> diff --git a/chassishandler.h b/chassishandler.h
> index 99ed366..1a26411 100644
> --- a/chassishandler.h
> +++ b/chassishandler.h
> @@ -1,9 +1,13 @@
> #ifndef __HOST_IPMI_CHASSIS_HANDLER_H__
> #define __HOST_IPMI_CHASSIS_HANDLER_H__
>
> +#include <stdint.h>
> +
> // IPMI commands for Chassis net functions.
> enum ipmi_netfn_app_cmds
> {
> + // Chassis Control
> + IPMI_CMD_CHASSIS_CONTROL = 0x02,
> // Get capability bits
> IPMI_CMD_GET_SYS_BOOT_OPTIONS = 0x09,
> };
> @@ -14,4 +18,15 @@ enum ipmi_chassis_return_codes
> IPMI_CC_PARM_NOT_SUPPORTED = 0x80,
> };
>
> +// Various Chassis operations under a single command.
> +enum ipmi_chassis_control_cmds : uint8_t
> +{
> + CMD_POWER_OFF = 0x00,
> + CMD_POWER_ON = 0x01,
> + CMD_POWER_CYCLE = 0x02,
> + CMD_HARD_RESET = 0x03,
> + CMD_PULSE_DIAGNOSTIC_INTR = 0x04,
> + CMD_SOFT_OFF_VIA_OVER_TEMP = 0x05,
> +};
> +
> #endif
> diff --git a/host-services.c b/host-services.c
> new file mode 100644
> index 0000000..89f0b6c
> --- /dev/null
> +++ b/host-services.c
> @@ -0,0 +1,119 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <errno.h>
> +#include <systemd/sd-bus.h>
> +
> +// OpenBMC Host IPMI dbus framework
> +const char *bus_name = "org.openbmc.HostIpmi";
> +const char *object_name = "/org/openbmc/HostIpmi/1";
> +const char *intf_name = "org.openbmc.HostIpmi";
> +
> +//-------------------------------------------------------------------
> +// Gets called by PowerOff handler when a Soft Power off is requested
> +//-------------------------------------------------------------------
> +static int soft_power_off(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
> +{
> + int64_t bt_resp = -1;
> + int rc = 0;
> +
> + // Steps to be taken when we get this.
> + // 1: Send a SMS_ATN to the Host
> + // 2: Host receives it and sends a GetMsgFlags IPMI command
> + // 3: IPMID app handler will respond to that with a MSgFlag with bit:0x2
> + // set indicating we have a message for Host
> + // 4: Host sends a GetMsgBuffer command and app handler will respond to
> + // that with a OEM-SEL with certain fields packed indicating to the
> + // host that it do a shutdown of the partitions.
> + // 5: Host does the partition shutdown and calls Chassis Power off command
> + // 6: App handler handles the command by making a call to ChassisManager
> + // Dbus
> +
> + // Now the job is to send the SMS_ATTN.
> +
> + // Req message contains the specifics about which method etc that we want to
> + // access on which bus, object
> + sd_bus_message *response = NULL;
> +
> + // Error return mechanism
> + sd_bus_error bus_error = SD_BUS_ERROR_NULL;
> +
> + // Gets a hook onto either a SYSTEM or SESSION bus
> + sd_bus *bus = (sd_bus *)ipmid_get_sd_bus_connection();
> +
> + rc = sd_bus_call_method(bus, // On the System Bus
> + bus_name, // Service to contact
> + object_name, // Object path
> + intf_name, // Interface name
> + "setAttention", // Method to be called
> + &bus_error, // object to return error
> + &response, // Response buffer if any
> + NULL); // No input arguments
> + if(rc < 0)
> + {
> + fprintf(stderr,"ERROR initiating Power Off:[%s]\n",bus_error.message);
> + goto finish;
> + }
> +
> + // See if we were able to successfully raise SMS_ATN
> + rc = sd_bus_message_read(response, "x", &bt_resp);
> + if (rc < 0)
> + {
> + fprintf(stderr, "Failed to get a rc from BT for SMS_ATN: %s\n", strerror(-rc));
> + goto finish;
> + }
> +
> +finish:
> + sd_bus_error_free(&bus_error);
> + sd_bus_message_unref(response);
> +
> + if(rc < 0)
> + {
> + return sd_bus_reply_method_return(m, "x", rc);
> + }
> + else
> + {
> + return sd_bus_reply_method_return(m, "x", bt_resp);
> + }
> +}
> +
> +//-------------------------------------------
> +// Function pointer of APIs exposed via Dbus
> +//-------------------------------------------
> +static const sd_bus_vtable host_services_vtable[] =
> +{
> + SD_BUS_VTABLE_START(0),
> + // Takes No("") arguments -but- returns a value of type 64 bit integer("x")
> + SD_BUS_METHOD("SoftPowerOff", "", "x", &soft_power_off, SD_BUS_VTABLE_UNPRIVILEGED),
> + SD_BUS_VTABLE_END,
> +};
> +
> +//------------------------------------------------------
> +// Called by IPMID as part of the start up
> +// -----------------------------------------------------
> +int start_host_service(sd_bus *bus, sd_bus_slot *slot)
> +{
> + int rc = 0;
> +
> + /* Install the object */
> + rc = sd_bus_add_object_vtable(bus,
> + &slot,
> + "/org/openbmc/HostServices", /* object path */
> + "org.openbmc.HostServices", /* interface name */
> + host_services_vtable,
> + NULL);
> + if (rc < 0)
> + {
> + fprintf(stderr, "Failed to issue method call: %s\n", strerror(-rc));
> + }
> + else
> + {
> + /* Take one in OpenBmc */
> + rc = sd_bus_request_name(bus, "org.openbmc.HostServices", 0);
> + if (rc < 0)
> + {
> + fprintf(stderr, "Failed to acquire service name: %s\n", strerror(-rc));
> + }
> + }
> +
> + return rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
> +}
> diff --git a/host-services.h b/host-services.h
> new file mode 100644
> index 0000000..0d93480
> --- /dev/null
> +++ b/host-services.h
> @@ -0,0 +1,3 @@
> +#include <systemd/sd-bus.h>
> +
> +extern "C" int start_host_service(sd_bus *, sd_bus_slot *);
> diff --git a/ipmid-api.h b/ipmid-api.h
> index 34d3bbe..952dd3f 100644
> --- a/ipmid-api.h
> +++ b/ipmid-api.h
> @@ -53,7 +53,7 @@ typedef ipmi_ret_t (*ipmid_callback_t)(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
> // information of netfn, cmd, callback handler pointer and context data.
> // Making this a extern "C" so that plugin libraries written in C can also use
> // it.
> -extern "C" void ipmi_register_callback(ipmi_netfn_t, ipmi_cmd_t,
> +extern "C" void ipmi_register_callback(ipmi_netfn_t, ipmi_cmd_t,
> ipmi_context_t, ipmid_callback_t);
>
> // These are the command network functions, the response
> @@ -94,5 +94,5 @@ enum ipmi_return_codes
> IPMI_CC_UNSPECIFIED_ERROR = 0xFF,
> };
>
> -sd_bus *ipmid_get_sd_bus_connection(void);
> +extern "C" sd_bus* ipmid_get_sd_bus_connection(void);
> #endif
> diff --git a/ipmid.C b/ipmid.C
> index 6b1eacc..440705c 100644
> --- a/ipmid.C
> +++ b/ipmid.C
> @@ -40,7 +40,6 @@ typedef std::pair<ipmid_callback_t, ipmi_context_t> ipmi_fn_context_t;
> std::map<ipmi_fn_cmd_t, ipmi_fn_context_t> g_ipmid_router_map;
>
>
> -
> #ifndef HEXDUMP_COLS
> #define HEXDUMP_COLS 16
> #endif
> @@ -418,6 +417,10 @@ int main(int argc, char *argv[])
> // Register all the handlers that provider implementation to IPMI commands.
> ipmi_register_callback_handlers(HOST_IPMI_LIB_PATH);
>
> + // Start the Host Services Dbus Objects
> + start_host_service(bus, slot);
> +
> + // Watch for BT messages
> r = sd_bus_add_match(bus, &slot, FILTER, handle_ipmi_command, NULL);
> if (r < 0) {
> fprintf(stderr, "Failed: sd_bus_add_match: %s : %s\n", strerror(-r), FILTER);
> @@ -427,7 +430,6 @@ int main(int argc, char *argv[])
>
> for (;;) {
> /* Process requests */
> -
> r = sd_bus_process(bus, NULL);
> if (r < 0) {
> fprintf(stderr, "Failed to process bus: %s\n", strerror(-r));
> diff --git a/ipmid.H b/ipmid.H
> index 73b60e6..3de2c8c 100644
> --- a/ipmid.H
> +++ b/ipmid.H
> @@ -2,6 +2,7 @@
> #define __HOST_IPMID_IPMI_H__
> #include "ipmid-api.h"
> #include <stdio.h>
> +#include "host-services.h"
>
> // When the requester sends in a netfn and a command along with data, this
> // function will look for registered handlers that will handle that [netfn,cmd]
> --
> 2.6.3
>
>
> _______________________________________________
> openbmc mailing list
> openbmc at lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/openbmc
>
> _______________________________________________
> openbmc mailing list
> openbmc at lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/openbmc
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ozlabs.org/pipermail/openbmc/attachments/20151121/d8fc2355/attachment-0001.html>
More information about the openbmc
mailing list