[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