blob: fca3c7931945b5ce2c4dc55174001f51214a8007 [file] [log] [blame]
Adriana Kobylak40814c62015-10-27 15:58:44 -05001#include "chassishandler.h"
2#include "ipmid-api.h"
3#include <stdio.h>
4#include <string.h>
5#include <stdint.h>
6
vishwa36993272015-11-20 12:43:49 -06007// OpenBMC Chassis Manager dbus framework
8const char *chassis_bus_name = "org.openbmc.control.Chassis";
9const char *chassis_object_name = "/org/openbmc/control/chassis0";
10const char *chassis_intf_name = "org.openbmc.control.Chassis";
11
shgoupfd84fbbf2015-12-17 10:05:51 +080012
Adriana Kobylak40814c62015-10-27 15:58:44 -050013void register_netfn_chassis_functions() __attribute__((constructor));
14
shgoupfd84fbbf2015-12-17 10:05:51 +080015// Host settings in dbus
16// Service name should be referenced by connection name got via object mapper
17const char *settings_object_name = "/org/openbmc/settings/host0";
18const char *settings_intf_name = "org.freedesktop.DBus.Properties";
19const char *host_intf_name = "org.openbmc.settings.Host";
20
21const char *objmapper_service_name = "org.openbmc.objectmapper";
22const char *objmapper_object_name = "/org/openbmc/objectmapper/objectmapper";
23const char *objmapper_intf_name = "org.openbmc.objectmapper.ObjectMapper";
24
25int object_mapper_get_connection(char **buf, const char *obj_path)
26{
27 sd_bus_error error = SD_BUS_ERROR_NULL;
28 sd_bus_message *m = NULL;
29 sd_bus *bus = NULL;
30 char *temp_buf = NULL, *intf = NULL;
31 size_t buf_size = 0;
32 int r;
33
34 // Get the system bus where most system services are provided.
35 bus = ipmid_get_sd_bus_connection();
36
37 /*
38 * Bus, service, object path, interface and method are provided to call
39 * the method.
40 * Signatures and input arguments are provided by the arguments at the
41 * end.
42 */
43 r = sd_bus_call_method(bus,
44 objmapper_service_name, /* service to contact */
45 objmapper_object_name, /* object path */
46 objmapper_intf_name, /* interface name */
47 "GetObject", /* method name */
48 &error, /* object to return error in */
49 &m, /* return message on success */
50 "s", /* input signature */
51 obj_path /* first argument */
52 );
53
54 if (r < 0) {
55 fprintf(stderr, "Failed to issue method call: %s\n", error.message);
56 goto finish;
57 }
58
59 // Get the key, aka, the connection name
60 sd_bus_message_read(m, "a{sas}", 1, &temp_buf, 1, &intf);
61
62 /*
63 * TODO: check the return code. Currently for no reason the message
64 * parsing of object mapper is always complaining about
65 * "Device or resource busy", but the result seems OK for now. Need
66 * further checks.
67 * TODO: The following code is preserved in the comments so that it can be
68 * resumed after the problem aforementioned is resolved.
69 *r = sd_bus_message_read(m, "a{sas}", 1, &temp_buf, 1, &intf);
70 *if (r < 0) {
71 * fprintf(stderr, "Failed to parse response message: %s\n", strerror(-r));
72 * goto finish;
73 *}
74 */
75
76 buf_size = strlen(temp_buf) + 1;
77 printf("IPMID connection name: %s\n", temp_buf);
78 *buf = (char *)malloc(buf_size);
79
80 if (*buf == NULL) {
81 fprintf(stderr, "Malloc failed for get_sys_boot_options");
82 r = -1;
83 goto finish;
84 }
85
86 memcpy(*buf, temp_buf, buf_size);
87
88finish:
89 sd_bus_error_free(&error);
90 sd_bus_message_unref(m);
91
92 return r;
93}
94
95int dbus_get_property(char **buf)
96{
97 sd_bus_error error = SD_BUS_ERROR_NULL;
98 sd_bus_message *m = NULL;
99 sd_bus *bus = NULL;
100 char *temp_buf = NULL;
101 char *connection = NULL;
102 int r;
103
104 r = object_mapper_get_connection(&connection, settings_object_name);
105
106 if (r < 0) {
107 fprintf(stderr, "Failed to get connection, return value: %d.\n", r);
108 goto finish;
109 }
110
111 printf("connection: %s\n", connection);
112
113 // Get the system bus where most system services are provided.
114 bus = ipmid_get_sd_bus_connection();
115
116 /*
117 * Bus, service, object path, interface and method are provided to call
118 * the method.
119 * Signatures and input arguments are provided by the arguments at the
120 * end.
121 */
122 r = sd_bus_call_method(bus,
123 connection, /* service to contact */
124 settings_object_name, /* object path */
125 settings_intf_name, /* interface name */
126 "Get", /* method name */
127 &error, /* object to return error in */
128 &m, /* return message on success */
129 "ss", /* input signature */
130 host_intf_name, /* first argument */
131 "boot_flags"); /* second argument */
132
133 if (r < 0) {
134 fprintf(stderr, "Failed to issue method call: %s\n", error.message);
135 goto finish;
136 }
137
138 /*
139 * The output should be parsed exactly the same as the output formatting
140 * specified.
141 */
142 r = sd_bus_message_read(m, "v", "s", &temp_buf);
143 if (r < 0) {
144 fprintf(stderr, "Failed to parse response message: %s\n", strerror(-r));
145 goto finish;
146 }
147
148 asprintf(buf, "%s", temp_buf);
149/* *buf = (char*) malloc(strlen(temp_buf));
150 if (*buf) {
151 strcpy(*buf, temp_buf);
152 }
153*/
154 printf("IPMID boot option property get: {%s}.\n", (char *) temp_buf);
155
156finish:
157 sd_bus_error_free(&error);
158 sd_bus_message_unref(m);
159 free(connection);
160
161 return r;
162}
163
164int dbus_set_property(const char *buf)
165{
166 sd_bus_error error = SD_BUS_ERROR_NULL;
167 sd_bus_message *m = NULL;
168 sd_bus *bus = NULL;
169 char *connection = NULL;
170 int r;
171
172 r = object_mapper_get_connection(&connection, settings_object_name);
173
174 if (r < 0) {
175 fprintf(stderr, "Failed to get connection, return value: %d.\n", r);
176 goto finish;
177 }
178
179 printf("connection: %s\n", connection);
180
181 // Get the system bus where most system services are provided.
182 bus = ipmid_get_sd_bus_connection();
183
184 /*
185 * Bus, service, object path, interface and method are provided to call
186 * the method.
187 * Signatures and input arguments are provided by the arguments at the
188 * end.
189 */
190 r = sd_bus_call_method(bus,
191 connection, /* service to contact */
192 settings_object_name, /* object path */
193 settings_intf_name, /* interface name */
194 "Set", /* method name */
195 &error, /* object to return error in */
196 &m, /* return message on success */
197 "ssv", /* input signature */
198 host_intf_name, /* first argument */
199 "boot_flags", /* second argument */
200 "s", /* third argument */
201 buf); /* fourth argument */
202
203 if (r < 0) {
204 fprintf(stderr, "Failed to issue method call: %s\n", error.message);
205 goto finish;
206 }
207
208 printf("IPMID boot option property set: {%s}.\n", buf);
209
210finish:
211 sd_bus_error_free(&error);
212 sd_bus_message_unref(m);
213 free(connection);
214
215 return r;
216}
217
Adriana Kobylak40814c62015-10-27 15:58:44 -0500218struct get_sys_boot_options_t {
219 uint8_t parameter;
220 uint8_t set;
221 uint8_t block;
222} __attribute__ ((packed));
223
shgoupfd84fbbf2015-12-17 10:05:51 +0800224struct get_sys_boot_options_response_t {
225 uint8_t version;
226 uint8_t parm;
227 uint8_t data[5];
228} __attribute__ ((packed));
229
230struct set_sys_boot_options_t {
231 uint8_t parameter;
232 uint8_t data[8];
233} __attribute__ ((packed));
234
Adriana Kobylak40814c62015-10-27 15:58:44 -0500235ipmi_ret_t ipmi_chassis_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
236 ipmi_request_t request, ipmi_response_t response,
237 ipmi_data_len_t data_len, ipmi_context_t context)
238{
239 printf("Handling CHASSIS WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
240 // Status code.
241 ipmi_ret_t rc = IPMI_CC_OK;
242 *data_len = 0;
243 return rc;
244}
245
vishwa36993272015-11-20 12:43:49 -0600246//------------------------------------------------------------
247// Calls into Chassis Control Dbus object to do the power off
248//------------------------------------------------------------
Chris Austen7888c4d2015-12-03 15:26:20 -0600249int ipmi_chassis_power_control(const char *method)
vishwa36993272015-11-20 12:43:49 -0600250{
251 // sd_bus error
252 int rc = 0;
253
254 // SD Bus error report mechanism.
255 sd_bus_error bus_error = SD_BUS_ERROR_NULL;
256
257 // Response from the call. Although there is no response for this call,
258 // obligated to mention this to make compiler happy.
259 sd_bus_message *response = NULL;
260
261 // Gets a hook onto either a SYSTEM or SESSION bus
262 sd_bus *bus_type = ipmid_get_sd_bus_connection();
263
264 rc = sd_bus_call_method(bus_type, // On the System Bus
265 chassis_bus_name, // Service to contact
266 chassis_object_name, // Object path
267 chassis_intf_name, // Interface name
Chris Austen7888c4d2015-12-03 15:26:20 -0600268 method, // Method to be called
vishwa36993272015-11-20 12:43:49 -0600269 &bus_error, // object to return error
270 &response, // Response buffer if any
271 NULL); // No input arguments
272 if(rc < 0)
273 {
274 fprintf(stderr,"ERROR initiating Power Off:[%s]\n",bus_error.message);
275 }
276 else
277 {
278 printf("Chassis Power Off initiated successfully\n");
279 }
280
281 sd_bus_error_free(&bus_error);
282 sd_bus_message_unref(response);
283
284 return rc;
285}
286
Chris Austen7888c4d2015-12-03 15:26:20 -0600287
vishwa36993272015-11-20 12:43:49 -0600288//----------------------------------------------------------------------
289// Chassis Control commands
290//----------------------------------------------------------------------
291ipmi_ret_t ipmi_chassis_control(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
292 ipmi_request_t request, ipmi_response_t response,
293 ipmi_data_len_t data_len, ipmi_context_t context)
294{
295 // Error from power off.
296 int rc = 0;
297
298 // No response for this command.
299 *data_len = 0;
300
301 // Catch the actual operaton by peeking into request buffer
302 uint8_t chassis_ctrl_cmd = *(uint8_t *)request;
303 printf("Chassis Control Command: Operation:[0x%X]\n",chassis_ctrl_cmd);
304
305 switch(chassis_ctrl_cmd)
306 {
307 case CMD_POWER_OFF:
Chris Austen7888c4d2015-12-03 15:26:20 -0600308 rc = ipmi_chassis_power_control("powerOff");
vishwa36993272015-11-20 12:43:49 -0600309 break;
Chris Austen7888c4d2015-12-03 15:26:20 -0600310 case CMD_HARD_RESET:
311 rc = ipmi_chassis_power_control("reboot");
312 break;
vishwa36993272015-11-20 12:43:49 -0600313 default:
314 {
315 fprintf(stderr, "Invalid Chassis Control command:[0x%X] received\n",chassis_ctrl_cmd);
316 rc = -1;
317 }
318 }
319
320 return ( (rc < 0) ? IPMI_CC_INVALID : IPMI_CC_OK);
321}
322
shgoupfd84fbbf2015-12-17 10:05:51 +0800323struct bootOptionTypeMap_t {
324 uint8_t ipmibootflag;
325 char dbusname[8];
326};
327
328#define INVALID_STRING "Invalid"
329// dbus supports this list of boot devices.
330bootOptionTypeMap_t g_bootOptionTypeMap_t[] = {
331
332 {0x01, "Network"},
333 {0x02, "Disk"},
334 {0x03, "Safe"},
335 {0x05, "CDROM"},
336 {0x06, "Setup"},
337 {0x00, "Default"},
338 {0xFF, INVALID_STRING}
339};
340
341uint8_t get_ipmi_boot_option(char *p) {
342
343 bootOptionTypeMap_t *s = g_bootOptionTypeMap_t;
344
345 while (s->ipmibootflag != 0xFF) {
346 if (!strcmp(s->dbusname,p))
347 break;
348 s++;
349 }
350
351 if (!s->ipmibootflag)
352 printf("Failed to find Sensor Type %s\n", p);
353
354 return s->ipmibootflag;
355}
356
357char* get_boot_option_by_ipmi(uint8_t p) {
358
359 bootOptionTypeMap_t *s = g_bootOptionTypeMap_t;
360
361 while (s->ipmibootflag != 0xFF) {
362
363 if (s->ipmibootflag == p)
364 break;
365
366 s++;
367 }
368
369
370 if (!s->ipmibootflag)
371 printf("Failed to find Sensor Type 0x%x\n", p);
372
373 return s->dbusname;
374}
375
376#define SET_PARM_VERSION 1
377#define SET_PARM_BOOT_FLAGS_VALID 0x80
378
Adriana Kobylak40814c62015-10-27 15:58:44 -0500379ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
380 ipmi_request_t request, ipmi_response_t response,
381 ipmi_data_len_t data_len, ipmi_context_t context)
382{
shgoupfd84fbbf2015-12-17 10:05:51 +0800383 ipmi_ret_t rc = IPMI_CC_PARM_NOT_SUPPORTED;
384 char *p = NULL;
385 get_sys_boot_options_response_t *resp = (get_sys_boot_options_response_t *) response;
386 get_sys_boot_options_t *reqptr = (get_sys_boot_options_t*) request;
387 uint8_t s;
Adriana Kobylak40814c62015-10-27 15:58:44 -0500388
389 printf("IPMI GET_SYS_BOOT_OPTIONS\n");
390
shgoupfd84fbbf2015-12-17 10:05:51 +0800391 memset(resp,0,sizeof(*resp));
392 resp->version = SET_PARM_VERSION;
393 resp->parm = 5;
394 resp->data[0] = SET_PARM_BOOT_FLAGS_VALID;
Adriana Kobylak40814c62015-10-27 15:58:44 -0500395
shgoupfd84fbbf2015-12-17 10:05:51 +0800396 *data_len = sizeof(*resp);
Adriana Kobylak40814c62015-10-27 15:58:44 -0500397
shgoupfd84fbbf2015-12-17 10:05:51 +0800398 /*
399 * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc.
400 * This is the only parameter used by petitboot.
401 */
402 if (reqptr->parameter == 5) {
403
404 int r = dbus_get_property(&p);
405
406 if (r < 0) {
407 fprintf(stderr, "Dbus get property failed for get_sys_boot_options.\n");
408 rc = IPMI_CC_UNSPECIFIED_ERROR;
409
410 } else {
411
412 s = get_ipmi_boot_option(p);
413 resp->data[1] = (s << 2);
414 rc = IPMI_CC_OK;
415 }
416
417 } else {
Adriana Kobylak40814c62015-10-27 15:58:44 -0500418 fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter);
shgoupfd84fbbf2015-12-17 10:05:51 +0800419 }
420
421 if (p)
422 free(p);
423
424 return rc;
425}
426
427
428
429ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
430 ipmi_request_t request, ipmi_response_t response,
431 ipmi_data_len_t data_len, ipmi_context_t context)
432{
433 ipmi_ret_t rc = IPMI_CC_OK;
434 char *s;
435
436 printf("IPMI SET_SYS_BOOT_OPTIONS\n");
437
438 set_sys_boot_options_t *reqptr = (set_sys_boot_options_t *) request;
439
440 // This IPMI command does not have any resposne data
441 *data_len = 0;
442
443 /* 000101
444 * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc.
445 * This is the only parameter used by petitboot.
446 */
447 if (reqptr->parameter == 5) {
448
449 s = get_boot_option_by_ipmi(((reqptr->data[1] & 0x3C) >> 2));
450
451 printf("%d: %s\n", __LINE__, s);
452 if (!strcmp(s,INVALID_STRING)) {
453
454 rc = IPMI_CC_PARM_NOT_SUPPORTED;
455
456 } else {
457
458 int r = dbus_set_property(s);
459
460 if (r < 0) {
461 fprintf(stderr, "Dbus set property failed for set_sys_boot_options.\n");
462 rc = IPMI_CC_UNSPECIFIED_ERROR;
463 }
464 }
465
466 } else {
467 fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter);
468 rc = IPMI_CC_PARM_NOT_SUPPORTED;
Adriana Kobylak40814c62015-10-27 15:58:44 -0500469 }
470
471 return rc;
472}
473
474void register_netfn_chassis_functions()
475{
476 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_WILDCARD);
477 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_WILDCARD, NULL, ipmi_chassis_wildcard);
478
479 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_GET_SYS_BOOT_OPTIONS);
480 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_SYS_BOOT_OPTIONS, NULL, ipmi_chassis_get_sys_boot_options);
Adriana Kobylak40814c62015-10-27 15:58:44 -0500481
vishwa36993272015-11-20 12:43:49 -0600482 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_CHASSIS_CONTROL);
483 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_CHASSIS_CONTROL, NULL, ipmi_chassis_control);
shgoupfd84fbbf2015-12-17 10:05:51 +0800484
485 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_CHASSIS, IPMI_CMD_SET_SYS_BOOT_OPTIONS);
486 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_SET_SYS_BOOT_OPTIONS, NULL, ipmi_chassis_set_sys_boot_options);
vishwa36993272015-11-20 12:43:49 -0600487}
shgoupfd84fbbf2015-12-17 10:05:51 +0800488