blob: aba86e37b3a083fbd3b251682c0f0bd2632ab8df [file] [log] [blame]
Matthew Barth70dbc582016-09-20 10:16:52 -05001#include "oemhandler.hpp"
Vishwanatha Subbanna07655062017-07-14 20:31:57 +05302#include "config.h"
Chris Austen4d98c1e2015-10-13 14:33:50 -05003#include <host-ipmid/ipmid-api.h>
Vishwanatha Subbanna07655062017-07-14 20:31:57 +05304#include <host-ipmid/ipmid-host-cmd.hpp>
Adriana Kobylak187bfce2016-03-04 11:55:43 -06005#include <fstream>
Chris Austen4d98c1e2015-10-13 14:33:50 -05006#include <stdio.h>
7#include <string.h>
Nan Li8a0807a2016-05-24 16:59:24 +08008#include <endian.h>
Vishwanatha Subbanna07655062017-07-14 20:31:57 +05309#include <functional>
10#include <systemd/sd-bus.h>
11#include <sdbusplus/bus.hpp>
12#include <host-interface.hpp>
Chris Austen4d98c1e2015-10-13 14:33:50 -050013
14void register_netfn_oem_partial_esel() __attribute__((constructor));
15
Chris Austenfcafccf2016-02-19 23:15:57 -060016const char *g_esel_path = "/tmp/esel";
Chris Austen29a8e0f2015-10-30 11:44:38 -050017uint16_t g_record_id = 0x0001;
Chris Austen4d98c1e2015-10-13 14:33:50 -050018
Chris Austen4d98c1e2015-10-13 14:33:50 -050019///////////////////////////////////////////////////////////////////////////////
Patrick Williams24fa5a92015-10-30 14:53:57 -050020// For the First partial add eSEL the SEL Record ID and offset
21// value should be 0x0000. The extended data needs to be in
22// the form of an IPMI SEL Event Record, with Event sensor type
23// of 0xDF and Event Message format of 0x04. The returned
Chris Austen4d98c1e2015-10-13 14:33:50 -050024// Record ID should be used for all partial eSEL adds.
25//
Chris Austenba54afb2016-02-19 23:18:42 -060026// This function creates a /tmp/esel file to store the
Chris Austen4d98c1e2015-10-13 14:33:50 -050027// incoming partial esel. It is the role of some other
Patrick Williams24fa5a92015-10-30 14:53:57 -050028// function to commit the error log in to long term
29// storage. Likely via the ipmi add_sel command.
Chris Austen4d98c1e2015-10-13 14:33:50 -050030///////////////////////////////////////////////////////////////////////////////
Patrick Williams24fa5a92015-10-30 14:53:57 -050031ipmi_ret_t ipmi_ibm_oem_partial_esel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Chris Austen17160ce2015-10-30 11:44:38 -050032 ipmi_request_t request, ipmi_response_t response,
33 ipmi_data_len_t data_len, ipmi_context_t context)
Chris Austen4d98c1e2015-10-13 14:33:50 -050034{
Nan Li8a0807a2016-05-24 16:59:24 +080035 uint8_t *reqptr = (uint8_t *) request;
36 esel_request_t esel_req;
Chris Austenba54afb2016-02-19 23:18:42 -060037 FILE *fp;
Nan Lib6c4c562016-03-30 17:06:13 +080038 int r = 0;
Chris Austenba54afb2016-02-19 23:18:42 -060039 uint8_t rlen;
40 ipmi_ret_t rc = IPMI_CC_OK;
41 const char *pio;
Chris Austen4d98c1e2015-10-13 14:33:50 -050042
Nan Li8a0807a2016-05-24 16:59:24 +080043 esel_req.resid = le16toh((((uint16_t) reqptr[1]) << 8) + reqptr[0]);
44 esel_req.selrecord = le16toh((((uint16_t) reqptr[3]) << 8) + reqptr[2]);
45 esel_req.offset = le16toh((((uint16_t) reqptr[5]) << 8) + reqptr[4]);
46 esel_req.progress = reqptr[6];
Nan Lib6c4c562016-03-30 17:06:13 +080047
Nan Li8a0807a2016-05-24 16:59:24 +080048 uint16_t used_res_id = get_sel_reserve_id();
Nan Lib6c4c562016-03-30 17:06:13 +080049
50 // According to IPMI spec, Reservation ID must be checked.
Nan Li8a0807a2016-05-24 16:59:24 +080051 if ( used_res_id != esel_req.resid ) {
Nan Lib6c4c562016-03-30 17:06:13 +080052 // 0xc5 means Reservation Cancelled or Invalid Reservation ID.
53 printf("Used Reservation ID = %d\n", used_res_id);
54 rc = IPMI_CC_INVALID_RESERVATION_ID;
55
Andrew Geisslerd9296052017-06-15 14:57:25 -050056 // clean g_esel_path.
Nan Lib6c4c562016-03-30 17:06:13 +080057 r = remove(g_esel_path);
58 if(r < 0)
59 fprintf(stderr, "Error deleting %s\n", g_esel_path);
60
61 return rc;
62 }
63
64 // OpenPOWER Host Interface spec says if RecordID and Offset are
Chris Austenba54afb2016-02-19 23:18:42 -060065 // 0 then then this is a new request
Nan Li8a0807a2016-05-24 16:59:24 +080066 if (!esel_req.selrecord && !esel_req.offset)
Chris Austenba54afb2016-02-19 23:18:42 -060067 pio = "wb";
68 else
69 pio = "rb+";
Chris Austen4d98c1e2015-10-13 14:33:50 -050070
Chris Austenba54afb2016-02-19 23:18:42 -060071 rlen = (*data_len) - (uint8_t) (sizeof(esel_request_t));
Chris Austen4d98c1e2015-10-13 14:33:50 -050072
Chris Austenba54afb2016-02-19 23:18:42 -060073 if ((fp = fopen(g_esel_path, pio)) != NULL) {
Nan Li8a0807a2016-05-24 16:59:24 +080074 fseek(fp, esel_req.offset, SEEK_SET);
75 fwrite(reqptr+(uint8_t) (sizeof(esel_request_t)), rlen, 1, fp);
Chris Austenba54afb2016-02-19 23:18:42 -060076 fclose(fp);
Chris Austen4d98c1e2015-10-13 14:33:50 -050077
Chris Austenba54afb2016-02-19 23:18:42 -060078 *data_len = sizeof(g_record_id);
79 memcpy(response, &g_record_id, *data_len);
80 } else {
81 fprintf(stderr, "Error trying to perform %s for esel%s\n",pio, g_esel_path);
82 rc = IPMI_CC_INVALID;
83 *data_len = 0;
84 }
Chris Austen4d98c1e2015-10-13 14:33:50 -050085
Chris Austenba54afb2016-02-19 23:18:42 -060086 // The first bit prepresents that this is the last partial packet
87 // coming down. If that is the case advance the record id so we
88 // don't overlap logs. This allows anyone to establish a log
89 // directory system.
Nan Li8a0807a2016-05-24 16:59:24 +080090 if (esel_req.progress & 1 ) {
Chris Austenba54afb2016-02-19 23:18:42 -060091 g_record_id++;
92 }
Chris Austen4d98c1e2015-10-13 14:33:50 -050093
Chris Austenba54afb2016-02-19 23:18:42 -060094 return rc;
Chris Austen4d98c1e2015-10-13 14:33:50 -050095}
96
Adriana Kobylak187bfce2016-03-04 11:55:43 -060097// Prepare for FW Update.
98// Execute needed commands to prepare the system for a fw update from the host.
99ipmi_ret_t ipmi_ibm_oem_prep_fw_update(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
100 ipmi_request_t request, ipmi_response_t response,
101 ipmi_data_len_t data_len, ipmi_context_t context)
102{
103 ipmi_ret_t ipmi_rc = IPMI_CC_OK;
104 *data_len = 0;
105
106 int rc = 0;
107 std::ofstream rwfs_file;
108 const char *busname = "org.openbmc.control.Bmc";
109 const char *objname = "/org/openbmc/control/bmc0";
110 const char *iface = "org.openbmc.control.Bmc";
111 sd_bus *bus = ipmid_get_sd_bus_connection();
112 sd_bus_message *reply = NULL;
113 sd_bus_error error = SD_BUS_ERROR_NULL;
114 int r = 0;
115
116 // Set one time flag
117 rc = system("fw_setenv openbmconce copy-files-to-ram copy-base-filesystem-to-ram");
118 rc = WEXITSTATUS(rc);
119 if (rc != 0) {
120 fprintf(stderr, "fw_setenv openbmconce failed with rc=%d\n", rc);
Andrew Geisslerd9296052017-06-15 14:57:25 -0500121 return IPMI_CC_UNSPECIFIED_ERROR;
Adriana Kobylak187bfce2016-03-04 11:55:43 -0600122 }
123
124 // Touch the image-rwfs file to perform an empty update to force the save
125 // in case we're already in ram and the flash is the same causing the ram files
126 // to not be copied back to flash
127 rwfs_file.open("/run/initramfs/image-rwfs", std::ofstream::out | std::ofstream::app);
128 rwfs_file.close();
129
130 // Reboot the BMC for settings to take effect
131 r = sd_bus_call_method(bus, busname, objname, iface,
132 "warmReset", &error, &reply, NULL);
133 if (r < 0) {
134 fprintf(stderr, "Failed to reset BMC: %s\n", strerror(-r));
135 return -1;
136 }
137 printf("Warning: BMC is going down for reboot!\n");
138 sd_bus_error_free(&error);
139 reply = sd_bus_message_unref(reply);
140
141 return ipmi_rc;
142}
Chris Austen4d98c1e2015-10-13 14:33:50 -0500143
Vishwanatha Subbanna07655062017-07-14 20:31:57 +0530144namespace {
145// Storage to keep the object alive during process life
146std::unique_ptr<open_power::host::command::Host> opHost
147 __attribute__((init_priority(101)));
148std::unique_ptr<sdbusplus::server::manager::manager> objManager
149 __attribute__((init_priority(101)));
150}
151
Chris Austen4d98c1e2015-10-13 14:33:50 -0500152void register_netfn_oem_partial_esel()
153{
Tomcbfd6ec2016-09-14 17:45:55 +0530154 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_OEM, IPMI_CMD_PESEL);
155 ipmi_register_callback(NETFUN_OEM, IPMI_CMD_PESEL, NULL, ipmi_ibm_oem_partial_esel,
156 SYSTEM_INTERFACE);
Adriana Kobylak187bfce2016-03-04 11:55:43 -0600157
158 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_OEM, IPMI_CMD_PREP_FW_UPDATE);
Tomcbfd6ec2016-09-14 17:45:55 +0530159 ipmi_register_callback(NETFUN_OEM, IPMI_CMD_PREP_FW_UPDATE, NULL, ipmi_ibm_oem_prep_fw_update,
160 SYSTEM_INTERFACE);
Adriana Kobylak187bfce2016-03-04 11:55:43 -0600161
Vishwanatha Subbanna07655062017-07-14 20:31:57 +0530162 // Create new object on the bus
163 auto objPath = std::string{CONTROL_HOST_OBJ_MGR} + '/' + HOST_NAME + '0';
164
165 // Add sdbusplus ObjectManager.
166 auto& sdbusPlusHandler = ipmid_get_sdbus_plus_handler();
167 objManager = std::make_unique<sdbusplus::server::manager::manager>(
168 *sdbusPlusHandler,
169 CONTROL_HOST_OBJ_MGR);
170
171 opHost = std::make_unique<open_power::host::command::Host>(
172 *sdbusPlusHandler, objPath.c_str());
173
174 // Service for this is provided by phosphor layer systemcmdintf
175 // and this will be as part of that.
Tomcbfd6ec2016-09-14 17:45:55 +0530176 return;
Chris Austen4d98c1e2015-10-13 14:33:50 -0500177}