summaryrefslogtreecommitdiffstats
path: root/host-services.c
blob: b0b12aefc5fc24f08336aa77d8d78ab56cda0135 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <systemd/sd-bus.h>
#include <mapper.h>
#include "host-ipmid/ipmid-api.h"

void register_host_services() __attribute__((constructor));

// OpenBMC Host IPMI dbus framework
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;
    char *bus_name = NULL;

    // 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 = ipmid_get_sd_bus_connection();
    rc = mapper_get_service(bus, object_name, &bus_name);
    if (rc < 0) {
        fprintf(stderr, "Failed to get %s bus name: %s\n",
                object_name, strerror(-rc));
        goto finish;
    }
    rc = sd_bus_call_method(bus,             // In 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);
    response = sd_bus_message_unref(response);
    free(bus_name);

    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;
}

//------------------------------------------------------
// Callback register function
// -----------------------------------------------------
void register_host_services()
{
    // Gets a hook onto SYSTEM bus used by host-ipmid
    sd_bus *bus = ipmid_get_sd_bus_connection();

    // Gets a hook onto SYSTEM bus slot used by host-ipmid
    sd_bus_slot *ipmid_slot = ipmid_get_sd_bus_slot();

    //start_host_service(bus, ipmid_slot);
    start_host_service(bus, ipmid_slot);
}
OpenPOWER on IntegriCloud