blob: 0932f72639cbfac55a30260a9ae227693cc1ff78 [file] [log] [blame]
Patrick Venture3a5071a2018-09-12 13:27:42 -07001#include "storagehandler.hpp"
2
3#include "fruread.hpp"
4#include "read_fru_data.hpp"
5#include "selutility.hpp"
6#include "sensorhandler.hpp"
7#include "storageaddsel.hpp"
Patrick Venture3a5071a2018-09-12 13:27:42 -07008
Lei YU52d91242017-10-17 22:52:28 +08009#include <arpa/inet.h>
Patrick Venture3a5071a2018-09-12 13:27:42 -070010#include <mapper.h>
11#include <systemd/sd-bus.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070012
13#include <algorithm>
Lei YU52d91242017-10-17 22:52:28 +080014#include <chrono>
15#include <cstdio>
Patrick Ventureb51bf9c2018-09-10 15:53:14 -070016#include <cstring>
Vernon Mauerybdda8002019-02-26 10:18:51 -080017#include <filesystem>
Vernon Mauerye08fbff2019-04-03 09:19:34 -070018#include <ipmid/api.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -070019#include <ipmid/utils.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070020#include <phosphor-logging/elog-errors.hpp>
21#include <phosphor-logging/log.hpp>
22#include <sdbusplus/server.hpp>
23#include <string>
Vernon Mauery16b86932019-05-01 08:36:11 -070024#include <variant>
Patrick Venture3a5071a2018-09-12 13:27:42 -070025#include <xyz/openbmc_project/Common/error.hpp>
26
Chris Austenb4f5b922015-10-13 12:44:43 -050027void register_netfn_storage_functions() __attribute__((constructor));
28
Patrick Venture0b02be92018-08-31 11:55:55 -070029unsigned int g_sel_time = 0xFFFFFFFF;
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -060030extern const ipmi::sensor::IdInfoMap sensors;
31extern const FruMap frus;
anil kumar appana2c7db1d2019-05-28 11:20:19 +000032constexpr uint8_t eventDataSize = 3;
Patrick Venture0b02be92018-08-31 11:55:55 -070033namespace
34{
Lei YUe8939392017-06-15 10:45:05 +080035constexpr auto TIME_INTERFACE = "xyz.openbmc_project.Time.EpochTime";
36constexpr auto HOST_TIME_PATH = "/xyz/openbmc_project/time/host";
37constexpr auto DBUS_PROPERTIES = "org.freedesktop.DBus.Properties";
Patrick Venture0b02be92018-08-31 11:55:55 -070038constexpr auto PROPERTY_ELAPSED = "Elapsed";
Lei YUe8939392017-06-15 10:45:05 +080039
Patrick Venture0b02be92018-08-31 11:55:55 -070040} // namespace
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +053041
Tom Joseph6f7deaa2017-06-30 19:03:54 +053042namespace cache
43{
Patrick Venture0b02be92018-08-31 11:55:55 -070044/*
45 * This cache contains the object paths of the logging entries sorted in the
46 * order of the filename(numeric order). The cache is initialized by
47 * invoking readLoggingObjectPaths with the cache as the parameter. The
48 * cache is invoked in the execution of the Get SEL info and Delete SEL
49 * entry command. The Get SEL Info command is typically invoked before the
50 * Get SEL entry command, so the cache is utilized for responding to Get SEL
51 * entry command. The cache is invalidated by clearing after Delete SEL
52 * entry and Clear SEL command.
53 */
54ipmi::sel::ObjectPaths paths;
Tom Joseph6f7deaa2017-06-30 19:03:54 +053055
Patrick Venture0b02be92018-08-31 11:55:55 -070056} // namespace cache
Tom Joseph6f7deaa2017-06-30 19:03:54 +053057
58using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070059 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Tom Joseph6f7deaa2017-06-30 19:03:54 +053060using namespace phosphor::logging;
Marri Devender Raocac383b2017-07-03 13:24:27 -050061using namespace ipmi::fru;
62
63/**
64 * @enum Device access mode
65 */
66enum class AccessMode
67{
68 bytes, ///< Device is accessed by bytes
69 words ///< Device is accessed by words
70};
71
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -050072ipmi_ret_t ipmi_storage_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -070073 ipmi_request_t request,
74 ipmi_response_t response,
75 ipmi_data_len_t data_len,
76 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -050077{
Chris Austenb4f5b922015-10-13 12:44:43 -050078 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +080079 ipmi_ret_t rc = IPMI_CC_INVALID;
Chris Austenb4f5b922015-10-13 12:44:43 -050080 *data_len = 0;
81 return rc;
82}
83
jayaprakash Mutyalab7557722019-05-02 21:13:30 +000084/** @brief implements the get SEL Info command
85 * @returns IPMI completion code plus response data
86 * - selVersion - SEL revision
87 * - entries - Number of log entries in SEL.
88 * - freeSpace - Free Space in bytes.
89 * - addTimeStamp - Most recent addition timestamp
90 * - eraseTimeStamp - Most recent erase timestamp
91 * - operationSupport - Reserve & Delete SEL operations supported
92 */
93
94ipmi::RspType<uint8_t, // SEL revision.
95 uint16_t, // number of log entries in SEL.
96 uint16_t, // free Space in bytes.
97 uint32_t, // most recent addition timestamp
98 uint32_t, // most recent erase timestamp.
99
100 bool, // SEL allocation info supported
101 bool, // reserve SEL supported
102 bool, // partial Add SEL Entry supported
103 bool, // delete SEL supported
104 uint3_t, // reserved
105 bool // overflow flag
106 >
107 ipmiStorageGetSelInfo()
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530108{
jayaprakash Mutyalab7557722019-05-02 21:13:30 +0000109 uint16_t entries = 0;
110 // Most recent addition timestamp.
111 uint32_t addTimeStamp = ipmi::sel::invalidTimeStamp;
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530112
Tom Josephe59abfb2018-08-06 18:46:27 +0530113 try
114 {
115 ipmi::sel::readLoggingObjectPaths(cache::paths);
116 }
117 catch (const sdbusplus::exception::SdBusError& e)
118 {
119 // No action if reading log objects have failed for this command.
120 // readLoggingObjectPaths will throw exception if there are no log
121 // entries. The command will be responded with number of SEL entries
122 // as 0.
123 }
124
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530125 if (!cache::paths.empty())
126 {
jayaprakash Mutyalab7557722019-05-02 21:13:30 +0000127 entries = static_cast<uint16_t>(cache::paths.size());
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530128
129 try
130 {
jayaprakash Mutyalab7557722019-05-02 21:13:30 +0000131 addTimeStamp = static_cast<uint32_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700132 (ipmi::sel::getEntryTimeStamp(cache::paths.back()).count()));
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530133 }
134 catch (InternalFailure& e)
135 {
136 }
137 catch (const std::runtime_error& e)
138 {
139 log<level::ERR>(e.what());
140 }
141 }
142
jayaprakash Mutyalab7557722019-05-02 21:13:30 +0000143 constexpr uint8_t selVersion = ipmi::sel::selVersion;
144 constexpr uint16_t freeSpace = 0xFFFF;
145 constexpr uint32_t eraseTimeStamp = ipmi::sel::invalidTimeStamp;
146 constexpr uint3_t reserved{0};
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530147
jayaprakash Mutyalab7557722019-05-02 21:13:30 +0000148 return ipmi::responseSuccess(
149 selVersion, entries, freeSpace, addTimeStamp, eraseTimeStamp,
150 ipmi::sel::operationSupport::getSelAllocationInfo,
151 ipmi::sel::operationSupport::reserveSel,
152 ipmi::sel::operationSupport::partialAddSelEntry,
153 ipmi::sel::operationSupport::deleteSel, reserved,
154 ipmi::sel::operationSupport::overflow);
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530155}
156
Tom Josepha4953392017-06-30 19:09:47 +0530157ipmi_ret_t getSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
158 ipmi_request_t request, ipmi_response_t response,
159 ipmi_data_len_t data_len, ipmi_context_t context)
160{
Jason M. Bills851acb12019-02-04 14:06:57 -0800161 if (*data_len != sizeof(ipmi::sel::GetSELEntryRequest))
162 {
163 *data_len = 0;
164 return IPMI_CC_REQ_DATA_LEN_INVALID;
165 }
166
Patrick Venture0b02be92018-08-31 11:55:55 -0700167 auto requestData =
168 reinterpret_cast<const ipmi::sel::GetSELEntryRequest*>(request);
Tom Josepha4953392017-06-30 19:09:47 +0530169
170 if (requestData->reservationID != 0)
171 {
Jason M. Bills13e67c82018-09-10 14:12:16 -0700172 if (!checkSELReservation(requestData->reservationID))
Tom Josepha4953392017-06-30 19:09:47 +0530173 {
174 *data_len = 0;
175 return IPMI_CC_INVALID_RESERVATION_ID;
176 }
177 }
178
179 if (cache::paths.empty())
180 {
181 *data_len = 0;
182 return IPMI_CC_SENSOR_INVALID;
183 }
184
185 ipmi::sel::ObjectPaths::const_iterator iter;
186
187 // Check for the requested SEL Entry.
188 if (requestData->selRecordID == ipmi::sel::firstEntry)
189 {
190 iter = cache::paths.begin();
191 }
192 else if (requestData->selRecordID == ipmi::sel::lastEntry)
193 {
194 iter = cache::paths.end();
195 }
196 else
197 {
198 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
199 std::to_string(requestData->selRecordID);
200
201 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
202 if (iter == cache::paths.end())
203 {
204 *data_len = 0;
205 return IPMI_CC_SENSOR_INVALID;
206 }
207 }
208
Patrick Venture0b02be92018-08-31 11:55:55 -0700209 ipmi::sel::GetSELEntryResponse record{};
Tom Josepha4953392017-06-30 19:09:47 +0530210
211 // Convert the log entry into SEL record.
212 try
213 {
214 record = ipmi::sel::convertLogEntrytoSEL(*iter);
215 }
216 catch (InternalFailure& e)
217 {
218 *data_len = 0;
219 return IPMI_CC_UNSPECIFIED_ERROR;
220 }
221 catch (const std::runtime_error& e)
222 {
223 log<level::ERR>(e.what());
224 *data_len = 0;
225 return IPMI_CC_UNSPECIFIED_ERROR;
226 }
227
Tom Josepha4953392017-06-30 19:09:47 +0530228 // Identify the next SEL record ID
Patrick Venture0b02be92018-08-31 11:55:55 -0700229 if (iter != cache::paths.end())
Tom Josepha4953392017-06-30 19:09:47 +0530230 {
231 ++iter;
232 if (iter == cache::paths.end())
233 {
234 record.nextRecordID = ipmi::sel::lastEntry;
235 }
236 else
237 {
Vernon Mauery185b9f82018-07-20 10:52:36 -0700238 namespace fs = std::filesystem;
Tom Josepha4953392017-06-30 19:09:47 +0530239 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700240 record.nextRecordID = static_cast<uint16_t>(
241 std::stoul(std::string(path.filename().c_str())));
Tom Josepha4953392017-06-30 19:09:47 +0530242 }
243 }
244 else
245 {
246 record.nextRecordID = ipmi::sel::lastEntry;
247 }
248
249 if (requestData->readLength == ipmi::sel::entireRecord)
250 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700251 std::memcpy(response, &record, sizeof(record));
Tom Josepha4953392017-06-30 19:09:47 +0530252 *data_len = sizeof(record);
253 }
254 else
255 {
256 if (requestData->offset >= ipmi::sel::selRecordSize ||
257 requestData->readLength > ipmi::sel::selRecordSize)
258 {
259 *data_len = 0;
260 return IPMI_CC_INVALID_FIELD_REQUEST;
261 }
262
263 auto diff = ipmi::sel::selRecordSize - requestData->offset;
Patrick Venture0b02be92018-08-31 11:55:55 -0700264 auto readLength =
265 std::min(diff, static_cast<int>(requestData->readLength));
Tom Josepha4953392017-06-30 19:09:47 +0530266
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700267 std::memcpy(response, &record.nextRecordID,
268 sizeof(record.nextRecordID));
269 std::memcpy(static_cast<uint8_t*>(response) +
270 sizeof(record.nextRecordID),
271 &record.recordID + requestData->offset, readLength);
Tom Josepha4953392017-06-30 19:09:47 +0530272 *data_len = sizeof(record.nextRecordID) + readLength;
273 }
274
275 return IPMI_CC_OK;
276}
277
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000278/** @brief implements the delete SEL entry command
279 * @request
280 * - reservationID; // reservation ID.
281 * - selRecordID; // SEL record ID.
282 *
283 * @returns ipmi completion code plus response data
284 * - Record ID of the deleted record
285 */
286ipmi::RspType<uint16_t // deleted record ID
287 >
288 deleteSELEntry(uint16_t reservationID, uint16_t selRecordID)
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530289{
Jason M. Bills851acb12019-02-04 14:06:57 -0800290
Brad Bishop1a4117b2018-11-21 15:48:18 -0500291 namespace fs = std::filesystem;
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530292
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000293 if (!checkSELReservation(reservationID))
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530294 {
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000295 return ipmi::responseInvalidReservationId();
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530296 }
297
Jason M. Bills13e67c82018-09-10 14:12:16 -0700298 // Per the IPMI spec, need to cancel the reservation when a SEL entry is
299 // deleted
300 cancelSELReservation();
301
Tom Josephe59abfb2018-08-06 18:46:27 +0530302 try
303 {
304 ipmi::sel::readLoggingObjectPaths(cache::paths);
305 }
306 catch (const sdbusplus::exception::SdBusError& e)
307 {
308 // readLoggingObjectPaths will throw exception if there are no error
309 // log entries.
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000310 return ipmi::responseSensorInvalid();
Tom Josephe59abfb2018-08-06 18:46:27 +0530311 }
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530312
313 if (cache::paths.empty())
314 {
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000315 return ipmi::responseSensorInvalid();
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530316 }
317
318 ipmi::sel::ObjectPaths::const_iterator iter;
319 uint16_t delRecordID = 0;
320
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000321 if (selRecordID == ipmi::sel::firstEntry)
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530322 {
323 iter = cache::paths.begin();
324 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700325 delRecordID = static_cast<uint16_t>(
326 std::stoul(std::string(path.filename().c_str())));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530327 }
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000328 else if (selRecordID == ipmi::sel::lastEntry)
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530329 {
330 iter = cache::paths.end();
331 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700332 delRecordID = static_cast<uint16_t>(
333 std::stoul(std::string(path.filename().c_str())));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530334 }
335 else
336 {
337 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000338 std::to_string(selRecordID);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530339
340 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
341 if (iter == cache::paths.end())
342 {
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000343 return ipmi::responseSensorInvalid();
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530344 }
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000345 delRecordID = selRecordID;
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530346 }
347
348 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
349 std::string service;
350
351 try
352 {
353 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf, *iter);
354 }
355 catch (const std::runtime_error& e)
356 {
357 log<level::ERR>(e.what());
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000358 return ipmi::responseUnspecifiedError();
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530359 }
360
Patrick Venture0b02be92018-08-31 11:55:55 -0700361 auto methodCall = bus.new_method_call(service.c_str(), (*iter).c_str(),
362 ipmi::sel::logDeleteIntf, "Delete");
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530363 auto reply = bus.call(methodCall);
364 if (reply.is_method_error())
365 {
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000366 return ipmi::responseUnspecifiedError();
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530367 }
368
369 // Invalidate the cache of dbus entry objects.
370 cache::paths.clear();
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530371
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000372 return ipmi::responseSuccess(delRecordID);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530373}
374
Pradeep Kumar4a5a99a2019-04-26 15:22:39 +0000375/** @brief implements the Clear SEL command
376 * @request
377 * - reservationID // Reservation ID.
378 * - clr // char array { 'C'(0x43h), 'L'(0x4Ch), 'R'(0x52h) }
379 * - eraseOperation; // requested operation.
380 *
381 * @returns ipmi completion code plus response data
382 * - erase status
383 */
384
385ipmi::RspType<uint8_t // erase status
386 >
387 clearSEL(uint16_t reservationID, const std::array<char, 3>& clr,
388 uint8_t eraseOperation)
Tom Joseph2f05bb52017-06-30 19:14:49 +0530389{
Pradeep Kumar4a5a99a2019-04-26 15:22:39 +0000390 static constexpr std::array<char, 3> clrOk = {'C', 'L', 'R'};
391 if (clr != clrOk)
Jason M. Bills851acb12019-02-04 14:06:57 -0800392 {
Pradeep Kumar4a5a99a2019-04-26 15:22:39 +0000393 return ipmi::responseInvalidFieldRequest();
Jason M. Bills851acb12019-02-04 14:06:57 -0800394 }
395
Pradeep Kumar4a5a99a2019-04-26 15:22:39 +0000396 if (!checkSELReservation(reservationID))
Tom Joseph2f05bb52017-06-30 19:14:49 +0530397 {
Pradeep Kumar4a5a99a2019-04-26 15:22:39 +0000398 return ipmi::responseInvalidReservationId();
Tom Joseph2f05bb52017-06-30 19:14:49 +0530399 }
400
Tom Joseph2f05bb52017-06-30 19:14:49 +0530401 /*
402 * Erasure status cannot be fetched from DBUS, so always return erasure
403 * status as `erase completed`.
404 */
Pradeep Kumar4a5a99a2019-04-26 15:22:39 +0000405 if (eraseOperation == ipmi::sel::getEraseStatus)
Tom Joseph2f05bb52017-06-30 19:14:49 +0530406 {
Pradeep Kumar4a5a99a2019-04-26 15:22:39 +0000407 return ipmi::responseSuccess(
408 static_cast<uint8_t>(ipmi::sel::eraseComplete));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530409 }
410
Jason M. Bills13e67c82018-09-10 14:12:16 -0700411 // Per the IPMI spec, need to cancel any reservation when the SEL is cleared
412 cancelSELReservation();
413
Tom Joseph2f05bb52017-06-30 19:14:49 +0530414 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Tom Josephe59abfb2018-08-06 18:46:27 +0530415 ipmi::sel::ObjectPaths objectPaths;
Tom Joseph2f05bb52017-06-30 19:14:49 +0530416 auto depth = 0;
417
Patrick Venture0b02be92018-08-31 11:55:55 -0700418 auto mapperCall =
419 bus.new_method_call(ipmi::sel::mapperBusName, ipmi::sel::mapperObjPath,
420 ipmi::sel::mapperIntf, "GetSubTreePaths");
Tom Joseph2f05bb52017-06-30 19:14:49 +0530421 mapperCall.append(ipmi::sel::logBasePath);
422 mapperCall.append(depth);
423 mapperCall.append(ipmi::sel::ObjectPaths({ipmi::sel::logEntryIntf}));
424
Tom Josephe59abfb2018-08-06 18:46:27 +0530425 try
Tom Joseph2f05bb52017-06-30 19:14:49 +0530426 {
Tom Josephe59abfb2018-08-06 18:46:27 +0530427 auto reply = bus.call(mapperCall);
428 if (reply.is_method_error())
429 {
Pradeep Kumar4a5a99a2019-04-26 15:22:39 +0000430 return ipmi::responseSuccess(
431 static_cast<uint8_t>(ipmi::sel::eraseComplete));
Tom Josephe59abfb2018-08-06 18:46:27 +0530432 }
Tom Joseph2f05bb52017-06-30 19:14:49 +0530433
Tom Josephe59abfb2018-08-06 18:46:27 +0530434 reply.read(objectPaths);
435 if (objectPaths.empty())
436 {
Pradeep Kumar4a5a99a2019-04-26 15:22:39 +0000437 return ipmi::responseSuccess(
438 static_cast<uint8_t>(ipmi::sel::eraseComplete));
Tom Josephe59abfb2018-08-06 18:46:27 +0530439 }
440 }
441 catch (const sdbusplus::exception::SdBusError& e)
Tom Joseph2f05bb52017-06-30 19:14:49 +0530442 {
Pradeep Kumar4a5a99a2019-04-26 15:22:39 +0000443 return ipmi::responseSuccess(
444 static_cast<uint8_t>(ipmi::sel::eraseComplete));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530445 }
446
447 std::string service;
448
449 try
450 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700451 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf,
Tom Joseph2f05bb52017-06-30 19:14:49 +0530452 objectPaths.front());
453 }
454 catch (const std::runtime_error& e)
455 {
456 log<level::ERR>(e.what());
Pradeep Kumar4a5a99a2019-04-26 15:22:39 +0000457 return ipmi::responseUnspecifiedError();
Tom Joseph2f05bb52017-06-30 19:14:49 +0530458 }
459
460 for (const auto& iter : objectPaths)
461 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700462 auto methodCall = bus.new_method_call(
463 service.c_str(), iter.c_str(), ipmi::sel::logDeleteIntf, "Delete");
Tom Joseph2f05bb52017-06-30 19:14:49 +0530464
465 auto reply = bus.call(methodCall);
466 if (reply.is_method_error())
467 {
Pradeep Kumar4a5a99a2019-04-26 15:22:39 +0000468 return ipmi::responseUnspecifiedError();
Tom Joseph2f05bb52017-06-30 19:14:49 +0530469 }
470 }
471
472 // Invalidate the cache of dbus entry objects.
473 cache::paths.clear();
Pradeep Kumar4a5a99a2019-04-26 15:22:39 +0000474 return ipmi::responseSuccess(
475 static_cast<uint8_t>(ipmi::sel::eraseComplete));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530476}
477
jayaprakash Mutyaladb2e8c42019-05-03 01:38:01 +0000478/** @brief implements the get SEL time command
479 * @returns IPMI completion code plus response data
480 * -current time
481 */
482ipmi::RspType<uint32_t> // current time
483 ipmiStorageGetSelTime()
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500484{
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530485 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530486 uint64_t host_time_usec = 0;
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500487 std::stringstream hostTime;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500488
Lei YUe8939392017-06-15 10:45:05 +0800489 try
490 {
491 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
492 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
Vernon Mauery16b86932019-05-01 08:36:11 -0700493 std::variant<uint64_t> value;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530494
Lei YUe8939392017-06-15 10:45:05 +0800495 // Get host time
Patrick Venture0b02be92018-08-31 11:55:55 -0700496 auto method = bus.new_method_call(service.c_str(), HOST_TIME_PATH,
497 DBUS_PROPERTIES, "Get");
Lei YUe8939392017-06-15 10:45:05 +0800498
499 method.append(TIME_INTERFACE, PROPERTY_ELAPSED);
500 auto reply = bus.call(method);
501 if (reply.is_method_error())
502 {
503 log<level::ERR>("Error getting time",
504 entry("SERVICE=%s", service.c_str()),
505 entry("PATH=%s", HOST_TIME_PATH));
jayaprakash Mutyaladb2e8c42019-05-03 01:38:01 +0000506 return ipmi::responseUnspecifiedError();
Lei YUe8939392017-06-15 10:45:05 +0800507 }
508 reply.read(value);
Vernon Maueryf442e112019-04-09 11:44:36 -0700509 host_time_usec = std::get<uint64_t>(value);
Lei YUe8939392017-06-15 10:45:05 +0800510 }
511 catch (InternalFailure& e)
512 {
513 log<level::ERR>(e.what());
jayaprakash Mutyaladb2e8c42019-05-03 01:38:01 +0000514 return ipmi::responseUnspecifiedError();
Lei YUe8939392017-06-15 10:45:05 +0800515 }
516 catch (const std::runtime_error& e)
517 {
518 log<level::ERR>(e.what());
jayaprakash Mutyaladb2e8c42019-05-03 01:38:01 +0000519 return ipmi::responseUnspecifiedError();
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530520 }
521
jayaprakash Mutyaladb2e8c42019-05-03 01:38:01 +0000522 hostTime << "Host time:"
523 << duration_cast<seconds>(microseconds(host_time_usec)).count();
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500524 log<level::DEBUG>(hostTime.str().c_str());
525
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530526 // Time is really long int but IPMI wants just uint32. This works okay until
527 // the number of seconds since 1970 overflows uint32 size.. Still a whole
528 // lot of time here to even think about that.
jayaprakash Mutyaladb2e8c42019-05-03 01:38:01 +0000529 return ipmi::responseSuccess(
530 duration_cast<seconds>(microseconds(host_time_usec)).count());
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500531}
532
jayaprakash Mutyaladb2e8c42019-05-03 01:38:01 +0000533/** @brief implements the set SEL time command
534 * @param selDeviceTime - epoch time
535 * -local time as the number of seconds from 00:00:00, January 1, 1970
536 * @returns IPMI completion code
537 */
538ipmi::RspType<> ipmiStorageSetSelTime(uint32_t selDeviceTime)
Chris Austenb4f5b922015-10-13 12:44:43 -0500539{
Lei YUe8939392017-06-15 10:45:05 +0800540 using namespace std::chrono;
jayaprakash Mutyaladb2e8c42019-05-03 01:38:01 +0000541 microseconds usec{seconds(selDeviceTime)};
Norman James82330442015-11-19 16:53:26 -0600542
Lei YUe8939392017-06-15 10:45:05 +0800543 try
544 {
545 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
546 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
Vernon Mauery16b86932019-05-01 08:36:11 -0700547 std::variant<uint64_t> value{usec.count()};
Lei YUe8939392017-06-15 10:45:05 +0800548
549 // Set host time
Patrick Venture0b02be92018-08-31 11:55:55 -0700550 auto method = bus.new_method_call(service.c_str(), HOST_TIME_PATH,
551 DBUS_PROPERTIES, "Set");
Lei YUe8939392017-06-15 10:45:05 +0800552
553 method.append(TIME_INTERFACE, PROPERTY_ELAPSED, value);
554 auto reply = bus.call(method);
555 if (reply.is_method_error())
556 {
557 log<level::ERR>("Error setting time",
558 entry("SERVICE=%s", service.c_str()),
559 entry("PATH=%s", HOST_TIME_PATH));
jayaprakash Mutyaladb2e8c42019-05-03 01:38:01 +0000560 return ipmi::responseUnspecifiedError();
Lei YUe8939392017-06-15 10:45:05 +0800561 }
Norman James82330442015-11-19 16:53:26 -0600562 }
Lei YUe8939392017-06-15 10:45:05 +0800563 catch (InternalFailure& e)
564 {
565 log<level::ERR>(e.what());
jayaprakash Mutyaladb2e8c42019-05-03 01:38:01 +0000566 return ipmi::responseUnspecifiedError();
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530567 }
Lei YUe8939392017-06-15 10:45:05 +0800568 catch (const std::runtime_error& e)
569 {
570 log<level::ERR>(e.what());
jayaprakash Mutyaladb2e8c42019-05-03 01:38:01 +0000571 return ipmi::responseUnspecifiedError();
Norman James82330442015-11-19 16:53:26 -0600572 }
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530573
jayaprakash Mutyaladb2e8c42019-05-03 01:38:01 +0000574 return ipmi::responseSuccess();
Chris Austenb4f5b922015-10-13 12:44:43 -0500575}
576
jayaprakash Mutyalab7557722019-05-02 21:13:30 +0000577/** @brief implements the reserve SEL command
578 * @returns IPMI completion code plus response data
579 * - SEL reservation ID.
580 */
581ipmi::RspType<uint16_t> ipmiStorageReserveSel()
Chris Austenb4f5b922015-10-13 12:44:43 -0500582{
jayaprakash Mutyalab7557722019-05-02 21:13:30 +0000583 return ipmi::responseSuccess(reserveSel());
Chris Austenb4f5b922015-10-13 12:44:43 -0500584}
585
anil kumar appana2c7db1d2019-05-28 11:20:19 +0000586/** @brief implements the Add SEL entry command
587 * @request
588 *
589 * - recordID ID used for SEL Record access
590 * - recordType Record Type
591 * - timeStamp Time when event was logged. LS byte first
592 * - generatorID software ID if event was generated from
593 * system software
594 * - evmRev event message format version
595 * - sensorType sensor type code for service that generated
596 * the event
597 * - sensorNumber number of sensors that generated the event
598 * - eventDir event dir
599 * - eventData event data field contents
600 *
601 * @returns ipmi completion code plus response data
602 * - RecordID of the Added SEL entry
603 */
604ipmi::RspType<uint16_t // recordID of the Added SEL entry
605 >
606 ipmiStorageAddSEL(uint16_t recordID, uint8_t recordType, uint32_t timeStamp,
607 uint16_t generatorID, uint8_t evmRev, uint8_t sensorType,
608 uint8_t sensorNumber, uint8_t eventDir,
609 std::array<uint8_t, eventDataSize> eventData)
Chris Austenb4f5b922015-10-13 12:44:43 -0500610{
Jason M. Bills13e67c82018-09-10 14:12:16 -0700611 // Per the IPMI spec, need to cancel the reservation when a SEL entry is
612 // added
613 cancelSELReservation();
Tom Josephb647d5b2017-10-31 17:25:33 +0530614 // Hostboot sends SEL with OEM record type 0xDE to indicate that there is
615 // a maintenance procedure associated with eSEL record.
616 static constexpr auto procedureType = 0xDE;
anil kumar appana2c7db1d2019-05-28 11:20:19 +0000617 if (recordType == procedureType)
Tom Josephb647d5b2017-10-31 17:25:33 +0530618 {
619 // In the OEM record type 0xDE, byte 11 in the SEL record indicate the
620 // procedure number.
anil kumar appana2c7db1d2019-05-28 11:20:19 +0000621 createProcedureLogEntry(sensorType);
Tom Josephb647d5b2017-10-31 17:25:33 +0530622 }
Chris Austenb4f5b922015-10-13 12:44:43 -0500623
anil kumar appana2c7db1d2019-05-28 11:20:19 +0000624 return ipmi::responseSuccess(recordID);
Chris Austenb4f5b922015-10-13 12:44:43 -0500625}
626
Pradeep Kumarb0c794d2019-05-02 13:09:14 +0000627/** @brief implements the get FRU Inventory Area Info command
628 *
629 * @returns IPMI completion code plus response data
630 * - FRU Inventory area size in bytes,
631 * - access bit
632 **/
633ipmi::RspType<uint16_t, // FRU Inventory area size in bytes,
634 uint8_t // access size (bytes / words)
635 >
636 ipmiStorageGetFruInvAreaInfo(uint8_t fruID)
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500637{
Tom Joseph187f5642018-03-29 13:49:06 +0530638
Pradeep Kumarb0c794d2019-05-02 13:09:14 +0000639 auto iter = frus.find(fruID);
Tom Joseph187f5642018-03-29 13:49:06 +0530640 if (iter == frus.end())
641 {
Pradeep Kumarb0c794d2019-05-02 13:09:14 +0000642 return ipmi::responseSensorInvalid();
Tom Joseph187f5642018-03-29 13:49:06 +0530643 }
644
Marri Devender Raocac383b2017-07-03 13:24:27 -0500645 try
646 {
Pradeep Kumarb0c794d2019-05-02 13:09:14 +0000647 return ipmi::responseSuccess(
648 static_cast<uint16_t>(getFruAreaData(fruID).size()),
649 static_cast<uint8_t>(AccessMode::bytes));
Marri Devender Raocac383b2017-07-03 13:24:27 -0500650 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700651 catch (const InternalFailure& e)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500652 {
Marri Devender Raocac383b2017-07-03 13:24:27 -0500653 log<level::ERR>(e.what());
Pradeep Kumarb0c794d2019-05-02 13:09:14 +0000654 return ipmi::responseUnspecifiedError();
Marri Devender Raocac383b2017-07-03 13:24:27 -0500655 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500656}
657
Patrick Venture0b02be92018-08-31 11:55:55 -0700658// Read FRU data
659ipmi_ret_t ipmi_storage_read_fru_data(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
660 ipmi_request_t request,
661 ipmi_response_t response,
662 ipmi_data_len_t data_len,
663 ipmi_context_t context)
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500664{
665 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500666 const ReadFruDataRequest* reqptr =
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500667 reinterpret_cast<const ReadFruDataRequest*>(request);
Patrick Venture0b02be92018-08-31 11:55:55 -0700668 auto resptr = reinterpret_cast<ReadFruDataResponse*>(response);
Tom Joseph187f5642018-03-29 13:49:06 +0530669
670 auto iter = frus.find(reqptr->fruID);
671 if (iter == frus.end())
672 {
673 *data_len = 0;
674 return IPMI_CC_SENSOR_INVALID;
675 }
676
Marri Devender Raocac383b2017-07-03 13:24:27 -0500677 auto offset =
678 static_cast<uint16_t>(reqptr->offsetMS << 8 | reqptr->offsetLS);
679 try
680 {
681 const auto& fruArea = getFruAreaData(reqptr->fruID);
682 auto size = fruArea.size();
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500683
Tom Josephefcd68b2018-04-26 18:46:27 +0530684 if (offset >= size)
685 {
686 return IPMI_CC_PARM_OUT_OF_RANGE;
687 }
688
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500689 // Write the count of response data.
690 if ((offset + reqptr->count) <= size)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500691 {
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500692 resptr->count = reqptr->count;
693 }
694 else
695 {
696 resptr->count = size - offset;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500697 }
Ratan Gupta2848d602018-01-31 20:39:20 +0530698
Ratan Gupta2848d602018-01-31 20:39:20 +0530699 std::copy((fruArea.begin() + offset),
Patrick Venture0b02be92018-08-31 11:55:55 -0700700 (fruArea.begin() + offset + resptr->count), resptr->data);
Ratan Gupta2848d602018-01-31 20:39:20 +0530701
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500702 *data_len = resptr->count + 1; // additional one byte for count
Marri Devender Raocac383b2017-07-03 13:24:27 -0500703 }
704 catch (const InternalFailure& e)
705 {
706 rc = IPMI_CC_UNSPECIFIED_ERROR;
707 *data_len = 0;
708 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500709 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500710 return rc;
711}
712
Pradeep Kumarb60e8402019-05-06 15:17:01 +0000713ipmi::RspType<uint8_t, // SDR version
714 uint16_t, // record count LS first
715 uint16_t, // free space in bytes, LS first
716 uint32_t, // addition timestamp LS first
717 uint32_t, // deletion timestamp LS first
718 uint8_t> // operation Support
719 ipmiGetRepositoryInfo()
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600720{
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600721
Pradeep Kumarb60e8402019-05-06 15:17:01 +0000722 constexpr uint8_t sdrVersion = 0x51;
723 constexpr uint16_t freeSpace = 0xFFFF;
724 constexpr uint32_t additionTimestamp = 0x0;
725 constexpr uint32_t deletionTimestamp = 0x0;
726 constexpr uint8_t operationSupport = 0;
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600727
728 uint16_t records = frus.size() + sensors.size();
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600729
Pradeep Kumarb60e8402019-05-06 15:17:01 +0000730 return ipmi::responseSuccess(sdrVersion, records, freeSpace,
731 additionTimestamp, deletionTimestamp,
732 operationSupport);
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600733}
Chris Austenb4f5b922015-10-13 12:44:43 -0500734
Chris Austenb4f5b922015-10-13 12:44:43 -0500735void register_netfn_storage_functions()
736{
Tom05732372016-09-06 17:21:23 +0530737 // <Wildcard Command>
Patrick Venture0b02be92018-08-31 11:55:55 -0700738 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WILDCARD, NULL,
739 ipmi_storage_wildcard, PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500740
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530741 // <Get SEL Info>
jayaprakash Mutyalab7557722019-05-02 21:13:30 +0000742 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
743 ipmi::storage::cmdGetSelInfo, ipmi::Privilege::User,
744 ipmiStorageGetSelInfo);
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530745
Tom05732372016-09-06 17:21:23 +0530746 // <Get SEL Time>
jayaprakash Mutyaladb2e8c42019-05-03 01:38:01 +0000747 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
748 ipmi::storage::cmdGetSelTime, ipmi::Privilege::User,
749 ipmiStorageGetSelTime);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500750
Tom05732372016-09-06 17:21:23 +0530751 // <Set SEL Time>
jayaprakash Mutyaladb2e8c42019-05-03 01:38:01 +0000752 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
753 ipmi::storage::cmdSetSelTime,
754 ipmi::Privilege::Operator, ipmiStorageSetSelTime);
Chris Austenb4f5b922015-10-13 12:44:43 -0500755
Tom05732372016-09-06 17:21:23 +0530756 // <Reserve SEL>
jayaprakash Mutyalab7557722019-05-02 21:13:30 +0000757 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
758 ipmi::storage::cmdReserveSel, ipmi::Privilege::User,
759 ipmiStorageReserveSel);
Tom Josepha4953392017-06-30 19:09:47 +0530760 // <Get SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700761 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY, NULL,
762 getSELEntry, PRIVILEGE_USER);
Tom Josepha4953392017-06-30 19:09:47 +0530763
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530764 // <Delete SEL Entry>
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000765 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
766 ipmi::storage::cmdDeleteSelEntry,
767 ipmi::Privilege::Operator, deleteSELEntry);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530768
Tom05732372016-09-06 17:21:23 +0530769 // <Add SEL Entry>
anil kumar appana2c7db1d2019-05-28 11:20:19 +0000770 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
771 ipmi::storage::cmdAddSelEntry,
772 ipmi::Privilege::Operator, ipmiStorageAddSEL);
773
Tom Joseph2f05bb52017-06-30 19:14:49 +0530774 // <Clear SEL>
Pradeep Kumar4a5a99a2019-04-26 15:22:39 +0000775 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
776 ipmi::storage::cmdClearSel, ipmi::Privilege::Operator,
777 clearSEL);
778
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500779 // <Get FRU Inventory Area Info>
Pradeep Kumarb0c794d2019-05-02 13:09:14 +0000780 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
781 ipmi::storage::cmdGetFruInventoryAreaInfo,
782 ipmi::Privilege::User, ipmiStorageGetFruInvAreaInfo);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500783
Jason M. Billsb5248c92019-06-24 15:53:08 -0700784 // <READ FRU Data>
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500785 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_READ_FRU_DATA, NULL,
Jason M. Billsb5248c92019-06-24 15:53:08 -0700786 ipmi_storage_read_fru_data, PRIVILEGE_USER);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500787
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600788 // <Get Repository Info>
Pradeep Kumarb60e8402019-05-06 15:17:01 +0000789 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
790 ipmi::storage::cmdGetSdrRepositoryInfo,
791 ipmi::Privilege::User, ipmiGetRepositoryInfo);
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600792
Tom Joseph5ca50952018-02-22 00:33:38 +0530793 // <Reserve SDR Repository>
jayaprakash Mutyalad9578232019-05-13 20:22:50 +0000794 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
795 ipmi::storage::cmdReserveSdrRepository,
796 ipmi::Privilege::User, ipmiSensorReserveSdr);
Tom Joseph5ca50952018-02-22 00:33:38 +0530797
798 // <Get SDR>
Patrick Venture0b02be92018-08-31 11:55:55 -0700799 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SDR, nullptr,
800 ipmi_sen_get_sdr, PRIVILEGE_USER);
Tom Joseph5ca50952018-02-22 00:33:38 +0530801
Marri Devender Rao908f7502017-07-10 01:49:54 -0500802 ipmi::fru::registerCallbackHandler();
Chris Austenb4f5b922015-10-13 12:44:43 -0500803 return;
804}