blob: 91bf2b77e6e7ff4b3f81c8b6537c37ba09bd4283 [file] [log] [blame]
Matthew Barth70dbc582016-09-20 10:16:52 -05001#include "oemhandler.hpp"
Chris Austen4d98c1e2015-10-13 14:33:50 -05002#include <host-ipmid/ipmid-api.h>
Adriana Kobylak187bfce2016-03-04 11:55:43 -06003#include <fstream>
Chris Austen4d98c1e2015-10-13 14:33:50 -05004#include <stdio.h>
5#include <string.h>
Adriana Kobylak187bfce2016-03-04 11:55:43 -06006#include <systemd/sd-bus.h>
Nan Li8a0807a2016-05-24 16:59:24 +08007#include <endian.h>
Chris Austen4d98c1e2015-10-13 14:33:50 -05008
9void register_netfn_oem_partial_esel() __attribute__((constructor));
10
Chris Austenfcafccf2016-02-19 23:15:57 -060011const char *g_esel_path = "/tmp/esel";
Chris Austen29a8e0f2015-10-30 11:44:38 -050012uint16_t g_record_id = 0x0001;
Chris Austen4d98c1e2015-10-13 14:33:50 -050013
Chris Austen4d98c1e2015-10-13 14:33:50 -050014///////////////////////////////////////////////////////////////////////////////
Patrick Williams24fa5a92015-10-30 14:53:57 -050015// For the First partial add eSEL the SEL Record ID and offset
16// value should be 0x0000. The extended data needs to be in
17// the form of an IPMI SEL Event Record, with Event sensor type
18// of 0xDF and Event Message format of 0x04. The returned
Chris Austen4d98c1e2015-10-13 14:33:50 -050019// Record ID should be used for all partial eSEL adds.
20//
Chris Austenba54afb2016-02-19 23:18:42 -060021// This function creates a /tmp/esel file to store the
Chris Austen4d98c1e2015-10-13 14:33:50 -050022// incoming partial esel. It is the role of some other
Patrick Williams24fa5a92015-10-30 14:53:57 -050023// function to commit the error log in to long term
24// storage. Likely via the ipmi add_sel command.
Chris Austen4d98c1e2015-10-13 14:33:50 -050025///////////////////////////////////////////////////////////////////////////////
Patrick Williams24fa5a92015-10-30 14:53:57 -050026ipmi_ret_t ipmi_ibm_oem_partial_esel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Chris Austen17160ce2015-10-30 11:44:38 -050027 ipmi_request_t request, ipmi_response_t response,
28 ipmi_data_len_t data_len, ipmi_context_t context)
Chris Austen4d98c1e2015-10-13 14:33:50 -050029{
Nan Li8a0807a2016-05-24 16:59:24 +080030 uint8_t *reqptr = (uint8_t *) request;
31 esel_request_t esel_req;
Chris Austenba54afb2016-02-19 23:18:42 -060032 FILE *fp;
Nan Lib6c4c562016-03-30 17:06:13 +080033 int r = 0;
Chris Austenba54afb2016-02-19 23:18:42 -060034 uint8_t rlen;
35 ipmi_ret_t rc = IPMI_CC_OK;
36 const char *pio;
Chris Austen4d98c1e2015-10-13 14:33:50 -050037
Nan Li8a0807a2016-05-24 16:59:24 +080038 esel_req.resid = le16toh((((uint16_t) reqptr[1]) << 8) + reqptr[0]);
39 esel_req.selrecord = le16toh((((uint16_t) reqptr[3]) << 8) + reqptr[2]);
40 esel_req.offset = le16toh((((uint16_t) reqptr[5]) << 8) + reqptr[4]);
41 esel_req.progress = reqptr[6];
Nan Lib6c4c562016-03-30 17:06:13 +080042
Nan Li8a0807a2016-05-24 16:59:24 +080043 uint16_t used_res_id = get_sel_reserve_id();
Nan Lib6c4c562016-03-30 17:06:13 +080044
45 // According to IPMI spec, Reservation ID must be checked.
Nan Li8a0807a2016-05-24 16:59:24 +080046 if ( used_res_id != esel_req.resid ) {
Nan Lib6c4c562016-03-30 17:06:13 +080047 // 0xc5 means Reservation Cancelled or Invalid Reservation ID.
48 printf("Used Reservation ID = %d\n", used_res_id);
49 rc = IPMI_CC_INVALID_RESERVATION_ID;
50
Andrew Geisslerd9296052017-06-15 14:57:25 -050051 // clean g_esel_path.
Nan Lib6c4c562016-03-30 17:06:13 +080052 r = remove(g_esel_path);
53 if(r < 0)
54 fprintf(stderr, "Error deleting %s\n", g_esel_path);
55
56 return rc;
57 }
58
59 // OpenPOWER Host Interface spec says if RecordID and Offset are
Chris Austenba54afb2016-02-19 23:18:42 -060060 // 0 then then this is a new request
Nan Li8a0807a2016-05-24 16:59:24 +080061 if (!esel_req.selrecord && !esel_req.offset)
Chris Austenba54afb2016-02-19 23:18:42 -060062 pio = "wb";
63 else
64 pio = "rb+";
Chris Austen4d98c1e2015-10-13 14:33:50 -050065
Chris Austenba54afb2016-02-19 23:18:42 -060066 rlen = (*data_len) - (uint8_t) (sizeof(esel_request_t));
Chris Austen4d98c1e2015-10-13 14:33:50 -050067
Chris Austenba54afb2016-02-19 23:18:42 -060068 if ((fp = fopen(g_esel_path, pio)) != NULL) {
Nan Li8a0807a2016-05-24 16:59:24 +080069 fseek(fp, esel_req.offset, SEEK_SET);
70 fwrite(reqptr+(uint8_t) (sizeof(esel_request_t)), rlen, 1, fp);
Chris Austenba54afb2016-02-19 23:18:42 -060071 fclose(fp);
Chris Austen4d98c1e2015-10-13 14:33:50 -050072
Chris Austenba54afb2016-02-19 23:18:42 -060073 *data_len = sizeof(g_record_id);
74 memcpy(response, &g_record_id, *data_len);
75 } else {
76 fprintf(stderr, "Error trying to perform %s for esel%s\n",pio, g_esel_path);
77 rc = IPMI_CC_INVALID;
78 *data_len = 0;
79 }
Chris Austen4d98c1e2015-10-13 14:33:50 -050080
Chris Austenba54afb2016-02-19 23:18:42 -060081 // The first bit prepresents that this is the last partial packet
82 // coming down. If that is the case advance the record id so we
83 // don't overlap logs. This allows anyone to establish a log
84 // directory system.
Nan Li8a0807a2016-05-24 16:59:24 +080085 if (esel_req.progress & 1 ) {
Chris Austenba54afb2016-02-19 23:18:42 -060086 g_record_id++;
87 }
Chris Austen4d98c1e2015-10-13 14:33:50 -050088
Chris Austenba54afb2016-02-19 23:18:42 -060089 return rc;
Chris Austen4d98c1e2015-10-13 14:33:50 -050090}
91
Adriana Kobylak187bfce2016-03-04 11:55:43 -060092// Prepare for FW Update.
93// Execute needed commands to prepare the system for a fw update from the host.
94ipmi_ret_t ipmi_ibm_oem_prep_fw_update(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
95 ipmi_request_t request, ipmi_response_t response,
96 ipmi_data_len_t data_len, ipmi_context_t context)
97{
98 ipmi_ret_t ipmi_rc = IPMI_CC_OK;
99 *data_len = 0;
100
101 int rc = 0;
102 std::ofstream rwfs_file;
103 const char *busname = "org.openbmc.control.Bmc";
104 const char *objname = "/org/openbmc/control/bmc0";
105 const char *iface = "org.openbmc.control.Bmc";
106 sd_bus *bus = ipmid_get_sd_bus_connection();
107 sd_bus_message *reply = NULL;
108 sd_bus_error error = SD_BUS_ERROR_NULL;
109 int r = 0;
110
111 // Set one time flag
112 rc = system("fw_setenv openbmconce copy-files-to-ram copy-base-filesystem-to-ram");
113 rc = WEXITSTATUS(rc);
114 if (rc != 0) {
115 fprintf(stderr, "fw_setenv openbmconce failed with rc=%d\n", rc);
Andrew Geisslerd9296052017-06-15 14:57:25 -0500116 return IPMI_CC_UNSPECIFIED_ERROR;
Adriana Kobylak187bfce2016-03-04 11:55:43 -0600117 }
118
119 // Touch the image-rwfs file to perform an empty update to force the save
120 // in case we're already in ram and the flash is the same causing the ram files
121 // to not be copied back to flash
122 rwfs_file.open("/run/initramfs/image-rwfs", std::ofstream::out | std::ofstream::app);
123 rwfs_file.close();
124
125 // Reboot the BMC for settings to take effect
126 r = sd_bus_call_method(bus, busname, objname, iface,
127 "warmReset", &error, &reply, NULL);
128 if (r < 0) {
129 fprintf(stderr, "Failed to reset BMC: %s\n", strerror(-r));
130 return -1;
131 }
132 printf("Warning: BMC is going down for reboot!\n");
133 sd_bus_error_free(&error);
134 reply = sd_bus_message_unref(reply);
135
136 return ipmi_rc;
137}
Chris Austen4d98c1e2015-10-13 14:33:50 -0500138
139void register_netfn_oem_partial_esel()
140{
Tomcbfd6ec2016-09-14 17:45:55 +0530141 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_OEM, IPMI_CMD_PESEL);
142 ipmi_register_callback(NETFUN_OEM, IPMI_CMD_PESEL, NULL, ipmi_ibm_oem_partial_esel,
143 SYSTEM_INTERFACE);
Adriana Kobylak187bfce2016-03-04 11:55:43 -0600144
145 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_OEM, IPMI_CMD_PREP_FW_UPDATE);
Tomcbfd6ec2016-09-14 17:45:55 +0530146 ipmi_register_callback(NETFUN_OEM, IPMI_CMD_PREP_FW_UPDATE, NULL, ipmi_ibm_oem_prep_fw_update,
147 SYSTEM_INTERFACE);
Adriana Kobylak187bfce2016-03-04 11:55:43 -0600148
Tomcbfd6ec2016-09-14 17:45:55 +0530149 return;
Chris Austen4d98c1e2015-10-13 14:33:50 -0500150}