blob: d5b3404df7de6a8af84892ab121a3d772b3211b1 [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
ratagupta6f6bff2016-04-04 06:20:11 -05007
8//Defines
9#define SET_PARM_VERSION 1
10#define SET_PARM_BOOT_FLAGS_PERMANENT 0x40 //boot flags data1 7th bit on
11#define SET_PARM_BOOT_FLAGS_VALID_ONE_TIME 0x80 //boot flags data1 8th bit on
12#define SET_PARM_BOOT_FLAGS_VALID_PERMANENT 0xC0 //boot flags data1 7 & 8 bit on
13
14
15
vishwa36993272015-11-20 12:43:49 -060016// OpenBMC Chassis Manager dbus framework
17const char *chassis_bus_name = "org.openbmc.control.Chassis";
18const char *chassis_object_name = "/org/openbmc/control/chassis0";
19const char *chassis_intf_name = "org.openbmc.control.Chassis";
20
shgoupfd84fbbf2015-12-17 10:05:51 +080021
Adriana Kobylak40814c62015-10-27 15:58:44 -050022void register_netfn_chassis_functions() __attribute__((constructor));
23
shgoupfd84fbbf2015-12-17 10:05:51 +080024// Host settings in dbus
25// Service name should be referenced by connection name got via object mapper
26const char *settings_object_name = "/org/openbmc/settings/host0";
27const char *settings_intf_name = "org.freedesktop.DBus.Properties";
28const char *host_intf_name = "org.openbmc.settings.Host";
29
30const char *objmapper_service_name = "org.openbmc.objectmapper";
31const char *objmapper_object_name = "/org/openbmc/objectmapper/objectmapper";
32const char *objmapper_intf_name = "org.openbmc.objectmapper.ObjectMapper";
33
34int object_mapper_get_connection(char **buf, const char *obj_path)
35{
36 sd_bus_error error = SD_BUS_ERROR_NULL;
37 sd_bus_message *m = NULL;
38 sd_bus *bus = NULL;
39 char *temp_buf = NULL, *intf = NULL;
40 size_t buf_size = 0;
41 int r;
42
43 // Get the system bus where most system services are provided.
44 bus = ipmid_get_sd_bus_connection();
45
46 /*
47 * Bus, service, object path, interface and method are provided to call
48 * the method.
49 * Signatures and input arguments are provided by the arguments at the
50 * end.
51 */
52 r = sd_bus_call_method(bus,
53 objmapper_service_name, /* service to contact */
54 objmapper_object_name, /* object path */
55 objmapper_intf_name, /* interface name */
56 "GetObject", /* method name */
57 &error, /* object to return error in */
58 &m, /* return message on success */
59 "s", /* input signature */
60 obj_path /* first argument */
61 );
62
63 if (r < 0) {
64 fprintf(stderr, "Failed to issue method call: %s\n", error.message);
65 goto finish;
66 }
67
68 // Get the key, aka, the connection name
69 sd_bus_message_read(m, "a{sas}", 1, &temp_buf, 1, &intf);
70
71 /*
72 * TODO: check the return code. Currently for no reason the message
73 * parsing of object mapper is always complaining about
74 * "Device or resource busy", but the result seems OK for now. Need
75 * further checks.
76 * TODO: The following code is preserved in the comments so that it can be
77 * resumed after the problem aforementioned is resolved.
78 *r = sd_bus_message_read(m, "a{sas}", 1, &temp_buf, 1, &intf);
79 *if (r < 0) {
80 * fprintf(stderr, "Failed to parse response message: %s\n", strerror(-r));
81 * goto finish;
82 *}
83 */
84
85 buf_size = strlen(temp_buf) + 1;
86 printf("IPMID connection name: %s\n", temp_buf);
87 *buf = (char *)malloc(buf_size);
88
89 if (*buf == NULL) {
90 fprintf(stderr, "Malloc failed for get_sys_boot_options");
91 r = -1;
92 goto finish;
93 }
94
95 memcpy(*buf, temp_buf, buf_size);
96
97finish:
98 sd_bus_error_free(&error);
99 sd_bus_message_unref(m);
100
101 return r;
102}
103
ratagupta6f6bff2016-04-04 06:20:11 -0500104int dbus_get_property(const char *name, char **buf)
shgoupfd84fbbf2015-12-17 10:05:51 +0800105{
106 sd_bus_error error = SD_BUS_ERROR_NULL;
107 sd_bus_message *m = NULL;
108 sd_bus *bus = NULL;
109 char *temp_buf = NULL;
110 char *connection = NULL;
111 int r;
112
113 r = object_mapper_get_connection(&connection, settings_object_name);
114
115 if (r < 0) {
116 fprintf(stderr, "Failed to get connection, return value: %d.\n", r);
117 goto finish;
118 }
119
120 printf("connection: %s\n", connection);
121
122 // Get the system bus where most system services are provided.
123 bus = ipmid_get_sd_bus_connection();
124
125 /*
126 * Bus, service, object path, interface and method are provided to call
127 * the method.
128 * Signatures and input arguments are provided by the arguments at the
129 * end.
130 */
131 r = sd_bus_call_method(bus,
132 connection, /* service to contact */
133 settings_object_name, /* object path */
134 settings_intf_name, /* interface name */
135 "Get", /* method name */
136 &error, /* object to return error in */
137 &m, /* return message on success */
138 "ss", /* input signature */
139 host_intf_name, /* first argument */
ratagupta6f6bff2016-04-04 06:20:11 -0500140 name); /* second argument */
shgoupfd84fbbf2015-12-17 10:05:51 +0800141
142 if (r < 0) {
143 fprintf(stderr, "Failed to issue method call: %s\n", error.message);
144 goto finish;
145 }
146
147 /*
148 * The output should be parsed exactly the same as the output formatting
149 * specified.
150 */
151 r = sd_bus_message_read(m, "v", "s", &temp_buf);
152 if (r < 0) {
153 fprintf(stderr, "Failed to parse response message: %s\n", strerror(-r));
154 goto finish;
155 }
156
157 asprintf(buf, "%s", temp_buf);
158/* *buf = (char*) malloc(strlen(temp_buf));
159 if (*buf) {
160 strcpy(*buf, temp_buf);
161 }
162*/
163 printf("IPMID boot option property get: {%s}.\n", (char *) temp_buf);
164
165finish:
166 sd_bus_error_free(&error);
167 sd_bus_message_unref(m);
168 free(connection);
169
170 return r;
171}
172
ratagupta6f6bff2016-04-04 06:20:11 -0500173int dbus_set_property(const char * name, const char *value)
shgoupfd84fbbf2015-12-17 10:05:51 +0800174{
175 sd_bus_error error = SD_BUS_ERROR_NULL;
176 sd_bus_message *m = NULL;
177 sd_bus *bus = NULL;
178 char *connection = NULL;
179 int r;
180
181 r = object_mapper_get_connection(&connection, settings_object_name);
182
183 if (r < 0) {
184 fprintf(stderr, "Failed to get connection, return value: %d.\n", r);
185 goto finish;
186 }
187
188 printf("connection: %s\n", connection);
189
190 // Get the system bus where most system services are provided.
191 bus = ipmid_get_sd_bus_connection();
192
193 /*
194 * Bus, service, object path, interface and method are provided to call
195 * the method.
196 * Signatures and input arguments are provided by the arguments at the
197 * end.
198 */
199 r = sd_bus_call_method(bus,
200 connection, /* service to contact */
201 settings_object_name, /* object path */
202 settings_intf_name, /* interface name */
203 "Set", /* method name */
204 &error, /* object to return error in */
205 &m, /* return message on success */
206 "ssv", /* input signature */
207 host_intf_name, /* first argument */
ratagupta6f6bff2016-04-04 06:20:11 -0500208 name, /* second argument */
shgoupfd84fbbf2015-12-17 10:05:51 +0800209 "s", /* third argument */
ratagupta6f6bff2016-04-04 06:20:11 -0500210 value); /* fourth argument */
shgoupfd84fbbf2015-12-17 10:05:51 +0800211
212 if (r < 0) {
213 fprintf(stderr, "Failed to issue method call: %s\n", error.message);
214 goto finish;
215 }
216
ratagupta6f6bff2016-04-04 06:20:11 -0500217 printf("IPMID boot option property set: {%s}.\n", value);
shgoupfd84fbbf2015-12-17 10:05:51 +0800218
219finish:
220 sd_bus_error_free(&error);
221 sd_bus_message_unref(m);
222 free(connection);
223
224 return r;
225}
226
Adriana Kobylak40814c62015-10-27 15:58:44 -0500227struct get_sys_boot_options_t {
228 uint8_t parameter;
229 uint8_t set;
230 uint8_t block;
231} __attribute__ ((packed));
232
shgoupfd84fbbf2015-12-17 10:05:51 +0800233struct get_sys_boot_options_response_t {
234 uint8_t version;
235 uint8_t parm;
236 uint8_t data[5];
237} __attribute__ ((packed));
238
239struct set_sys_boot_options_t {
240 uint8_t parameter;
241 uint8_t data[8];
242} __attribute__ ((packed));
243
Adriana Kobylak40814c62015-10-27 15:58:44 -0500244ipmi_ret_t ipmi_chassis_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
245 ipmi_request_t request, ipmi_response_t response,
246 ipmi_data_len_t data_len, ipmi_context_t context)
247{
248 printf("Handling CHASSIS WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
249 // Status code.
250 ipmi_ret_t rc = IPMI_CC_OK;
251 *data_len = 0;
252 return rc;
253}
254
vishwa36993272015-11-20 12:43:49 -0600255//------------------------------------------------------------
256// Calls into Chassis Control Dbus object to do the power off
257//------------------------------------------------------------
Chris Austen7888c4d2015-12-03 15:26:20 -0600258int ipmi_chassis_power_control(const char *method)
vishwa36993272015-11-20 12:43:49 -0600259{
260 // sd_bus error
261 int rc = 0;
262
263 // SD Bus error report mechanism.
264 sd_bus_error bus_error = SD_BUS_ERROR_NULL;
265
266 // Response from the call. Although there is no response for this call,
267 // obligated to mention this to make compiler happy.
268 sd_bus_message *response = NULL;
269
270 // Gets a hook onto either a SYSTEM or SESSION bus
271 sd_bus *bus_type = ipmid_get_sd_bus_connection();
272
273 rc = sd_bus_call_method(bus_type, // On the System Bus
274 chassis_bus_name, // Service to contact
275 chassis_object_name, // Object path
276 chassis_intf_name, // Interface name
Chris Austen7888c4d2015-12-03 15:26:20 -0600277 method, // Method to be called
vishwa36993272015-11-20 12:43:49 -0600278 &bus_error, // object to return error
279 &response, // Response buffer if any
280 NULL); // No input arguments
281 if(rc < 0)
282 {
283 fprintf(stderr,"ERROR initiating Power Off:[%s]\n",bus_error.message);
284 }
285 else
286 {
287 printf("Chassis Power Off initiated successfully\n");
288 }
289
290 sd_bus_error_free(&bus_error);
291 sd_bus_message_unref(response);
292
293 return rc;
294}
295
Chris Austen7888c4d2015-12-03 15:26:20 -0600296
vishwa36993272015-11-20 12:43:49 -0600297//----------------------------------------------------------------------
298// Chassis Control commands
299//----------------------------------------------------------------------
300ipmi_ret_t ipmi_chassis_control(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
301 ipmi_request_t request, ipmi_response_t response,
302 ipmi_data_len_t data_len, ipmi_context_t context)
303{
304 // Error from power off.
305 int rc = 0;
306
307 // No response for this command.
308 *data_len = 0;
309
310 // Catch the actual operaton by peeking into request buffer
311 uint8_t chassis_ctrl_cmd = *(uint8_t *)request;
312 printf("Chassis Control Command: Operation:[0x%X]\n",chassis_ctrl_cmd);
313
314 switch(chassis_ctrl_cmd)
315 {
316 case CMD_POWER_OFF:
Chris Austen7888c4d2015-12-03 15:26:20 -0600317 rc = ipmi_chassis_power_control("powerOff");
vishwa36993272015-11-20 12:43:49 -0600318 break;
Chris Austen7888c4d2015-12-03 15:26:20 -0600319 case CMD_HARD_RESET:
320 rc = ipmi_chassis_power_control("reboot");
321 break;
vishwa36993272015-11-20 12:43:49 -0600322 default:
323 {
324 fprintf(stderr, "Invalid Chassis Control command:[0x%X] received\n",chassis_ctrl_cmd);
325 rc = -1;
326 }
327 }
328
329 return ( (rc < 0) ? IPMI_CC_INVALID : IPMI_CC_OK);
330}
331
shgoupfd84fbbf2015-12-17 10:05:51 +0800332struct bootOptionTypeMap_t {
333 uint8_t ipmibootflag;
334 char dbusname[8];
335};
336
337#define INVALID_STRING "Invalid"
338// dbus supports this list of boot devices.
339bootOptionTypeMap_t g_bootOptionTypeMap_t[] = {
340
341 {0x01, "Network"},
342 {0x02, "Disk"},
343 {0x03, "Safe"},
344 {0x05, "CDROM"},
345 {0x06, "Setup"},
346 {0x00, "Default"},
347 {0xFF, INVALID_STRING}
348};
349
350uint8_t get_ipmi_boot_option(char *p) {
351
352 bootOptionTypeMap_t *s = g_bootOptionTypeMap_t;
353
354 while (s->ipmibootflag != 0xFF) {
355 if (!strcmp(s->dbusname,p))
356 break;
357 s++;
358 }
359
360 if (!s->ipmibootflag)
361 printf("Failed to find Sensor Type %s\n", p);
362
363 return s->ipmibootflag;
364}
365
366char* get_boot_option_by_ipmi(uint8_t p) {
367
368 bootOptionTypeMap_t *s = g_bootOptionTypeMap_t;
369
370 while (s->ipmibootflag != 0xFF) {
371
372 if (s->ipmibootflag == p)
373 break;
374
375 s++;
376 }
377
378
379 if (!s->ipmibootflag)
380 printf("Failed to find Sensor Type 0x%x\n", p);
381
382 return s->dbusname;
383}
384
Adriana Kobylak40814c62015-10-27 15:58:44 -0500385ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
386 ipmi_request_t request, ipmi_response_t response,
387 ipmi_data_len_t data_len, ipmi_context_t context)
388{
shgoupfd84fbbf2015-12-17 10:05:51 +0800389 ipmi_ret_t rc = IPMI_CC_PARM_NOT_SUPPORTED;
390 char *p = NULL;
391 get_sys_boot_options_response_t *resp = (get_sys_boot_options_response_t *) response;
392 get_sys_boot_options_t *reqptr = (get_sys_boot_options_t*) request;
393 uint8_t s;
Adriana Kobylak40814c62015-10-27 15:58:44 -0500394
395 printf("IPMI GET_SYS_BOOT_OPTIONS\n");
396
shgoupfd84fbbf2015-12-17 10:05:51 +0800397 memset(resp,0,sizeof(*resp));
398 resp->version = SET_PARM_VERSION;
399 resp->parm = 5;
ratagupta6f6bff2016-04-04 06:20:11 -0500400 resp->data[0] = SET_PARM_BOOT_FLAGS_VALID_ONE_TIME;
Adriana Kobylak40814c62015-10-27 15:58:44 -0500401
shgoupfd84fbbf2015-12-17 10:05:51 +0800402 *data_len = sizeof(*resp);
Adriana Kobylak40814c62015-10-27 15:58:44 -0500403
shgoupfd84fbbf2015-12-17 10:05:51 +0800404 /*
405 * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc.
406 * This is the only parameter used by petitboot.
407 */
408 if (reqptr->parameter == 5) {
409
ratagupta6f6bff2016-04-04 06:20:11 -0500410 /* Get the boot device */
411 int r = dbus_get_property("boot_flags",&p);
shgoupfd84fbbf2015-12-17 10:05:51 +0800412
413 if (r < 0) {
ratagupta6f6bff2016-04-04 06:20:11 -0500414 fprintf(stderr, "Dbus get property(boot_flags) failed for get_sys_boot_options.\n");
shgoupfd84fbbf2015-12-17 10:05:51 +0800415 rc = IPMI_CC_UNSPECIFIED_ERROR;
416
417 } else {
418
419 s = get_ipmi_boot_option(p);
420 resp->data[1] = (s << 2);
421 rc = IPMI_CC_OK;
ratagupta6f6bff2016-04-04 06:20:11 -0500422
shgoupfd84fbbf2015-12-17 10:05:51 +0800423 }
424
ratagupta6f6bff2016-04-04 06:20:11 -0500425 if (p)
426 {
427 free(p);
428 p = NULL;
429 }
430
431 /* Get the boot policy */
432 r = dbus_get_property("boot_policy",&p);
433
434 if (r < 0) {
435 fprintf(stderr, "Dbus get property(boot_policy) failed for get_sys_boot_options.\n");
436 rc = IPMI_CC_UNSPECIFIED_ERROR;
437
438 } else {
439
440 printf("BootPolicy is[%s]", p);
441 resp->data[0] = (strncmp(p,"ONETIME",strlen("ONETIME"))==0) ?
442 SET_PARM_BOOT_FLAGS_VALID_ONE_TIME:
443 SET_PARM_BOOT_FLAGS_VALID_PERMANENT;
444 rc = IPMI_CC_OK;
445
446 }
447
448
shgoupfd84fbbf2015-12-17 10:05:51 +0800449 } else {
Adriana Kobylak40814c62015-10-27 15:58:44 -0500450 fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter);
shgoupfd84fbbf2015-12-17 10:05:51 +0800451 }
452
453 if (p)
454 free(p);
455
456 return rc;
457}
458
459
460
461ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
462 ipmi_request_t request, ipmi_response_t response,
463 ipmi_data_len_t data_len, ipmi_context_t context)
464{
465 ipmi_ret_t rc = IPMI_CC_OK;
466 char *s;
467
468 printf("IPMI SET_SYS_BOOT_OPTIONS\n");
469
470 set_sys_boot_options_t *reqptr = (set_sys_boot_options_t *) request;
471
472 // This IPMI command does not have any resposne data
473 *data_len = 0;
474
475 /* 000101
476 * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc.
477 * This is the only parameter used by petitboot.
478 */
479 if (reqptr->parameter == 5) {
480
481 s = get_boot_option_by_ipmi(((reqptr->data[1] & 0x3C) >> 2));
482
483 printf("%d: %s\n", __LINE__, s);
484 if (!strcmp(s,INVALID_STRING)) {
485
486 rc = IPMI_CC_PARM_NOT_SUPPORTED;
487
488 } else {
489
ratagupta6f6bff2016-04-04 06:20:11 -0500490 int r = dbus_set_property("boot_flags",s);
shgoupfd84fbbf2015-12-17 10:05:51 +0800491
492 if (r < 0) {
ratagupta6f6bff2016-04-04 06:20:11 -0500493 fprintf(stderr, "Dbus set property(boot_flags) failed for set_sys_boot_options.\n");
shgoupfd84fbbf2015-12-17 10:05:51 +0800494 rc = IPMI_CC_UNSPECIFIED_ERROR;
495 }
496 }
ratagupta6f6bff2016-04-04 06:20:11 -0500497
498 /* setting the boot policy */
499 s = (char *)(((reqptr->data[0] & SET_PARM_BOOT_FLAGS_PERMANENT) ==
500 SET_PARM_BOOT_FLAGS_PERMANENT) ?"PERMANENT":"ONETIME");
501
502 printf ( "\nBoot Policy is %s",s);
503 int r = dbus_set_property("boot_policy",s);
504
505 if (r < 0) {
506 fprintf(stderr, "Dbus set property(boot_policy) failed for set_sys_boot_options.\n");
507 rc = IPMI_CC_UNSPECIFIED_ERROR;
508 }
shgoupfd84fbbf2015-12-17 10:05:51 +0800509
510 } else {
511 fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter);
512 rc = IPMI_CC_PARM_NOT_SUPPORTED;
Adriana Kobylak40814c62015-10-27 15:58:44 -0500513 }
514
515 return rc;
516}
517
518void register_netfn_chassis_functions()
519{
520 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_WILDCARD);
521 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_WILDCARD, NULL, ipmi_chassis_wildcard);
522
523 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_GET_SYS_BOOT_OPTIONS);
524 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 -0500525
vishwa36993272015-11-20 12:43:49 -0600526 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_CHASSIS_CONTROL);
527 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_CHASSIS_CONTROL, NULL, ipmi_chassis_control);
shgoupfd84fbbf2015-12-17 10:05:51 +0800528
529 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_CHASSIS, IPMI_CMD_SET_SYS_BOOT_OPTIONS);
530 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_SET_SYS_BOOT_OPTIONS, NULL, ipmi_chassis_set_sys_boot_options);
vishwa36993272015-11-20 12:43:49 -0600531}
shgoupfd84fbbf2015-12-17 10:05:51 +0800532