blob: 55e17f24af895cee5ec89855f92cbc261495569e [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>
William A. Kennington III194375f2018-12-14 02:14:33 -080010#include <ipmid/api.h>
Patrick Venture3a5071a2018-09-12 13:27:42 -070011#include <mapper.h>
12#include <systemd/sd-bus.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070013
14#include <algorithm>
Lei YU52d91242017-10-17 22:52:28 +080015#include <chrono>
16#include <cstdio>
Patrick Ventureb51bf9c2018-09-10 15:53:14 -070017#include <cstring>
Vernon Mauerybdda8002019-02-26 10:18:51 -080018#include <filesystem>
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>
William A. Kennington III4c008022018-10-12 17:18:14 -070022#include <sdbusplus/message/types.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070023#include <sdbusplus/server.hpp>
24#include <string>
25#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;
Chris Austenb4f5b922015-10-13 12:44:43 -050032
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
40const char* getTimeString(const uint64_t& usecSinceEpoch)
41{
42 using namespace std::chrono;
43 system_clock::time_point tp{microseconds(usecSinceEpoch)};
44 auto t = system_clock::to_time_t(tp);
45 return std::ctime(&t);
46}
Patrick Venture0b02be92018-08-31 11:55:55 -070047} // namespace
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +053048
Tom Joseph6f7deaa2017-06-30 19:03:54 +053049namespace cache
50{
Patrick Venture0b02be92018-08-31 11:55:55 -070051/*
52 * This cache contains the object paths of the logging entries sorted in the
53 * order of the filename(numeric order). The cache is initialized by
54 * invoking readLoggingObjectPaths with the cache as the parameter. The
55 * cache is invoked in the execution of the Get SEL info and Delete SEL
56 * entry command. The Get SEL Info command is typically invoked before the
57 * Get SEL entry command, so the cache is utilized for responding to Get SEL
58 * entry command. The cache is invalidated by clearing after Delete SEL
59 * entry and Clear SEL command.
60 */
61ipmi::sel::ObjectPaths paths;
Tom Joseph6f7deaa2017-06-30 19:03:54 +053062
Patrick Venture0b02be92018-08-31 11:55:55 -070063} // namespace cache
Tom Joseph6f7deaa2017-06-30 19:03:54 +053064
William A. Kennington III4c008022018-10-12 17:18:14 -070065namespace variant_ns = sdbusplus::message::variant_ns;
66
Tom Joseph6f7deaa2017-06-30 19:03:54 +053067using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070068 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Tom Joseph6f7deaa2017-06-30 19:03:54 +053069using namespace phosphor::logging;
Marri Devender Raocac383b2017-07-03 13:24:27 -050070using namespace ipmi::fru;
71
72/**
73 * @enum Device access mode
74 */
75enum class AccessMode
76{
77 bytes, ///< Device is accessed by bytes
78 words ///< Device is accessed by words
79};
80
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -050081ipmi_ret_t ipmi_storage_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -070082 ipmi_request_t request,
83 ipmi_response_t response,
84 ipmi_data_len_t data_len,
85 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -050086{
Chris Austenb4f5b922015-10-13 12:44:43 -050087 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +080088 ipmi_ret_t rc = IPMI_CC_INVALID;
Chris Austenb4f5b922015-10-13 12:44:43 -050089 *data_len = 0;
90 return rc;
91}
92
Tom Joseph6f7deaa2017-06-30 19:03:54 +053093ipmi_ret_t getSELInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
94 ipmi_request_t request, ipmi_response_t response,
95 ipmi_data_len_t data_len, ipmi_context_t context)
96{
Jason M. Bills851acb12019-02-04 14:06:57 -080097 if (*data_len != 0)
98 {
99 *data_len = 0;
100 return IPMI_CC_REQ_DATA_LEN_INVALID;
101 }
102
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530103 std::vector<uint8_t> outPayload(sizeof(ipmi::sel::GetSELInfoResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700104 auto responseData =
105 reinterpret_cast<ipmi::sel::GetSELInfoResponse*>(outPayload.data());
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530106
107 responseData->selVersion = ipmi::sel::selVersion;
108 // Last erase timestamp is not available from log manager.
109 responseData->eraseTimeStamp = ipmi::sel::invalidTimeStamp;
110 responseData->operationSupport = ipmi::sel::operationSupport;
111
Tom Josephe59abfb2018-08-06 18:46:27 +0530112 try
113 {
114 ipmi::sel::readLoggingObjectPaths(cache::paths);
115 }
116 catch (const sdbusplus::exception::SdBusError& e)
117 {
118 // No action if reading log objects have failed for this command.
119 // readLoggingObjectPaths will throw exception if there are no log
120 // entries. The command will be responded with number of SEL entries
121 // as 0.
122 }
123
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530124 responseData->entries = 0;
125 responseData->addTimeStamp = ipmi::sel::invalidTimeStamp;
126
127 if (!cache::paths.empty())
128 {
129 responseData->entries = static_cast<uint16_t>(cache::paths.size());
130
131 try
132 {
133 responseData->addTimeStamp = static_cast<uint32_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700134 (ipmi::sel::getEntryTimeStamp(cache::paths.back()).count()));
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530135 }
136 catch (InternalFailure& e)
137 {
138 }
139 catch (const std::runtime_error& e)
140 {
141 log<level::ERR>(e.what());
142 }
143 }
144
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700145 std::memcpy(response, outPayload.data(), outPayload.size());
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530146 *data_len = outPayload.size();
147
148 return IPMI_CC_OK;
149}
150
Tom Josepha4953392017-06-30 19:09:47 +0530151ipmi_ret_t getSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
152 ipmi_request_t request, ipmi_response_t response,
153 ipmi_data_len_t data_len, ipmi_context_t context)
154{
Jason M. Bills851acb12019-02-04 14:06:57 -0800155 if (*data_len != sizeof(ipmi::sel::GetSELEntryRequest))
156 {
157 *data_len = 0;
158 return IPMI_CC_REQ_DATA_LEN_INVALID;
159 }
160
Patrick Venture0b02be92018-08-31 11:55:55 -0700161 auto requestData =
162 reinterpret_cast<const ipmi::sel::GetSELEntryRequest*>(request);
Tom Josepha4953392017-06-30 19:09:47 +0530163
164 if (requestData->reservationID != 0)
165 {
Jason M. Bills13e67c82018-09-10 14:12:16 -0700166 if (!checkSELReservation(requestData->reservationID))
Tom Josepha4953392017-06-30 19:09:47 +0530167 {
168 *data_len = 0;
169 return IPMI_CC_INVALID_RESERVATION_ID;
170 }
171 }
172
173 if (cache::paths.empty())
174 {
175 *data_len = 0;
176 return IPMI_CC_SENSOR_INVALID;
177 }
178
179 ipmi::sel::ObjectPaths::const_iterator iter;
180
181 // Check for the requested SEL Entry.
182 if (requestData->selRecordID == ipmi::sel::firstEntry)
183 {
184 iter = cache::paths.begin();
185 }
186 else if (requestData->selRecordID == ipmi::sel::lastEntry)
187 {
188 iter = cache::paths.end();
189 }
190 else
191 {
192 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
193 std::to_string(requestData->selRecordID);
194
195 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
196 if (iter == cache::paths.end())
197 {
198 *data_len = 0;
199 return IPMI_CC_SENSOR_INVALID;
200 }
201 }
202
Patrick Venture0b02be92018-08-31 11:55:55 -0700203 ipmi::sel::GetSELEntryResponse record{};
Tom Josepha4953392017-06-30 19:09:47 +0530204
205 // Convert the log entry into SEL record.
206 try
207 {
208 record = ipmi::sel::convertLogEntrytoSEL(*iter);
209 }
210 catch (InternalFailure& e)
211 {
212 *data_len = 0;
213 return IPMI_CC_UNSPECIFIED_ERROR;
214 }
215 catch (const std::runtime_error& e)
216 {
217 log<level::ERR>(e.what());
218 *data_len = 0;
219 return IPMI_CC_UNSPECIFIED_ERROR;
220 }
221
Tom Josepha4953392017-06-30 19:09:47 +0530222 // Identify the next SEL record ID
Patrick Venture0b02be92018-08-31 11:55:55 -0700223 if (iter != cache::paths.end())
Tom Josepha4953392017-06-30 19:09:47 +0530224 {
225 ++iter;
226 if (iter == cache::paths.end())
227 {
228 record.nextRecordID = ipmi::sel::lastEntry;
229 }
230 else
231 {
Vernon Mauery185b9f82018-07-20 10:52:36 -0700232 namespace fs = std::filesystem;
Tom Josepha4953392017-06-30 19:09:47 +0530233 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700234 record.nextRecordID = static_cast<uint16_t>(
235 std::stoul(std::string(path.filename().c_str())));
Tom Josepha4953392017-06-30 19:09:47 +0530236 }
237 }
238 else
239 {
240 record.nextRecordID = ipmi::sel::lastEntry;
241 }
242
243 if (requestData->readLength == ipmi::sel::entireRecord)
244 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700245 std::memcpy(response, &record, sizeof(record));
Tom Josepha4953392017-06-30 19:09:47 +0530246 *data_len = sizeof(record);
247 }
248 else
249 {
250 if (requestData->offset >= ipmi::sel::selRecordSize ||
251 requestData->readLength > ipmi::sel::selRecordSize)
252 {
253 *data_len = 0;
254 return IPMI_CC_INVALID_FIELD_REQUEST;
255 }
256
257 auto diff = ipmi::sel::selRecordSize - requestData->offset;
Patrick Venture0b02be92018-08-31 11:55:55 -0700258 auto readLength =
259 std::min(diff, static_cast<int>(requestData->readLength));
Tom Josepha4953392017-06-30 19:09:47 +0530260
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700261 std::memcpy(response, &record.nextRecordID,
262 sizeof(record.nextRecordID));
263 std::memcpy(static_cast<uint8_t*>(response) +
264 sizeof(record.nextRecordID),
265 &record.recordID + requestData->offset, readLength);
Tom Josepha4953392017-06-30 19:09:47 +0530266 *data_len = sizeof(record.nextRecordID) + readLength;
267 }
268
269 return IPMI_CC_OK;
270}
271
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530272ipmi_ret_t deleteSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
273 ipmi_request_t request, ipmi_response_t response,
274 ipmi_data_len_t data_len, ipmi_context_t context)
275{
Jason M. Bills851acb12019-02-04 14:06:57 -0800276 if (*data_len != sizeof(ipmi::sel::DeleteSELEntryRequest))
277 {
278 *data_len = 0;
279 return IPMI_CC_REQ_DATA_LEN_INVALID;
280 }
281
Brad Bishop1a4117b2018-11-21 15:48:18 -0500282 namespace fs = std::filesystem;
Patrick Venture0b02be92018-08-31 11:55:55 -0700283 auto requestData =
284 reinterpret_cast<const ipmi::sel::DeleteSELEntryRequest*>(request);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530285
Jason M. Bills13e67c82018-09-10 14:12:16 -0700286 if (!checkSELReservation(requestData->reservationID))
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530287 {
288 *data_len = 0;
289 return IPMI_CC_INVALID_RESERVATION_ID;
290 }
291
Jason M. Bills13e67c82018-09-10 14:12:16 -0700292 // Per the IPMI spec, need to cancel the reservation when a SEL entry is
293 // deleted
294 cancelSELReservation();
295
Tom Josephe59abfb2018-08-06 18:46:27 +0530296 try
297 {
298 ipmi::sel::readLoggingObjectPaths(cache::paths);
299 }
300 catch (const sdbusplus::exception::SdBusError& e)
301 {
302 // readLoggingObjectPaths will throw exception if there are no error
303 // log entries.
304 *data_len = 0;
305 return IPMI_CC_SENSOR_INVALID;
306 }
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530307
308 if (cache::paths.empty())
309 {
310 *data_len = 0;
311 return IPMI_CC_SENSOR_INVALID;
312 }
313
314 ipmi::sel::ObjectPaths::const_iterator iter;
315 uint16_t delRecordID = 0;
316
317 if (requestData->selRecordID == ipmi::sel::firstEntry)
318 {
319 iter = cache::paths.begin();
320 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700321 delRecordID = static_cast<uint16_t>(
322 std::stoul(std::string(path.filename().c_str())));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530323 }
324 else if (requestData->selRecordID == ipmi::sel::lastEntry)
325 {
326 iter = cache::paths.end();
327 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700328 delRecordID = static_cast<uint16_t>(
329 std::stoul(std::string(path.filename().c_str())));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530330 }
331 else
332 {
333 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
334 std::to_string(requestData->selRecordID);
335
336 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
337 if (iter == cache::paths.end())
338 {
339 *data_len = 0;
340 return IPMI_CC_SENSOR_INVALID;
341 }
342 delRecordID = requestData->selRecordID;
343 }
344
345 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
346 std::string service;
347
348 try
349 {
350 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf, *iter);
351 }
352 catch (const std::runtime_error& e)
353 {
354 log<level::ERR>(e.what());
355 *data_len = 0;
356 return IPMI_CC_UNSPECIFIED_ERROR;
357 }
358
Patrick Venture0b02be92018-08-31 11:55:55 -0700359 auto methodCall = bus.new_method_call(service.c_str(), (*iter).c_str(),
360 ipmi::sel::logDeleteIntf, "Delete");
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530361 auto reply = bus.call(methodCall);
362 if (reply.is_method_error())
363 {
364 *data_len = 0;
365 return IPMI_CC_UNSPECIFIED_ERROR;
366 }
367
368 // Invalidate the cache of dbus entry objects.
369 cache::paths.clear();
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700370 std::memcpy(response, &delRecordID, sizeof(delRecordID));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530371 *data_len = sizeof(delRecordID);
372
373 return IPMI_CC_OK;
374}
375
Tom Joseph2f05bb52017-06-30 19:14:49 +0530376ipmi_ret_t clearSEL(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
377 ipmi_response_t response, ipmi_data_len_t data_len,
378 ipmi_context_t context)
379{
Jason M. Bills851acb12019-02-04 14:06:57 -0800380 if (*data_len != sizeof(ipmi::sel::ClearSELRequest))
381 {
382 *data_len = 0;
383 return IPMI_CC_REQ_DATA_LEN_INVALID;
384 }
385
Patrick Venture0b02be92018-08-31 11:55:55 -0700386 auto requestData =
387 reinterpret_cast<const ipmi::sel::ClearSELRequest*>(request);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530388
Jason M. Bills13e67c82018-09-10 14:12:16 -0700389 if (!checkSELReservation(requestData->reservationID))
Tom Joseph2f05bb52017-06-30 19:14:49 +0530390 {
391 *data_len = 0;
392 return IPMI_CC_INVALID_RESERVATION_ID;
393 }
394
Patrick Venture0b02be92018-08-31 11:55:55 -0700395 if (requestData->charC != 'C' || requestData->charL != 'L' ||
Tom Joseph2f05bb52017-06-30 19:14:49 +0530396 requestData->charR != 'R')
397 {
398 *data_len = 0;
399 return IPMI_CC_INVALID_FIELD_REQUEST;
400 }
401
402 uint8_t eraseProgress = ipmi::sel::eraseComplete;
403
404 /*
405 * Erasure status cannot be fetched from DBUS, so always return erasure
406 * status as `erase completed`.
407 */
408 if (requestData->eraseOperation == ipmi::sel::getEraseStatus)
409 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700410 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530411 *data_len = sizeof(eraseProgress);
412 return IPMI_CC_OK;
413 }
414
Jason M. Bills13e67c82018-09-10 14:12:16 -0700415 // Per the IPMI spec, need to cancel any reservation when the SEL is cleared
416 cancelSELReservation();
417
Tom Joseph2f05bb52017-06-30 19:14:49 +0530418 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Tom Josephe59abfb2018-08-06 18:46:27 +0530419 ipmi::sel::ObjectPaths objectPaths;
Tom Joseph2f05bb52017-06-30 19:14:49 +0530420 auto depth = 0;
421
Patrick Venture0b02be92018-08-31 11:55:55 -0700422 auto mapperCall =
423 bus.new_method_call(ipmi::sel::mapperBusName, ipmi::sel::mapperObjPath,
424 ipmi::sel::mapperIntf, "GetSubTreePaths");
Tom Joseph2f05bb52017-06-30 19:14:49 +0530425 mapperCall.append(ipmi::sel::logBasePath);
426 mapperCall.append(depth);
427 mapperCall.append(ipmi::sel::ObjectPaths({ipmi::sel::logEntryIntf}));
428
Tom Josephe59abfb2018-08-06 18:46:27 +0530429 try
Tom Joseph2f05bb52017-06-30 19:14:49 +0530430 {
Tom Josephe59abfb2018-08-06 18:46:27 +0530431 auto reply = bus.call(mapperCall);
432 if (reply.is_method_error())
433 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700434 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Josephe59abfb2018-08-06 18:46:27 +0530435 *data_len = sizeof(eraseProgress);
436 return IPMI_CC_OK;
437 }
Tom Joseph2f05bb52017-06-30 19:14:49 +0530438
Tom Josephe59abfb2018-08-06 18:46:27 +0530439 reply.read(objectPaths);
440 if (objectPaths.empty())
441 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700442 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Josephe59abfb2018-08-06 18:46:27 +0530443 *data_len = sizeof(eraseProgress);
444 return IPMI_CC_OK;
445 }
446 }
447 catch (const sdbusplus::exception::SdBusError& e)
Tom Joseph2f05bb52017-06-30 19:14:49 +0530448 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700449 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530450 *data_len = sizeof(eraseProgress);
451 return IPMI_CC_OK;
452 }
453
454 std::string service;
455
456 try
457 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700458 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf,
Tom Joseph2f05bb52017-06-30 19:14:49 +0530459 objectPaths.front());
460 }
461 catch (const std::runtime_error& e)
462 {
463 log<level::ERR>(e.what());
464 *data_len = 0;
465 return IPMI_CC_UNSPECIFIED_ERROR;
466 }
467
468 for (const auto& iter : objectPaths)
469 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700470 auto methodCall = bus.new_method_call(
471 service.c_str(), iter.c_str(), ipmi::sel::logDeleteIntf, "Delete");
Tom Joseph2f05bb52017-06-30 19:14:49 +0530472
473 auto reply = bus.call(methodCall);
474 if (reply.is_method_error())
475 {
476 *data_len = 0;
477 return IPMI_CC_UNSPECIFIED_ERROR;
478 }
479 }
480
481 // Invalidate the cache of dbus entry objects.
482 cache::paths.clear();
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700483 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530484 *data_len = sizeof(eraseProgress);
485 return IPMI_CC_OK;
486}
487
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500488ipmi_ret_t ipmi_storage_get_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700489 ipmi_request_t request,
490 ipmi_response_t response,
491 ipmi_data_len_t data_len,
492 ipmi_context_t context)
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500493{
Jason M. Bills851acb12019-02-04 14:06:57 -0800494 if (*data_len != 0)
495 {
496 *data_len = 0;
497 return IPMI_CC_REQ_DATA_LEN_INVALID;
498 }
499
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530500 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530501 uint64_t host_time_usec = 0;
502 uint32_t resp = 0;
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500503 std::stringstream hostTime;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500504
Lei YUe8939392017-06-15 10:45:05 +0800505 try
506 {
507 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
508 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
509 sdbusplus::message::variant<uint64_t> value;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530510
Lei YUe8939392017-06-15 10:45:05 +0800511 // Get host time
Patrick Venture0b02be92018-08-31 11:55:55 -0700512 auto method = bus.new_method_call(service.c_str(), HOST_TIME_PATH,
513 DBUS_PROPERTIES, "Get");
Lei YUe8939392017-06-15 10:45:05 +0800514
515 method.append(TIME_INTERFACE, PROPERTY_ELAPSED);
516 auto reply = bus.call(method);
517 if (reply.is_method_error())
518 {
519 log<level::ERR>("Error getting time",
520 entry("SERVICE=%s", service.c_str()),
521 entry("PATH=%s", HOST_TIME_PATH));
522 return IPMI_CC_UNSPECIFIED_ERROR;
523 }
524 reply.read(value);
William A. Kennington III4c008022018-10-12 17:18:14 -0700525 host_time_usec = variant_ns::get<uint64_t>(value);
Lei YUe8939392017-06-15 10:45:05 +0800526 }
527 catch (InternalFailure& e)
528 {
529 log<level::ERR>(e.what());
530 return IPMI_CC_UNSPECIFIED_ERROR;
531 }
532 catch (const std::runtime_error& e)
533 {
534 log<level::ERR>(e.what());
535 return IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530536 }
537
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500538 hostTime << "Host time:" << getTimeString(host_time_usec);
539 log<level::DEBUG>(hostTime.str().c_str());
540
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530541 // Time is really long int but IPMI wants just uint32. This works okay until
542 // the number of seconds since 1970 overflows uint32 size.. Still a whole
543 // lot of time here to even think about that.
544 resp = duration_cast<seconds>(microseconds(host_time_usec)).count();
545 resp = htole32(resp);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530546
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500547 // From the IPMI Spec 2.0, response should be a 32-bit value
548 *data_len = sizeof(resp);
549
550 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700551 std::memcpy(response, &resp, *data_len);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500552
Lei YUe8939392017-06-15 10:45:05 +0800553 return IPMI_CC_OK;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500554}
555
556ipmi_ret_t ipmi_storage_set_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700557 ipmi_request_t request,
558 ipmi_response_t response,
559 ipmi_data_len_t data_len,
560 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500561{
Jason M. Bills851acb12019-02-04 14:06:57 -0800562 if (*data_len != sizeof(uint32_t))
563 {
564 *data_len = 0;
565 return IPMI_CC_REQ_DATA_LEN_INVALID;
566 }
Lei YUe8939392017-06-15 10:45:05 +0800567 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530568 ipmi_ret_t rc = IPMI_CC_OK;
Lei YUe8939392017-06-15 10:45:05 +0800569 uint32_t secs = *static_cast<uint32_t*>(request);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530570 *data_len = 0;
Chris Austenb4f5b922015-10-13 12:44:43 -0500571
Lei YUe8939392017-06-15 10:45:05 +0800572 secs = le32toh(secs);
573 microseconds usec{seconds(secs)};
Norman James82330442015-11-19 16:53:26 -0600574
Lei YUe8939392017-06-15 10:45:05 +0800575 try
576 {
577 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
578 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
579 sdbusplus::message::variant<uint64_t> value{usec.count()};
580
581 // Set host time
Patrick Venture0b02be92018-08-31 11:55:55 -0700582 auto method = bus.new_method_call(service.c_str(), HOST_TIME_PATH,
583 DBUS_PROPERTIES, "Set");
Lei YUe8939392017-06-15 10:45:05 +0800584
585 method.append(TIME_INTERFACE, PROPERTY_ELAPSED, value);
586 auto reply = bus.call(method);
587 if (reply.is_method_error())
588 {
589 log<level::ERR>("Error setting time",
590 entry("SERVICE=%s", service.c_str()),
591 entry("PATH=%s", HOST_TIME_PATH));
592 rc = IPMI_CC_UNSPECIFIED_ERROR;
593 }
Norman James82330442015-11-19 16:53:26 -0600594 }
Lei YUe8939392017-06-15 10:45:05 +0800595 catch (InternalFailure& e)
596 {
597 log<level::ERR>(e.what());
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530598 rc = IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530599 }
Lei YUe8939392017-06-15 10:45:05 +0800600 catch (const std::runtime_error& e)
601 {
602 log<level::ERR>(e.what());
Norman James82330442015-11-19 16:53:26 -0600603 rc = IPMI_CC_UNSPECIFIED_ERROR;
604 }
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530605
Chris Austenb4f5b922015-10-13 12:44:43 -0500606 return rc;
607}
608
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500609ipmi_ret_t ipmi_storage_reserve_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700610 ipmi_request_t request,
611 ipmi_response_t response,
612 ipmi_data_len_t data_len,
613 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500614{
Jason M. Bills851acb12019-02-04 14:06:57 -0800615 if (*data_len != 0)
616 {
617 *data_len = 0;
618 return IPMI_CC_REQ_DATA_LEN_INVALID;
619 }
620
Chris Austenb4f5b922015-10-13 12:44:43 -0500621 ipmi_ret_t rc = IPMI_CC_OK;
Jason M. Bills13e67c82018-09-10 14:12:16 -0700622 unsigned short selResID = reserveSel();
Chris Austenb4f5b922015-10-13 12:44:43 -0500623
Jason M. Bills13e67c82018-09-10 14:12:16 -0700624 *data_len = sizeof(selResID);
Chris Austenb4f5b922015-10-13 12:44:43 -0500625
626 // Pack the actual response
Jason M. Bills13e67c82018-09-10 14:12:16 -0700627 std::memcpy(response, &selResID, *data_len);
Chris Austenb4f5b922015-10-13 12:44:43 -0500628
629 return rc;
630}
631
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500632ipmi_ret_t ipmi_storage_add_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700633 ipmi_request_t request,
634 ipmi_response_t response,
635 ipmi_data_len_t data_len,
636 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500637{
Jason M. Bills851acb12019-02-04 14:06:57 -0800638 if (*data_len != sizeof(ipmi_add_sel_request_t))
639 {
640 *data_len = 0;
641 return IPMI_CC_REQ_DATA_LEN_INVALID;
642 }
Chris Austenb4f5b922015-10-13 12:44:43 -0500643
644 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -0700645 ipmi_add_sel_request_t* p = (ipmi_add_sel_request_t*)request;
Chris Austen41a4b312015-10-25 03:45:42 -0500646 uint16_t recordid;
Chris Austenb4f5b922015-10-13 12:44:43 -0500647
Jason M. Bills13e67c82018-09-10 14:12:16 -0700648 // Per the IPMI spec, need to cancel the reservation when a SEL entry is
649 // added
650 cancelSELReservation();
651
Chris Austen313d95b2015-10-31 12:55:30 -0500652 recordid = ((uint16_t)p->eventdata[1] << 8) | p->eventdata[2];
Chris Austen41a4b312015-10-25 03:45:42 -0500653
Jason M. Bills13e67c82018-09-10 14:12:16 -0700654 *data_len = sizeof(recordid);
Chris Austenb4f5b922015-10-13 12:44:43 -0500655
656 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700657 std::memcpy(response, &p->eventdata[1], 2);
Chris Austenb4f5b922015-10-13 12:44:43 -0500658
Tom Josephb647d5b2017-10-31 17:25:33 +0530659 // Hostboot sends SEL with OEM record type 0xDE to indicate that there is
660 // a maintenance procedure associated with eSEL record.
661 static constexpr auto procedureType = 0xDE;
662 if (p->recordtype == procedureType)
663 {
664 // In the OEM record type 0xDE, byte 11 in the SEL record indicate the
665 // procedure number.
666 createProcedureLogEntry(p->sensortype);
667 }
Chris Austenb4f5b922015-10-13 12:44:43 -0500668
669 return rc;
670}
671
Patrick Venture0b02be92018-08-31 11:55:55 -0700672// Read FRU info area
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500673ipmi_ret_t ipmi_storage_get_fru_inv_area_info(
Patrick Venture0b02be92018-08-31 11:55:55 -0700674 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
675 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500676{
677 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500678 const FruInvenAreaInfoRequest* reqptr =
679 reinterpret_cast<const FruInvenAreaInfoRequest*>(request);
Tom Joseph187f5642018-03-29 13:49:06 +0530680
681 auto iter = frus.find(reqptr->fruID);
682 if (iter == frus.end())
683 {
684 *data_len = 0;
685 return IPMI_CC_SENSOR_INVALID;
686 }
687
Marri Devender Raocac383b2017-07-03 13:24:27 -0500688 try
689 {
690 const auto& fruArea = getFruAreaData(reqptr->fruID);
691 auto size = static_cast<uint16_t>(fruArea.size());
692 FruInvenAreaInfoResponse resp;
693 resp.sizems = size >> 8;
694 resp.sizels = size;
695 resp.access = static_cast<uint8_t>(AccessMode::bytes);
696
697 *data_len = sizeof(resp);
698
699 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700700 std::memcpy(response, &resp, *data_len);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500701 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700702 catch (const InternalFailure& e)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500703 {
704 rc = IPMI_CC_UNSPECIFIED_ERROR;
705 *data_len = 0;
706 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500707 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500708 return rc;
709}
710
Patrick Venture0b02be92018-08-31 11:55:55 -0700711// Read FRU data
712ipmi_ret_t ipmi_storage_read_fru_data(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
713 ipmi_request_t request,
714 ipmi_response_t response,
715 ipmi_data_len_t data_len,
716 ipmi_context_t context)
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500717{
718 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500719 const ReadFruDataRequest* reqptr =
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500720 reinterpret_cast<const ReadFruDataRequest*>(request);
Patrick Venture0b02be92018-08-31 11:55:55 -0700721 auto resptr = reinterpret_cast<ReadFruDataResponse*>(response);
Tom Joseph187f5642018-03-29 13:49:06 +0530722
723 auto iter = frus.find(reqptr->fruID);
724 if (iter == frus.end())
725 {
726 *data_len = 0;
727 return IPMI_CC_SENSOR_INVALID;
728 }
729
Marri Devender Raocac383b2017-07-03 13:24:27 -0500730 auto offset =
731 static_cast<uint16_t>(reqptr->offsetMS << 8 | reqptr->offsetLS);
732 try
733 {
734 const auto& fruArea = getFruAreaData(reqptr->fruID);
735 auto size = fruArea.size();
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500736
Tom Josephefcd68b2018-04-26 18:46:27 +0530737 if (offset >= size)
738 {
739 return IPMI_CC_PARM_OUT_OF_RANGE;
740 }
741
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500742 // Write the count of response data.
743 if ((offset + reqptr->count) <= size)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500744 {
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500745 resptr->count = reqptr->count;
746 }
747 else
748 {
749 resptr->count = size - offset;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500750 }
Ratan Gupta2848d602018-01-31 20:39:20 +0530751
Ratan Gupta2848d602018-01-31 20:39:20 +0530752 std::copy((fruArea.begin() + offset),
Patrick Venture0b02be92018-08-31 11:55:55 -0700753 (fruArea.begin() + offset + resptr->count), resptr->data);
Ratan Gupta2848d602018-01-31 20:39:20 +0530754
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500755 *data_len = resptr->count + 1; // additional one byte for count
Marri Devender Raocac383b2017-07-03 13:24:27 -0500756 }
757 catch (const InternalFailure& e)
758 {
759 rc = IPMI_CC_UNSPECIFIED_ERROR;
760 *data_len = 0;
761 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500762 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500763 return rc;
764}
765
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600766ipmi_ret_t ipmi_get_repository_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700767 ipmi_request_t request,
768 ipmi_response_t response,
769 ipmi_data_len_t data_len,
770 ipmi_context_t context)
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600771{
772 constexpr auto sdrVersion = 0x51;
Patrick Venture0b02be92018-08-31 11:55:55 -0700773 auto responseData = reinterpret_cast<GetRepositoryInfoResponse*>(response);
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600774
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700775 std::memset(responseData, 0, sizeof(GetRepositoryInfoResponse));
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600776
777 responseData->sdrVersion = sdrVersion;
778
779 uint16_t records = frus.size() + sensors.size();
780 responseData->recordCountMs = records >> 8;
781 responseData->recordCountLs = records;
782
783 responseData->freeSpace[0] = 0xFF;
784 responseData->freeSpace[1] = 0xFF;
785
786 *data_len = sizeof(GetRepositoryInfoResponse);
787
788 return IPMI_CC_OK;
789}
Chris Austenb4f5b922015-10-13 12:44:43 -0500790
Chris Austenb4f5b922015-10-13 12:44:43 -0500791void register_netfn_storage_functions()
792{
Tom05732372016-09-06 17:21:23 +0530793 // <Wildcard Command>
Patrick Venture0b02be92018-08-31 11:55:55 -0700794 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WILDCARD, NULL,
795 ipmi_storage_wildcard, PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500796
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530797 // <Get SEL Info>
Patrick Venture0b02be92018-08-31 11:55:55 -0700798 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO, NULL,
799 getSELInfo, PRIVILEGE_USER);
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530800
Tom05732372016-09-06 17:21:23 +0530801 // <Get SEL Time>
Patrick Venture0b02be92018-08-31 11:55:55 -0700802 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME, NULL,
803 ipmi_storage_get_sel_time, PRIVILEGE_USER);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500804
Tom05732372016-09-06 17:21:23 +0530805 // <Set SEL Time>
Patrick Venture0b02be92018-08-31 11:55:55 -0700806 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME, NULL,
807 ipmi_storage_set_sel_time, PRIVILEGE_OPERATOR);
Chris Austenb4f5b922015-10-13 12:44:43 -0500808
Tom05732372016-09-06 17:21:23 +0530809 // <Reserve SEL>
Patrick Venture0b02be92018-08-31 11:55:55 -0700810 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL, NULL,
811 ipmi_storage_reserve_sel, PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500812
Tom Josepha4953392017-06-30 19:09:47 +0530813 // <Get SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700814 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY, NULL,
815 getSELEntry, PRIVILEGE_USER);
Tom Josepha4953392017-06-30 19:09:47 +0530816
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530817 // <Delete SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700818 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_DELETE_SEL, NULL,
819 deleteSELEntry, PRIVILEGE_OPERATOR);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530820
Tom05732372016-09-06 17:21:23 +0530821 // <Add SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700822 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_ADD_SEL, NULL,
823 ipmi_storage_add_sel, PRIVILEGE_OPERATOR);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530824 // <Clear SEL>
Tom Joseph2f05bb52017-06-30 19:14:49 +0530825 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_CLEAR_SEL, NULL, clearSEL,
826 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500827 // <Get FRU Inventory Area Info>
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500828 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_FRU_INV_AREA_INFO, NULL,
Patrick Venture0b02be92018-08-31 11:55:55 -0700829 ipmi_storage_get_fru_inv_area_info,
830 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500831
832 // <Add READ FRU Data
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500833 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_READ_FRU_DATA, NULL,
Patrick Venture0b02be92018-08-31 11:55:55 -0700834 ipmi_storage_read_fru_data, PRIVILEGE_OPERATOR);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500835
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600836 // <Get Repository Info>
837 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_REPOSITORY_INFO,
Patrick Venture0b02be92018-08-31 11:55:55 -0700838 nullptr, ipmi_get_repository_info, PRIVILEGE_USER);
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600839
Tom Joseph5ca50952018-02-22 00:33:38 +0530840 // <Reserve SDR Repository>
Patrick Venture0b02be92018-08-31 11:55:55 -0700841 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SDR, nullptr,
842 ipmi_sen_reserve_sdr, PRIVILEGE_USER);
Tom Joseph5ca50952018-02-22 00:33:38 +0530843
844 // <Get SDR>
Patrick Venture0b02be92018-08-31 11:55:55 -0700845 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SDR, nullptr,
846 ipmi_sen_get_sdr, PRIVILEGE_USER);
Tom Joseph5ca50952018-02-22 00:33:38 +0530847
Marri Devender Rao908f7502017-07-10 01:49:54 -0500848 ipmi::fru::registerCallbackHandler();
Chris Austenb4f5b922015-10-13 12:44:43 -0500849 return;
850}