blob: ebd0a200a13e3611bcde6c6debae01b45f406f53 [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"
8#include "utils.hpp"
9
Lei YU52d91242017-10-17 22:52:28 +080010#include <arpa/inet.h>
Patrick Venture3a5071a2018-09-12 13:27:42 -070011#include <host-ipmid/ipmid-api.h>
12#include <mapper.h>
13#include <systemd/sd-bus.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070014
15#include <algorithm>
Lei YU52d91242017-10-17 22:52:28 +080016#include <chrono>
17#include <cstdio>
Patrick Ventureb51bf9c2018-09-10 15:53:14 -070018#include <cstring>
Patrick Venture3a5071a2018-09-12 13:27:42 -070019#include <phosphor-logging/elog-errors.hpp>
20#include <phosphor-logging/log.hpp>
William A. Kennington III4c008022018-10-12 17:18:14 -070021#include <sdbusplus/message/types.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070022#include <sdbusplus/server.hpp>
23#include <string>
24#include <xyz/openbmc_project/Common/error.hpp>
25
Vernon Mauery185b9f82018-07-20 10:52:36 -070026#if __has_include(<filesystem>)
27#include <filesystem>
28#elif __has_include(<experimental/filesystem>)
Tom Josepha4953392017-06-30 19:09:47 +053029#include <experimental/filesystem>
Patrick Venture0b02be92018-08-31 11:55:55 -070030namespace std
31{
32// splice experimental::filesystem into std
33namespace filesystem = std::experimental::filesystem;
34} // namespace std
Vernon Mauery185b9f82018-07-20 10:52:36 -070035#else
Patrick Venture0b02be92018-08-31 11:55:55 -070036#error filesystem not available
Vernon Mauery185b9f82018-07-20 10:52:36 -070037#endif
Patrick Venture0b02be92018-08-31 11:55:55 -070038
Chris Austenb4f5b922015-10-13 12:44:43 -050039void register_netfn_storage_functions() __attribute__((constructor));
40
Patrick Venture0b02be92018-08-31 11:55:55 -070041unsigned int g_sel_time = 0xFFFFFFFF;
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -060042extern const ipmi::sensor::IdInfoMap sensors;
43extern const FruMap frus;
Chris Austenb4f5b922015-10-13 12:44:43 -050044
Patrick Venture0b02be92018-08-31 11:55:55 -070045namespace
46{
Lei YUe8939392017-06-15 10:45:05 +080047constexpr auto TIME_INTERFACE = "xyz.openbmc_project.Time.EpochTime";
48constexpr auto HOST_TIME_PATH = "/xyz/openbmc_project/time/host";
49constexpr auto DBUS_PROPERTIES = "org.freedesktop.DBus.Properties";
Patrick Venture0b02be92018-08-31 11:55:55 -070050constexpr auto PROPERTY_ELAPSED = "Elapsed";
Lei YUe8939392017-06-15 10:45:05 +080051
52const char* getTimeString(const uint64_t& usecSinceEpoch)
53{
54 using namespace std::chrono;
55 system_clock::time_point tp{microseconds(usecSinceEpoch)};
56 auto t = system_clock::to_time_t(tp);
57 return std::ctime(&t);
58}
Patrick Venture0b02be92018-08-31 11:55:55 -070059} // namespace
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +053060
Tom Joseph6f7deaa2017-06-30 19:03:54 +053061namespace cache
62{
Patrick Venture0b02be92018-08-31 11:55:55 -070063/*
64 * This cache contains the object paths of the logging entries sorted in the
65 * order of the filename(numeric order). The cache is initialized by
66 * invoking readLoggingObjectPaths with the cache as the parameter. The
67 * cache is invoked in the execution of the Get SEL info and Delete SEL
68 * entry command. The Get SEL Info command is typically invoked before the
69 * Get SEL entry command, so the cache is utilized for responding to Get SEL
70 * entry command. The cache is invalidated by clearing after Delete SEL
71 * entry and Clear SEL command.
72 */
73ipmi::sel::ObjectPaths paths;
Tom Joseph6f7deaa2017-06-30 19:03:54 +053074
Patrick Venture0b02be92018-08-31 11:55:55 -070075} // namespace cache
Tom Joseph6f7deaa2017-06-30 19:03:54 +053076
William A. Kennington III4c008022018-10-12 17:18:14 -070077namespace variant_ns = sdbusplus::message::variant_ns;
78
Tom Joseph6f7deaa2017-06-30 19:03:54 +053079using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070080 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Tom Joseph6f7deaa2017-06-30 19:03:54 +053081using namespace phosphor::logging;
Marri Devender Raocac383b2017-07-03 13:24:27 -050082using namespace ipmi::fru;
83
84/**
85 * @enum Device access mode
86 */
87enum class AccessMode
88{
89 bytes, ///< Device is accessed by bytes
90 words ///< Device is accessed by words
91};
92
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -050093ipmi_ret_t ipmi_storage_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -070094 ipmi_request_t request,
95 ipmi_response_t response,
96 ipmi_data_len_t data_len,
97 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -050098{
Chris Austenb4f5b922015-10-13 12:44:43 -050099 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +0800100 ipmi_ret_t rc = IPMI_CC_INVALID;
Chris Austenb4f5b922015-10-13 12:44:43 -0500101 *data_len = 0;
102 return rc;
103}
104
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530105ipmi_ret_t getSELInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
106 ipmi_request_t request, ipmi_response_t response,
107 ipmi_data_len_t data_len, ipmi_context_t context)
108{
109 std::vector<uint8_t> outPayload(sizeof(ipmi::sel::GetSELInfoResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700110 auto responseData =
111 reinterpret_cast<ipmi::sel::GetSELInfoResponse*>(outPayload.data());
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530112
113 responseData->selVersion = ipmi::sel::selVersion;
114 // Last erase timestamp is not available from log manager.
115 responseData->eraseTimeStamp = ipmi::sel::invalidTimeStamp;
116 responseData->operationSupport = ipmi::sel::operationSupport;
117
Tom Josephe59abfb2018-08-06 18:46:27 +0530118 try
119 {
120 ipmi::sel::readLoggingObjectPaths(cache::paths);
121 }
122 catch (const sdbusplus::exception::SdBusError& e)
123 {
124 // No action if reading log objects have failed for this command.
125 // readLoggingObjectPaths will throw exception if there are no log
126 // entries. The command will be responded with number of SEL entries
127 // as 0.
128 }
129
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530130 responseData->entries = 0;
131 responseData->addTimeStamp = ipmi::sel::invalidTimeStamp;
132
133 if (!cache::paths.empty())
134 {
135 responseData->entries = static_cast<uint16_t>(cache::paths.size());
136
137 try
138 {
139 responseData->addTimeStamp = static_cast<uint32_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700140 (ipmi::sel::getEntryTimeStamp(cache::paths.back()).count()));
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530141 }
142 catch (InternalFailure& e)
143 {
144 }
145 catch (const std::runtime_error& e)
146 {
147 log<level::ERR>(e.what());
148 }
149 }
150
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700151 std::memcpy(response, outPayload.data(), outPayload.size());
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530152 *data_len = outPayload.size();
153
154 return IPMI_CC_OK;
155}
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{
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{
Brad Bishop1a4117b2018-11-21 15:48:18 -0500276 namespace fs = std::filesystem;
Patrick Venture0b02be92018-08-31 11:55:55 -0700277 auto requestData =
278 reinterpret_cast<const ipmi::sel::DeleteSELEntryRequest*>(request);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530279
Jason M. Bills13e67c82018-09-10 14:12:16 -0700280 if (!checkSELReservation(requestData->reservationID))
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530281 {
282 *data_len = 0;
283 return IPMI_CC_INVALID_RESERVATION_ID;
284 }
285
Jason M. Bills13e67c82018-09-10 14:12:16 -0700286 // Per the IPMI spec, need to cancel the reservation when a SEL entry is
287 // deleted
288 cancelSELReservation();
289
Tom Josephe59abfb2018-08-06 18:46:27 +0530290 try
291 {
292 ipmi::sel::readLoggingObjectPaths(cache::paths);
293 }
294 catch (const sdbusplus::exception::SdBusError& e)
295 {
296 // readLoggingObjectPaths will throw exception if there are no error
297 // log entries.
298 *data_len = 0;
299 return IPMI_CC_SENSOR_INVALID;
300 }
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530301
302 if (cache::paths.empty())
303 {
304 *data_len = 0;
305 return IPMI_CC_SENSOR_INVALID;
306 }
307
308 ipmi::sel::ObjectPaths::const_iterator iter;
309 uint16_t delRecordID = 0;
310
311 if (requestData->selRecordID == ipmi::sel::firstEntry)
312 {
313 iter = cache::paths.begin();
314 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700315 delRecordID = static_cast<uint16_t>(
316 std::stoul(std::string(path.filename().c_str())));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530317 }
318 else if (requestData->selRecordID == ipmi::sel::lastEntry)
319 {
320 iter = cache::paths.end();
321 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700322 delRecordID = static_cast<uint16_t>(
323 std::stoul(std::string(path.filename().c_str())));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530324 }
325 else
326 {
327 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
328 std::to_string(requestData->selRecordID);
329
330 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
331 if (iter == cache::paths.end())
332 {
333 *data_len = 0;
334 return IPMI_CC_SENSOR_INVALID;
335 }
336 delRecordID = requestData->selRecordID;
337 }
338
339 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
340 std::string service;
341
342 try
343 {
344 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf, *iter);
345 }
346 catch (const std::runtime_error& e)
347 {
348 log<level::ERR>(e.what());
349 *data_len = 0;
350 return IPMI_CC_UNSPECIFIED_ERROR;
351 }
352
Patrick Venture0b02be92018-08-31 11:55:55 -0700353 auto methodCall = bus.new_method_call(service.c_str(), (*iter).c_str(),
354 ipmi::sel::logDeleteIntf, "Delete");
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530355 auto reply = bus.call(methodCall);
356 if (reply.is_method_error())
357 {
358 *data_len = 0;
359 return IPMI_CC_UNSPECIFIED_ERROR;
360 }
361
362 // Invalidate the cache of dbus entry objects.
363 cache::paths.clear();
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700364 std::memcpy(response, &delRecordID, sizeof(delRecordID));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530365 *data_len = sizeof(delRecordID);
366
367 return IPMI_CC_OK;
368}
369
Tom Joseph2f05bb52017-06-30 19:14:49 +0530370ipmi_ret_t clearSEL(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
371 ipmi_response_t response, ipmi_data_len_t data_len,
372 ipmi_context_t context)
373{
Patrick Venture0b02be92018-08-31 11:55:55 -0700374 auto requestData =
375 reinterpret_cast<const ipmi::sel::ClearSELRequest*>(request);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530376
Jason M. Bills13e67c82018-09-10 14:12:16 -0700377 if (!checkSELReservation(requestData->reservationID))
Tom Joseph2f05bb52017-06-30 19:14:49 +0530378 {
379 *data_len = 0;
380 return IPMI_CC_INVALID_RESERVATION_ID;
381 }
382
Patrick Venture0b02be92018-08-31 11:55:55 -0700383 if (requestData->charC != 'C' || requestData->charL != 'L' ||
Tom Joseph2f05bb52017-06-30 19:14:49 +0530384 requestData->charR != 'R')
385 {
386 *data_len = 0;
387 return IPMI_CC_INVALID_FIELD_REQUEST;
388 }
389
390 uint8_t eraseProgress = ipmi::sel::eraseComplete;
391
392 /*
393 * Erasure status cannot be fetched from DBUS, so always return erasure
394 * status as `erase completed`.
395 */
396 if (requestData->eraseOperation == ipmi::sel::getEraseStatus)
397 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700398 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530399 *data_len = sizeof(eraseProgress);
400 return IPMI_CC_OK;
401 }
402
Jason M. Bills13e67c82018-09-10 14:12:16 -0700403 // Per the IPMI spec, need to cancel any reservation when the SEL is cleared
404 cancelSELReservation();
405
Tom Joseph2f05bb52017-06-30 19:14:49 +0530406 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Tom Josephe59abfb2018-08-06 18:46:27 +0530407 ipmi::sel::ObjectPaths objectPaths;
Tom Joseph2f05bb52017-06-30 19:14:49 +0530408 auto depth = 0;
409
Patrick Venture0b02be92018-08-31 11:55:55 -0700410 auto mapperCall =
411 bus.new_method_call(ipmi::sel::mapperBusName, ipmi::sel::mapperObjPath,
412 ipmi::sel::mapperIntf, "GetSubTreePaths");
Tom Joseph2f05bb52017-06-30 19:14:49 +0530413 mapperCall.append(ipmi::sel::logBasePath);
414 mapperCall.append(depth);
415 mapperCall.append(ipmi::sel::ObjectPaths({ipmi::sel::logEntryIntf}));
416
Tom Josephe59abfb2018-08-06 18:46:27 +0530417 try
Tom Joseph2f05bb52017-06-30 19:14:49 +0530418 {
Tom Josephe59abfb2018-08-06 18:46:27 +0530419 auto reply = bus.call(mapperCall);
420 if (reply.is_method_error())
421 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700422 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Josephe59abfb2018-08-06 18:46:27 +0530423 *data_len = sizeof(eraseProgress);
424 return IPMI_CC_OK;
425 }
Tom Joseph2f05bb52017-06-30 19:14:49 +0530426
Tom Josephe59abfb2018-08-06 18:46:27 +0530427 reply.read(objectPaths);
428 if (objectPaths.empty())
429 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700430 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Josephe59abfb2018-08-06 18:46:27 +0530431 *data_len = sizeof(eraseProgress);
432 return IPMI_CC_OK;
433 }
434 }
435 catch (const sdbusplus::exception::SdBusError& e)
Tom Joseph2f05bb52017-06-30 19:14:49 +0530436 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700437 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530438 *data_len = sizeof(eraseProgress);
439 return IPMI_CC_OK;
440 }
441
442 std::string service;
443
444 try
445 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700446 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf,
Tom Joseph2f05bb52017-06-30 19:14:49 +0530447 objectPaths.front());
448 }
449 catch (const std::runtime_error& e)
450 {
451 log<level::ERR>(e.what());
452 *data_len = 0;
453 return IPMI_CC_UNSPECIFIED_ERROR;
454 }
455
456 for (const auto& iter : objectPaths)
457 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700458 auto methodCall = bus.new_method_call(
459 service.c_str(), iter.c_str(), ipmi::sel::logDeleteIntf, "Delete");
Tom Joseph2f05bb52017-06-30 19:14:49 +0530460
461 auto reply = bus.call(methodCall);
462 if (reply.is_method_error())
463 {
464 *data_len = 0;
465 return IPMI_CC_UNSPECIFIED_ERROR;
466 }
467 }
468
469 // Invalidate the cache of dbus entry objects.
470 cache::paths.clear();
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700471 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530472 *data_len = sizeof(eraseProgress);
473 return IPMI_CC_OK;
474}
475
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500476ipmi_ret_t ipmi_storage_get_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700477 ipmi_request_t request,
478 ipmi_response_t response,
479 ipmi_data_len_t data_len,
480 ipmi_context_t context)
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500481{
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530482 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530483 uint64_t host_time_usec = 0;
484 uint32_t resp = 0;
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500485 std::stringstream hostTime;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500486
Lei YUe8939392017-06-15 10:45:05 +0800487 try
488 {
489 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
490 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
491 sdbusplus::message::variant<uint64_t> value;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530492
Lei YUe8939392017-06-15 10:45:05 +0800493 // Get host time
Patrick Venture0b02be92018-08-31 11:55:55 -0700494 auto method = bus.new_method_call(service.c_str(), HOST_TIME_PATH,
495 DBUS_PROPERTIES, "Get");
Lei YUe8939392017-06-15 10:45:05 +0800496
497 method.append(TIME_INTERFACE, PROPERTY_ELAPSED);
498 auto reply = bus.call(method);
499 if (reply.is_method_error())
500 {
501 log<level::ERR>("Error getting time",
502 entry("SERVICE=%s", service.c_str()),
503 entry("PATH=%s", HOST_TIME_PATH));
504 return IPMI_CC_UNSPECIFIED_ERROR;
505 }
506 reply.read(value);
William A. Kennington III4c008022018-10-12 17:18:14 -0700507 host_time_usec = variant_ns::get<uint64_t>(value);
Lei YUe8939392017-06-15 10:45:05 +0800508 }
509 catch (InternalFailure& e)
510 {
511 log<level::ERR>(e.what());
512 return IPMI_CC_UNSPECIFIED_ERROR;
513 }
514 catch (const std::runtime_error& e)
515 {
516 log<level::ERR>(e.what());
517 return IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530518 }
519
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500520 hostTime << "Host time:" << getTimeString(host_time_usec);
521 log<level::DEBUG>(hostTime.str().c_str());
522
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530523 // Time is really long int but IPMI wants just uint32. This works okay until
524 // the number of seconds since 1970 overflows uint32 size.. Still a whole
525 // lot of time here to even think about that.
526 resp = duration_cast<seconds>(microseconds(host_time_usec)).count();
527 resp = htole32(resp);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530528
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500529 // From the IPMI Spec 2.0, response should be a 32-bit value
530 *data_len = sizeof(resp);
531
532 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700533 std::memcpy(response, &resp, *data_len);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500534
Lei YUe8939392017-06-15 10:45:05 +0800535 return IPMI_CC_OK;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500536}
537
538ipmi_ret_t ipmi_storage_set_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700539 ipmi_request_t request,
540 ipmi_response_t response,
541 ipmi_data_len_t data_len,
542 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500543{
Lei YUe8939392017-06-15 10:45:05 +0800544 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530545 ipmi_ret_t rc = IPMI_CC_OK;
Lei YUe8939392017-06-15 10:45:05 +0800546 uint32_t secs = *static_cast<uint32_t*>(request);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530547 *data_len = 0;
Chris Austenb4f5b922015-10-13 12:44:43 -0500548
Lei YUe8939392017-06-15 10:45:05 +0800549 secs = le32toh(secs);
550 microseconds usec{seconds(secs)};
Norman James82330442015-11-19 16:53:26 -0600551
Lei YUe8939392017-06-15 10:45:05 +0800552 try
553 {
554 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
555 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
556 sdbusplus::message::variant<uint64_t> value{usec.count()};
557
558 // Set host time
Patrick Venture0b02be92018-08-31 11:55:55 -0700559 auto method = bus.new_method_call(service.c_str(), HOST_TIME_PATH,
560 DBUS_PROPERTIES, "Set");
Lei YUe8939392017-06-15 10:45:05 +0800561
562 method.append(TIME_INTERFACE, PROPERTY_ELAPSED, value);
563 auto reply = bus.call(method);
564 if (reply.is_method_error())
565 {
566 log<level::ERR>("Error setting time",
567 entry("SERVICE=%s", service.c_str()),
568 entry("PATH=%s", HOST_TIME_PATH));
569 rc = IPMI_CC_UNSPECIFIED_ERROR;
570 }
Norman James82330442015-11-19 16:53:26 -0600571 }
Lei YUe8939392017-06-15 10:45:05 +0800572 catch (InternalFailure& e)
573 {
574 log<level::ERR>(e.what());
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530575 rc = IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530576 }
Lei YUe8939392017-06-15 10:45:05 +0800577 catch (const std::runtime_error& e)
578 {
579 log<level::ERR>(e.what());
Norman James82330442015-11-19 16:53:26 -0600580 rc = IPMI_CC_UNSPECIFIED_ERROR;
581 }
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530582
Chris Austenb4f5b922015-10-13 12:44:43 -0500583 return rc;
584}
585
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500586ipmi_ret_t ipmi_storage_reserve_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700587 ipmi_request_t request,
588 ipmi_response_t response,
589 ipmi_data_len_t data_len,
590 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500591{
Chris Austenb4f5b922015-10-13 12:44:43 -0500592 ipmi_ret_t rc = IPMI_CC_OK;
Jason M. Bills13e67c82018-09-10 14:12:16 -0700593 unsigned short selResID = reserveSel();
Chris Austenb4f5b922015-10-13 12:44:43 -0500594
Jason M. Bills13e67c82018-09-10 14:12:16 -0700595 *data_len = sizeof(selResID);
Chris Austenb4f5b922015-10-13 12:44:43 -0500596
597 // Pack the actual response
Jason M. Bills13e67c82018-09-10 14:12:16 -0700598 std::memcpy(response, &selResID, *data_len);
Chris Austenb4f5b922015-10-13 12:44:43 -0500599
600 return rc;
601}
602
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500603ipmi_ret_t ipmi_storage_add_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700604 ipmi_request_t request,
605 ipmi_response_t response,
606 ipmi_data_len_t data_len,
607 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500608{
609
610 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -0700611 ipmi_add_sel_request_t* p = (ipmi_add_sel_request_t*)request;
Chris Austen41a4b312015-10-25 03:45:42 -0500612 uint16_t recordid;
Chris Austenb4f5b922015-10-13 12:44:43 -0500613
Jason M. Bills13e67c82018-09-10 14:12:16 -0700614 // Per the IPMI spec, need to cancel the reservation when a SEL entry is
615 // added
616 cancelSELReservation();
617
Chris Austen313d95b2015-10-31 12:55:30 -0500618 recordid = ((uint16_t)p->eventdata[1] << 8) | p->eventdata[2];
Chris Austen41a4b312015-10-25 03:45:42 -0500619
Jason M. Bills13e67c82018-09-10 14:12:16 -0700620 *data_len = sizeof(recordid);
Chris Austenb4f5b922015-10-13 12:44:43 -0500621
622 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700623 std::memcpy(response, &p->eventdata[1], 2);
Chris Austenb4f5b922015-10-13 12:44:43 -0500624
Tom Josephb647d5b2017-10-31 17:25:33 +0530625 // Hostboot sends SEL with OEM record type 0xDE to indicate that there is
626 // a maintenance procedure associated with eSEL record.
627 static constexpr auto procedureType = 0xDE;
628 if (p->recordtype == procedureType)
629 {
630 // In the OEM record type 0xDE, byte 11 in the SEL record indicate the
631 // procedure number.
632 createProcedureLogEntry(p->sensortype);
633 }
Tom Josephe19540e2019-02-04 14:06:58 +0530634 else
635 {
636 send_esel(recordid);
637 }
Chris Austenb4f5b922015-10-13 12:44:43 -0500638
639 return rc;
640}
641
Patrick Venture0b02be92018-08-31 11:55:55 -0700642// Read FRU info area
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500643ipmi_ret_t ipmi_storage_get_fru_inv_area_info(
Patrick Venture0b02be92018-08-31 11:55:55 -0700644 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
645 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500646{
647 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500648 const FruInvenAreaInfoRequest* reqptr =
649 reinterpret_cast<const FruInvenAreaInfoRequest*>(request);
Tom Joseph187f5642018-03-29 13:49:06 +0530650
651 auto iter = frus.find(reqptr->fruID);
652 if (iter == frus.end())
653 {
654 *data_len = 0;
655 return IPMI_CC_SENSOR_INVALID;
656 }
657
Marri Devender Raocac383b2017-07-03 13:24:27 -0500658 try
659 {
660 const auto& fruArea = getFruAreaData(reqptr->fruID);
661 auto size = static_cast<uint16_t>(fruArea.size());
662 FruInvenAreaInfoResponse resp;
663 resp.sizems = size >> 8;
664 resp.sizels = size;
665 resp.access = static_cast<uint8_t>(AccessMode::bytes);
666
667 *data_len = sizeof(resp);
668
669 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700670 std::memcpy(response, &resp, *data_len);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500671 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700672 catch (const InternalFailure& e)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500673 {
674 rc = IPMI_CC_UNSPECIFIED_ERROR;
675 *data_len = 0;
676 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500677 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500678 return rc;
679}
680
Patrick Venture0b02be92018-08-31 11:55:55 -0700681// Read FRU data
682ipmi_ret_t ipmi_storage_read_fru_data(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
683 ipmi_request_t request,
684 ipmi_response_t response,
685 ipmi_data_len_t data_len,
686 ipmi_context_t context)
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500687{
688 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500689 const ReadFruDataRequest* reqptr =
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500690 reinterpret_cast<const ReadFruDataRequest*>(request);
Patrick Venture0b02be92018-08-31 11:55:55 -0700691 auto resptr = reinterpret_cast<ReadFruDataResponse*>(response);
Tom Joseph187f5642018-03-29 13:49:06 +0530692
693 auto iter = frus.find(reqptr->fruID);
694 if (iter == frus.end())
695 {
696 *data_len = 0;
697 return IPMI_CC_SENSOR_INVALID;
698 }
699
Marri Devender Raocac383b2017-07-03 13:24:27 -0500700 auto offset =
701 static_cast<uint16_t>(reqptr->offsetMS << 8 | reqptr->offsetLS);
702 try
703 {
704 const auto& fruArea = getFruAreaData(reqptr->fruID);
705 auto size = fruArea.size();
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500706
Tom Josephefcd68b2018-04-26 18:46:27 +0530707 if (offset >= size)
708 {
709 return IPMI_CC_PARM_OUT_OF_RANGE;
710 }
711
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500712 // Write the count of response data.
713 if ((offset + reqptr->count) <= size)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500714 {
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500715 resptr->count = reqptr->count;
716 }
717 else
718 {
719 resptr->count = size - offset;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500720 }
Ratan Gupta2848d602018-01-31 20:39:20 +0530721
Ratan Gupta2848d602018-01-31 20:39:20 +0530722 std::copy((fruArea.begin() + offset),
Patrick Venture0b02be92018-08-31 11:55:55 -0700723 (fruArea.begin() + offset + resptr->count), resptr->data);
Ratan Gupta2848d602018-01-31 20:39:20 +0530724
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500725 *data_len = resptr->count + 1; // additional one byte for count
Marri Devender Raocac383b2017-07-03 13:24:27 -0500726 }
727 catch (const InternalFailure& e)
728 {
729 rc = IPMI_CC_UNSPECIFIED_ERROR;
730 *data_len = 0;
731 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500732 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500733 return rc;
734}
735
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600736ipmi_ret_t ipmi_get_repository_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700737 ipmi_request_t request,
738 ipmi_response_t response,
739 ipmi_data_len_t data_len,
740 ipmi_context_t context)
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600741{
742 constexpr auto sdrVersion = 0x51;
Patrick Venture0b02be92018-08-31 11:55:55 -0700743 auto responseData = reinterpret_cast<GetRepositoryInfoResponse*>(response);
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600744
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700745 std::memset(responseData, 0, sizeof(GetRepositoryInfoResponse));
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600746
747 responseData->sdrVersion = sdrVersion;
748
749 uint16_t records = frus.size() + sensors.size();
750 responseData->recordCountMs = records >> 8;
751 responseData->recordCountLs = records;
752
753 responseData->freeSpace[0] = 0xFF;
754 responseData->freeSpace[1] = 0xFF;
755
756 *data_len = sizeof(GetRepositoryInfoResponse);
757
758 return IPMI_CC_OK;
759}
Chris Austenb4f5b922015-10-13 12:44:43 -0500760
Chris Austenb4f5b922015-10-13 12:44:43 -0500761void register_netfn_storage_functions()
762{
Tom05732372016-09-06 17:21:23 +0530763 // <Wildcard Command>
Patrick Venture0b02be92018-08-31 11:55:55 -0700764 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WILDCARD, NULL,
765 ipmi_storage_wildcard, PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500766
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530767 // <Get SEL Info>
Patrick Venture0b02be92018-08-31 11:55:55 -0700768 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO, NULL,
769 getSELInfo, PRIVILEGE_USER);
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530770
Tom05732372016-09-06 17:21:23 +0530771 // <Get SEL Time>
Patrick Venture0b02be92018-08-31 11:55:55 -0700772 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME, NULL,
773 ipmi_storage_get_sel_time, PRIVILEGE_USER);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500774
Tom05732372016-09-06 17:21:23 +0530775 // <Set SEL Time>
Patrick Venture0b02be92018-08-31 11:55:55 -0700776 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME, NULL,
777 ipmi_storage_set_sel_time, PRIVILEGE_OPERATOR);
Chris Austenb4f5b922015-10-13 12:44:43 -0500778
Tom05732372016-09-06 17:21:23 +0530779 // <Reserve SEL>
Patrick Venture0b02be92018-08-31 11:55:55 -0700780 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL, NULL,
781 ipmi_storage_reserve_sel, PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500782
Tom Josepha4953392017-06-30 19:09:47 +0530783 // <Get SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700784 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY, NULL,
785 getSELEntry, PRIVILEGE_USER);
Tom Josepha4953392017-06-30 19:09:47 +0530786
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530787 // <Delete SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700788 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_DELETE_SEL, NULL,
789 deleteSELEntry, PRIVILEGE_OPERATOR);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530790
Tom05732372016-09-06 17:21:23 +0530791 // <Add SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700792 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_ADD_SEL, NULL,
793 ipmi_storage_add_sel, PRIVILEGE_OPERATOR);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530794 // <Clear SEL>
Tom Joseph2f05bb52017-06-30 19:14:49 +0530795 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_CLEAR_SEL, NULL, clearSEL,
796 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500797 // <Get FRU Inventory Area Info>
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500798 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_FRU_INV_AREA_INFO, NULL,
Patrick Venture0b02be92018-08-31 11:55:55 -0700799 ipmi_storage_get_fru_inv_area_info,
800 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500801
802 // <Add READ FRU Data
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500803 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_READ_FRU_DATA, NULL,
Patrick Venture0b02be92018-08-31 11:55:55 -0700804 ipmi_storage_read_fru_data, PRIVILEGE_OPERATOR);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500805
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600806 // <Get Repository Info>
807 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_REPOSITORY_INFO,
Patrick Venture0b02be92018-08-31 11:55:55 -0700808 nullptr, ipmi_get_repository_info, PRIVILEGE_USER);
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600809
Tom Joseph5ca50952018-02-22 00:33:38 +0530810 // <Reserve SDR Repository>
Patrick Venture0b02be92018-08-31 11:55:55 -0700811 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SDR, nullptr,
812 ipmi_sen_reserve_sdr, PRIVILEGE_USER);
Tom Joseph5ca50952018-02-22 00:33:38 +0530813
814 // <Get SDR>
Patrick Venture0b02be92018-08-31 11:55:55 -0700815 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SDR, nullptr,
816 ipmi_sen_get_sdr, PRIVILEGE_USER);
Tom Joseph5ca50952018-02-22 00:33:38 +0530817
Marri Devender Rao908f7502017-07-10 01:49:54 -0500818 ipmi::fru::registerCallbackHandler();
Chris Austenb4f5b922015-10-13 12:44:43 -0500819 return;
820}