blob: e215e396c724c0d86c90ff3e8fed5060c3a7fa72 [file] [log] [blame]
Vishwanatha Subbanna07655062017-07-14 20:31:57 +05301#include "config.h"
Patrick Venture02261c02018-10-31 15:16:23 -07002
3#include "oemhandler.hpp"
4
Tom Joseph246bc0d2017-10-17 16:08:38 +05305#include "elog-errors.hpp"
Matt Spinler34aca012018-09-25 11:21:06 -05006#include "local_users.hpp"
Patrick Venture02261c02018-10-31 15:16:23 -07007
8#include <endian.h>
Chris Austen4d98c1e2015-10-13 14:33:50 -05009#include <host-ipmid/ipmid-api.h>
10#include <stdio.h>
11#include <string.h>
Vishwanatha Subbanna07655062017-07-14 20:31:57 +053012#include <systemd/sd-bus.h>
Patrick Venture02261c02018-10-31 15:16:23 -070013
14#include <fstream>
15#include <functional>
Vishwanatha Subbanna07655062017-07-14 20:31:57 +053016#include <host-interface.hpp>
Patrick Venture02261c02018-10-31 15:16:23 -070017#include <host-ipmid/ipmid-host-cmd.hpp>
18#include <memory>
Tom Joseph3503fdc2019-01-10 11:25:27 +053019#include <org/open_power/Host/error.hpp>
Tom Joseph246bc0d2017-10-17 16:08:38 +053020#include <org/open_power/OCC/Metrics/error.hpp>
Patrick Venture02261c02018-10-31 15:16:23 -070021#include <sdbusplus/bus.hpp>
Chris Austen4d98c1e2015-10-13 14:33:50 -050022
Andrew Jeffery8fb3f032018-07-27 16:45:44 +093023void register_netfn_ibm_oem_commands() __attribute__((constructor));
Chris Austen4d98c1e2015-10-13 14:33:50 -050024
Patrick Venture02261c02018-10-31 15:16:23 -070025const char* g_esel_path = "/tmp/esel";
Chris Austen29a8e0f2015-10-30 11:44:38 -050026uint16_t g_record_id = 0x0001;
Tom Joseph246bc0d2017-10-17 16:08:38 +053027using namespace phosphor::logging;
28constexpr auto occMetricsType = 0xDD;
29
30std::string readESEL(const char* fileName)
31{
Patrick Venture02261c02018-10-31 15:16:23 -070032 std::string content{};
Tom Joseph246bc0d2017-10-17 16:08:38 +053033
34 std::ifstream handle(fileName);
35
36 if (handle.fail())
37 {
Patrick Venture02261c02018-10-31 15:16:23 -070038 log<level::ERR>("Failed to open eSEL", entry("FILENAME=%s", fileName));
Tom Joseph246bc0d2017-10-17 16:08:38 +053039 return content;
40 }
41
42 handle.seekg(0, std::ios::end);
43 content.resize(handle.tellg());
44 handle.seekg(0, std::ios::beg);
45 handle.read(&content[0], content.size());
46 handle.close();
47
48 return content;
49}
50
51void createOCCLogEntry(const std::string& eSELData)
52{
53 // Each byte in eSEL is formatted as %02x with a space between bytes and
54 // insert '/0' at the end of the character array.
55 constexpr auto byteSeperator = 3;
56
Patrick Venture02261c02018-10-31 15:16:23 -070057 std::unique_ptr<char[]> data(
58 new char[(eSELData.size() * byteSeperator) + 1]());
Tom Joseph246bc0d2017-10-17 16:08:38 +053059
60 for (size_t i = 0; i < eSELData.size(); i++)
61 {
62 sprintf(&data[i * byteSeperator], "%02x ", eSELData[i]);
63 }
64 data[eSELData.size() * byteSeperator] = '\0';
65
Patrick Venture02261c02018-10-31 15:16:23 -070066 using error = sdbusplus::org::open_power::OCC::Metrics::Error::Event;
Tom Joseph246bc0d2017-10-17 16:08:38 +053067 using metadata = org::open_power::OCC::Metrics::Event;
68
69 report<error>(metadata::ESEL(data.get()));
70}
71
Tom Joseph3503fdc2019-01-10 11:25:27 +053072void createHostEntry(const std::string& eSELData)
73{
74 // Each byte in eSEL is formatted as %02x with a space between bytes and
75 // insert '/0' at the end of the character array.
76 std::string inventoryPath{};
77 constexpr auto byteSeperator = 3;
78
79 std::unique_ptr<char[]> data(
80 new char[(eSELData.size() * byteSeperator) + 1]());
81
82 for (size_t i = 0; i < eSELData.size(); i++)
83 {
84 sprintf(&data[i * byteSeperator], "%02x ", eSELData[i]);
85 }
86 data[eSELData.size() * byteSeperator] = '\0';
87
88 using hosterror = sdbusplus::org::open_power::Host::Error::Event;
89 using hostmetadata = org::open_power::Host::Event;
90
91 report<hosterror>(
92 Entry::Level::Warning, hostmetadata::ESEL(data.get()),
93 hostmetadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str()));
94}
95
Chris Austen4d98c1e2015-10-13 14:33:50 -050096///////////////////////////////////////////////////////////////////////////////
Patrick Williams24fa5a92015-10-30 14:53:57 -050097// For the First partial add eSEL the SEL Record ID and offset
98// value should be 0x0000. The extended data needs to be in
99// the form of an IPMI SEL Event Record, with Event sensor type
100// of 0xDF and Event Message format of 0x04. The returned
Chris Austen4d98c1e2015-10-13 14:33:50 -0500101// Record ID should be used for all partial eSEL adds.
102//
Chris Austenba54afb2016-02-19 23:18:42 -0600103// This function creates a /tmp/esel file to store the
Chris Austen4d98c1e2015-10-13 14:33:50 -0500104// incoming partial esel. It is the role of some other
Patrick Williams24fa5a92015-10-30 14:53:57 -0500105// function to commit the error log in to long term
106// storage. Likely via the ipmi add_sel command.
Chris Austen4d98c1e2015-10-13 14:33:50 -0500107///////////////////////////////////////////////////////////////////////////////
Patrick Williams24fa5a92015-10-30 14:53:57 -0500108ipmi_ret_t ipmi_ibm_oem_partial_esel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture02261c02018-10-31 15:16:23 -0700109 ipmi_request_t request,
110 ipmi_response_t response,
111 ipmi_data_len_t data_len,
112 ipmi_context_t context)
Chris Austen4d98c1e2015-10-13 14:33:50 -0500113{
Patrick Venture02261c02018-10-31 15:16:23 -0700114 uint8_t* reqptr = (uint8_t*)request;
115 esel_request_t esel_req;
116 FILE* fp;
117 int r = 0;
118 uint8_t rlen;
119 ipmi_ret_t rc = IPMI_CC_OK;
120 const char* pio;
Chris Austen4d98c1e2015-10-13 14:33:50 -0500121
Patrick Venture02261c02018-10-31 15:16:23 -0700122 esel_req.resid = le16toh((((uint16_t)reqptr[1]) << 8) + reqptr[0]);
123 esel_req.selrecord = le16toh((((uint16_t)reqptr[3]) << 8) + reqptr[2]);
124 esel_req.offset = le16toh((((uint16_t)reqptr[5]) << 8) + reqptr[4]);
125 esel_req.progress = reqptr[6];
Nan Lib6c4c562016-03-30 17:06:13 +0800126
Patrick Venture02261c02018-10-31 15:16:23 -0700127 // According to IPMI spec, Reservation ID must be checked.
128 if (!checkSELReservation(esel_req.resid))
129 {
130 // 0xc5 means Reservation Cancelled or Invalid Reservation ID.
131 printf("Used Reservation ID = %d\n", esel_req.resid);
132 rc = IPMI_CC_INVALID_RESERVATION_ID;
Nan Lib6c4c562016-03-30 17:06:13 +0800133
Patrick Venture02261c02018-10-31 15:16:23 -0700134 // clean g_esel_path.
135 r = remove(g_esel_path);
136 if (r < 0)
137 fprintf(stderr, "Error deleting %s\n", g_esel_path);
Nan Lib6c4c562016-03-30 17:06:13 +0800138
Patrick Venture02261c02018-10-31 15:16:23 -0700139 return rc;
140 }
Nan Lib6c4c562016-03-30 17:06:13 +0800141
142 // OpenPOWER Host Interface spec says if RecordID and Offset are
Patrick Venture02261c02018-10-31 15:16:23 -0700143 // 0 then then this is a new request
144 if (!esel_req.selrecord && !esel_req.offset)
145 pio = "wb";
146 else
147 pio = "rb+";
Chris Austen4d98c1e2015-10-13 14:33:50 -0500148
Patrick Venture02261c02018-10-31 15:16:23 -0700149 rlen = (*data_len) - (uint8_t)(sizeof(esel_request_t));
Chris Austen4d98c1e2015-10-13 14:33:50 -0500150
Patrick Venture02261c02018-10-31 15:16:23 -0700151 if ((fp = fopen(g_esel_path, pio)) != NULL)
Tom Joseph246bc0d2017-10-17 16:08:38 +0530152 {
Patrick Venture02261c02018-10-31 15:16:23 -0700153 fseek(fp, esel_req.offset, SEEK_SET);
154 fwrite(reqptr + (uint8_t)(sizeof(esel_request_t)), rlen, 1, fp);
155 fclose(fp);
Chris Austen4d98c1e2015-10-13 14:33:50 -0500156
Patrick Venture02261c02018-10-31 15:16:23 -0700157 *data_len = sizeof(g_record_id);
158 memcpy(response, &g_record_id, *data_len);
159 }
160 else
161 {
162 fprintf(stderr, "Error trying to perform %s for esel%s\n", pio,
163 g_esel_path);
164 rc = IPMI_CC_INVALID;
165 *data_len = 0;
166 }
Tom Joseph246bc0d2017-10-17 16:08:38 +0530167
Patrick Venture02261c02018-10-31 15:16:23 -0700168 // The first bit presents that this is the last partial packet
169 // coming down. If that is the case advance the record id so we
170 // don't overlap logs. This allows anyone to establish a log
171 // directory system.
172 if (esel_req.progress & 1)
173 {
174 g_record_id++;
Tom Joseph246bc0d2017-10-17 16:08:38 +0530175
Patrick Venture02261c02018-10-31 15:16:23 -0700176 auto eSELData = readESEL(g_esel_path);
177
178 if (eSELData.empty())
179 {
180 return IPMI_CC_UNSPECIFIED_ERROR;
181 }
182
183 // If the eSEL record type is OCC metrics, then create the OCC log
184 // entry.
185 if (eSELData[2] == occMetricsType)
186 {
187 createOCCLogEntry(eSELData);
188 }
Tom Joseph3503fdc2019-01-10 11:25:27 +0530189 else
190 {
191 createHostEntry(eSELData);
192 }
Tom Joseph246bc0d2017-10-17 16:08:38 +0530193 }
194
195 return rc;
Chris Austen4d98c1e2015-10-13 14:33:50 -0500196}
197
Adriana Kobylak187bfce2016-03-04 11:55:43 -0600198// Prepare for FW Update.
199// Execute needed commands to prepare the system for a fw update from the host.
200ipmi_ret_t ipmi_ibm_oem_prep_fw_update(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture02261c02018-10-31 15:16:23 -0700201 ipmi_request_t request,
202 ipmi_response_t response,
203 ipmi_data_len_t data_len,
204 ipmi_context_t context)
Adriana Kobylak187bfce2016-03-04 11:55:43 -0600205{
206 ipmi_ret_t ipmi_rc = IPMI_CC_OK;
207 *data_len = 0;
208
209 int rc = 0;
210 std::ofstream rwfs_file;
Patrick Venture02261c02018-10-31 15:16:23 -0700211 const char* busname = "org.openbmc.control.Bmc";
212 const char* objname = "/org/openbmc/control/bmc0";
213 const char* iface = "org.openbmc.control.Bmc";
214 sd_bus* bus = ipmid_get_sd_bus_connection();
215 sd_bus_message* reply = NULL;
Adriana Kobylak187bfce2016-03-04 11:55:43 -0600216 sd_bus_error error = SD_BUS_ERROR_NULL;
217 int r = 0;
218
219 // Set one time flag
Patrick Venture02261c02018-10-31 15:16:23 -0700220 rc = system(
221 "fw_setenv openbmconce copy-files-to-ram copy-base-filesystem-to-ram");
Adriana Kobylak187bfce2016-03-04 11:55:43 -0600222 rc = WEXITSTATUS(rc);
Patrick Venture02261c02018-10-31 15:16:23 -0700223 if (rc != 0)
224 {
Adriana Kobylak187bfce2016-03-04 11:55:43 -0600225 fprintf(stderr, "fw_setenv openbmconce failed with rc=%d\n", rc);
Andrew Geisslerd9296052017-06-15 14:57:25 -0500226 return IPMI_CC_UNSPECIFIED_ERROR;
Adriana Kobylak187bfce2016-03-04 11:55:43 -0600227 }
228
229 // Touch the image-rwfs file to perform an empty update to force the save
Patrick Venture02261c02018-10-31 15:16:23 -0700230 // in case we're already in ram and the flash is the same causing the ram
231 // files to not be copied back to flash
232 rwfs_file.open("/run/initramfs/image-rwfs",
233 std::ofstream::out | std::ofstream::app);
Adriana Kobylak187bfce2016-03-04 11:55:43 -0600234 rwfs_file.close();
235
236 // Reboot the BMC for settings to take effect
Patrick Venture02261c02018-10-31 15:16:23 -0700237 r = sd_bus_call_method(bus, busname, objname, iface, "warmReset", &error,
238 &reply, NULL);
239 if (r < 0)
240 {
Adriana Kobylak187bfce2016-03-04 11:55:43 -0600241 fprintf(stderr, "Failed to reset BMC: %s\n", strerror(-r));
242 return -1;
243 }
244 printf("Warning: BMC is going down for reboot!\n");
245 sd_bus_error_free(&error);
246 reply = sd_bus_message_unref(reply);
247
248 return ipmi_rc;
249}
Chris Austen4d98c1e2015-10-13 14:33:50 -0500250
Matt Spinler32884712018-09-28 13:56:20 -0500251ipmi_ret_t ipmi_ibm_oem_reset_bmc_auth(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
252 ipmi_request_t request,
253 ipmi_response_t response,
254 ipmi_data_len_t data_len,
255 ipmi_context_t context)
Adriana Kobylak81e23102018-08-09 14:44:19 -0500256{
Matt Spinler34aca012018-09-25 11:21:06 -0500257 ipmi_ret_t rc;
258
259 rc = local::users::enableUsers();
260
261 return rc;
Adriana Kobylak81e23102018-08-09 14:44:19 -0500262}
263
Patrick Venture02261c02018-10-31 15:16:23 -0700264namespace
265{
Vishwanatha Subbanna07655062017-07-14 20:31:57 +0530266// Storage to keep the object alive during process life
267std::unique_ptr<open_power::host::command::Host> opHost
Patrick Venture02261c02018-10-31 15:16:23 -0700268 __attribute__((init_priority(101)));
Vishwanatha Subbanna07655062017-07-14 20:31:57 +0530269std::unique_ptr<sdbusplus::server::manager::manager> objManager
Patrick Venture02261c02018-10-31 15:16:23 -0700270 __attribute__((init_priority(101)));
271} // namespace
Vishwanatha Subbanna07655062017-07-14 20:31:57 +0530272
Andrew Jeffery8fb3f032018-07-27 16:45:44 +0930273void register_netfn_ibm_oem_commands()
Chris Austen4d98c1e2015-10-13 14:33:50 -0500274{
Patrick Venture02261c02018-10-31 15:16:23 -0700275 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_IBM_OEM,
276 IPMI_CMD_PESEL);
277 ipmi_register_callback(NETFUN_IBM_OEM, IPMI_CMD_PESEL, NULL,
278 ipmi_ibm_oem_partial_esel, SYSTEM_INTERFACE);
Adriana Kobylak187bfce2016-03-04 11:55:43 -0600279
Patrick Venture02261c02018-10-31 15:16:23 -0700280 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_OEM,
281 IPMI_CMD_PREP_FW_UPDATE);
282 ipmi_register_callback(NETFUN_OEM, IPMI_CMD_PREP_FW_UPDATE, NULL,
283 ipmi_ibm_oem_prep_fw_update, SYSTEM_INTERFACE);
Adriana Kobylak187bfce2016-03-04 11:55:43 -0600284
Matt Spinler32884712018-09-28 13:56:20 -0500285 ipmi_register_callback(NETFUN_IBM_OEM, IPMI_CMD_RESET_BMC_AUTH, NULL,
286 ipmi_ibm_oem_reset_bmc_auth, SYSTEM_INTERFACE);
Adriana Kobylak81e23102018-08-09 14:44:19 -0500287
Vishwanatha Subbanna07655062017-07-14 20:31:57 +0530288 // Create new object on the bus
289 auto objPath = std::string{CONTROL_HOST_OBJ_MGR} + '/' + HOST_NAME + '0';
290
291 // Add sdbusplus ObjectManager.
292 auto& sdbusPlusHandler = ipmid_get_sdbus_plus_handler();
293 objManager = std::make_unique<sdbusplus::server::manager::manager>(
Patrick Venture02261c02018-10-31 15:16:23 -0700294 *sdbusPlusHandler, CONTROL_HOST_OBJ_MGR);
Vishwanatha Subbanna07655062017-07-14 20:31:57 +0530295
296 opHost = std::make_unique<open_power::host::command::Host>(
Patrick Venture02261c02018-10-31 15:16:23 -0700297 *sdbusPlusHandler, objPath.c_str());
Vishwanatha Subbanna07655062017-07-14 20:31:57 +0530298
299 // Service for this is provided by phosphor layer systemcmdintf
300 // and this will be as part of that.
Tomcbfd6ec2016-09-14 17:45:55 +0530301 return;
Chris Austen4d98c1e2015-10-13 14:33:50 -0500302}