blob: c225279e41342be799e56884d5c08f5b0b5cf876 [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>
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
65using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070066 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Tom Joseph6f7deaa2017-06-30 19:03:54 +053067using namespace phosphor::logging;
Marri Devender Raocac383b2017-07-03 13:24:27 -050068using namespace ipmi::fru;
69
70/**
71 * @enum Device access mode
72 */
73enum class AccessMode
74{
75 bytes, ///< Device is accessed by bytes
76 words ///< Device is accessed by words
77};
78
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -050079ipmi_ret_t ipmi_storage_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -070080 ipmi_request_t request,
81 ipmi_response_t response,
82 ipmi_data_len_t data_len,
83 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -050084{
Chris Austenb4f5b922015-10-13 12:44:43 -050085 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +080086 ipmi_ret_t rc = IPMI_CC_INVALID;
Chris Austenb4f5b922015-10-13 12:44:43 -050087 *data_len = 0;
88 return rc;
89}
90
Tom Joseph6f7deaa2017-06-30 19:03:54 +053091ipmi_ret_t getSELInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
92 ipmi_request_t request, ipmi_response_t response,
93 ipmi_data_len_t data_len, ipmi_context_t context)
94{
Jason M. Bills851acb12019-02-04 14:06:57 -080095 if (*data_len != 0)
96 {
97 *data_len = 0;
98 return IPMI_CC_REQ_DATA_LEN_INVALID;
99 }
100
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530101 std::vector<uint8_t> outPayload(sizeof(ipmi::sel::GetSELInfoResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700102 auto responseData =
103 reinterpret_cast<ipmi::sel::GetSELInfoResponse*>(outPayload.data());
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530104
105 responseData->selVersion = ipmi::sel::selVersion;
106 // Last erase timestamp is not available from log manager.
107 responseData->eraseTimeStamp = ipmi::sel::invalidTimeStamp;
108 responseData->operationSupport = ipmi::sel::operationSupport;
109
Tom Josephe59abfb2018-08-06 18:46:27 +0530110 try
111 {
112 ipmi::sel::readLoggingObjectPaths(cache::paths);
113 }
114 catch (const sdbusplus::exception::SdBusError& e)
115 {
116 // No action if reading log objects have failed for this command.
117 // readLoggingObjectPaths will throw exception if there are no log
118 // entries. The command will be responded with number of SEL entries
119 // as 0.
120 }
121
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530122 responseData->entries = 0;
123 responseData->addTimeStamp = ipmi::sel::invalidTimeStamp;
124
125 if (!cache::paths.empty())
126 {
127 responseData->entries = static_cast<uint16_t>(cache::paths.size());
128
129 try
130 {
131 responseData->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
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700143 std::memcpy(response, outPayload.data(), outPayload.size());
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530144 *data_len = outPayload.size();
145
146 return IPMI_CC_OK;
147}
148
Tom Josepha4953392017-06-30 19:09:47 +0530149ipmi_ret_t getSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
150 ipmi_request_t request, ipmi_response_t response,
151 ipmi_data_len_t data_len, ipmi_context_t context)
152{
Jason M. Bills851acb12019-02-04 14:06:57 -0800153 if (*data_len != sizeof(ipmi::sel::GetSELEntryRequest))
154 {
155 *data_len = 0;
156 return IPMI_CC_REQ_DATA_LEN_INVALID;
157 }
158
Patrick Venture0b02be92018-08-31 11:55:55 -0700159 auto requestData =
160 reinterpret_cast<const ipmi::sel::GetSELEntryRequest*>(request);
Tom Josepha4953392017-06-30 19:09:47 +0530161
162 if (requestData->reservationID != 0)
163 {
Jason M. Bills13e67c82018-09-10 14:12:16 -0700164 if (!checkSELReservation(requestData->reservationID))
Tom Josepha4953392017-06-30 19:09:47 +0530165 {
166 *data_len = 0;
167 return IPMI_CC_INVALID_RESERVATION_ID;
168 }
169 }
170
171 if (cache::paths.empty())
172 {
173 *data_len = 0;
174 return IPMI_CC_SENSOR_INVALID;
175 }
176
177 ipmi::sel::ObjectPaths::const_iterator iter;
178
179 // Check for the requested SEL Entry.
180 if (requestData->selRecordID == ipmi::sel::firstEntry)
181 {
182 iter = cache::paths.begin();
183 }
184 else if (requestData->selRecordID == ipmi::sel::lastEntry)
185 {
186 iter = cache::paths.end();
187 }
188 else
189 {
190 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
191 std::to_string(requestData->selRecordID);
192
193 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
194 if (iter == cache::paths.end())
195 {
196 *data_len = 0;
197 return IPMI_CC_SENSOR_INVALID;
198 }
199 }
200
Patrick Venture0b02be92018-08-31 11:55:55 -0700201 ipmi::sel::GetSELEntryResponse record{};
Tom Josepha4953392017-06-30 19:09:47 +0530202
203 // Convert the log entry into SEL record.
204 try
205 {
206 record = ipmi::sel::convertLogEntrytoSEL(*iter);
207 }
208 catch (InternalFailure& e)
209 {
210 *data_len = 0;
211 return IPMI_CC_UNSPECIFIED_ERROR;
212 }
213 catch (const std::runtime_error& e)
214 {
215 log<level::ERR>(e.what());
216 *data_len = 0;
217 return IPMI_CC_UNSPECIFIED_ERROR;
218 }
219
Tom Josepha4953392017-06-30 19:09:47 +0530220 // Identify the next SEL record ID
Patrick Venture0b02be92018-08-31 11:55:55 -0700221 if (iter != cache::paths.end())
Tom Josepha4953392017-06-30 19:09:47 +0530222 {
223 ++iter;
224 if (iter == cache::paths.end())
225 {
226 record.nextRecordID = ipmi::sel::lastEntry;
227 }
228 else
229 {
Vernon Mauery185b9f82018-07-20 10:52:36 -0700230 namespace fs = std::filesystem;
Tom Josepha4953392017-06-30 19:09:47 +0530231 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700232 record.nextRecordID = static_cast<uint16_t>(
233 std::stoul(std::string(path.filename().c_str())));
Tom Josepha4953392017-06-30 19:09:47 +0530234 }
235 }
236 else
237 {
238 record.nextRecordID = ipmi::sel::lastEntry;
239 }
240
241 if (requestData->readLength == ipmi::sel::entireRecord)
242 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700243 std::memcpy(response, &record, sizeof(record));
Tom Josepha4953392017-06-30 19:09:47 +0530244 *data_len = sizeof(record);
245 }
246 else
247 {
248 if (requestData->offset >= ipmi::sel::selRecordSize ||
249 requestData->readLength > ipmi::sel::selRecordSize)
250 {
251 *data_len = 0;
252 return IPMI_CC_INVALID_FIELD_REQUEST;
253 }
254
255 auto diff = ipmi::sel::selRecordSize - requestData->offset;
Patrick Venture0b02be92018-08-31 11:55:55 -0700256 auto readLength =
257 std::min(diff, static_cast<int>(requestData->readLength));
Tom Josepha4953392017-06-30 19:09:47 +0530258
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700259 std::memcpy(response, &record.nextRecordID,
260 sizeof(record.nextRecordID));
261 std::memcpy(static_cast<uint8_t*>(response) +
262 sizeof(record.nextRecordID),
263 &record.recordID + requestData->offset, readLength);
Tom Josepha4953392017-06-30 19:09:47 +0530264 *data_len = sizeof(record.nextRecordID) + readLength;
265 }
266
267 return IPMI_CC_OK;
268}
269
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530270ipmi_ret_t deleteSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
271 ipmi_request_t request, ipmi_response_t response,
272 ipmi_data_len_t data_len, ipmi_context_t context)
273{
Jason M. Bills851acb12019-02-04 14:06:57 -0800274 if (*data_len != sizeof(ipmi::sel::DeleteSELEntryRequest))
275 {
276 *data_len = 0;
277 return IPMI_CC_REQ_DATA_LEN_INVALID;
278 }
279
Brad Bishop1a4117b2018-11-21 15:48:18 -0500280 namespace fs = std::filesystem;
Patrick Venture0b02be92018-08-31 11:55:55 -0700281 auto requestData =
282 reinterpret_cast<const ipmi::sel::DeleteSELEntryRequest*>(request);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530283
Jason M. Bills13e67c82018-09-10 14:12:16 -0700284 if (!checkSELReservation(requestData->reservationID))
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530285 {
286 *data_len = 0;
287 return IPMI_CC_INVALID_RESERVATION_ID;
288 }
289
Jason M. Bills13e67c82018-09-10 14:12:16 -0700290 // Per the IPMI spec, need to cancel the reservation when a SEL entry is
291 // deleted
292 cancelSELReservation();
293
Tom Josephe59abfb2018-08-06 18:46:27 +0530294 try
295 {
296 ipmi::sel::readLoggingObjectPaths(cache::paths);
297 }
298 catch (const sdbusplus::exception::SdBusError& e)
299 {
300 // readLoggingObjectPaths will throw exception if there are no error
301 // log entries.
302 *data_len = 0;
303 return IPMI_CC_SENSOR_INVALID;
304 }
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530305
306 if (cache::paths.empty())
307 {
308 *data_len = 0;
309 return IPMI_CC_SENSOR_INVALID;
310 }
311
312 ipmi::sel::ObjectPaths::const_iterator iter;
313 uint16_t delRecordID = 0;
314
315 if (requestData->selRecordID == ipmi::sel::firstEntry)
316 {
317 iter = cache::paths.begin();
318 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700319 delRecordID = static_cast<uint16_t>(
320 std::stoul(std::string(path.filename().c_str())));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530321 }
322 else if (requestData->selRecordID == ipmi::sel::lastEntry)
323 {
324 iter = cache::paths.end();
325 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700326 delRecordID = static_cast<uint16_t>(
327 std::stoul(std::string(path.filename().c_str())));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530328 }
329 else
330 {
331 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
332 std::to_string(requestData->selRecordID);
333
334 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
335 if (iter == cache::paths.end())
336 {
337 *data_len = 0;
338 return IPMI_CC_SENSOR_INVALID;
339 }
340 delRecordID = requestData->selRecordID;
341 }
342
343 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
344 std::string service;
345
346 try
347 {
348 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf, *iter);
349 }
350 catch (const std::runtime_error& e)
351 {
352 log<level::ERR>(e.what());
353 *data_len = 0;
354 return IPMI_CC_UNSPECIFIED_ERROR;
355 }
356
Patrick Venture0b02be92018-08-31 11:55:55 -0700357 auto methodCall = bus.new_method_call(service.c_str(), (*iter).c_str(),
358 ipmi::sel::logDeleteIntf, "Delete");
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530359 auto reply = bus.call(methodCall);
360 if (reply.is_method_error())
361 {
362 *data_len = 0;
363 return IPMI_CC_UNSPECIFIED_ERROR;
364 }
365
366 // Invalidate the cache of dbus entry objects.
367 cache::paths.clear();
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700368 std::memcpy(response, &delRecordID, sizeof(delRecordID));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530369 *data_len = sizeof(delRecordID);
370
371 return IPMI_CC_OK;
372}
373
Tom Joseph2f05bb52017-06-30 19:14:49 +0530374ipmi_ret_t clearSEL(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
375 ipmi_response_t response, ipmi_data_len_t data_len,
376 ipmi_context_t context)
377{
Jason M. Bills851acb12019-02-04 14:06:57 -0800378 if (*data_len != sizeof(ipmi::sel::ClearSELRequest))
379 {
380 *data_len = 0;
381 return IPMI_CC_REQ_DATA_LEN_INVALID;
382 }
383
Patrick Venture0b02be92018-08-31 11:55:55 -0700384 auto requestData =
385 reinterpret_cast<const ipmi::sel::ClearSELRequest*>(request);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530386
Jason M. Bills13e67c82018-09-10 14:12:16 -0700387 if (!checkSELReservation(requestData->reservationID))
Tom Joseph2f05bb52017-06-30 19:14:49 +0530388 {
389 *data_len = 0;
390 return IPMI_CC_INVALID_RESERVATION_ID;
391 }
392
Patrick Venture0b02be92018-08-31 11:55:55 -0700393 if (requestData->charC != 'C' || requestData->charL != 'L' ||
Tom Joseph2f05bb52017-06-30 19:14:49 +0530394 requestData->charR != 'R')
395 {
396 *data_len = 0;
397 return IPMI_CC_INVALID_FIELD_REQUEST;
398 }
399
400 uint8_t eraseProgress = ipmi::sel::eraseComplete;
401
402 /*
403 * Erasure status cannot be fetched from DBUS, so always return erasure
404 * status as `erase completed`.
405 */
406 if (requestData->eraseOperation == ipmi::sel::getEraseStatus)
407 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700408 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530409 *data_len = sizeof(eraseProgress);
410 return IPMI_CC_OK;
411 }
412
Jason M. Bills13e67c82018-09-10 14:12:16 -0700413 // Per the IPMI spec, need to cancel any reservation when the SEL is cleared
414 cancelSELReservation();
415
Tom Joseph2f05bb52017-06-30 19:14:49 +0530416 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Tom Josephe59abfb2018-08-06 18:46:27 +0530417 ipmi::sel::ObjectPaths objectPaths;
Tom Joseph2f05bb52017-06-30 19:14:49 +0530418 auto depth = 0;
419
Patrick Venture0b02be92018-08-31 11:55:55 -0700420 auto mapperCall =
421 bus.new_method_call(ipmi::sel::mapperBusName, ipmi::sel::mapperObjPath,
422 ipmi::sel::mapperIntf, "GetSubTreePaths");
Tom Joseph2f05bb52017-06-30 19:14:49 +0530423 mapperCall.append(ipmi::sel::logBasePath);
424 mapperCall.append(depth);
425 mapperCall.append(ipmi::sel::ObjectPaths({ipmi::sel::logEntryIntf}));
426
Tom Josephe59abfb2018-08-06 18:46:27 +0530427 try
Tom Joseph2f05bb52017-06-30 19:14:49 +0530428 {
Tom Josephe59abfb2018-08-06 18:46:27 +0530429 auto reply = bus.call(mapperCall);
430 if (reply.is_method_error())
431 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700432 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Josephe59abfb2018-08-06 18:46:27 +0530433 *data_len = sizeof(eraseProgress);
434 return IPMI_CC_OK;
435 }
Tom Joseph2f05bb52017-06-30 19:14:49 +0530436
Tom Josephe59abfb2018-08-06 18:46:27 +0530437 reply.read(objectPaths);
438 if (objectPaths.empty())
439 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700440 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Josephe59abfb2018-08-06 18:46:27 +0530441 *data_len = sizeof(eraseProgress);
442 return IPMI_CC_OK;
443 }
444 }
445 catch (const sdbusplus::exception::SdBusError& e)
Tom Joseph2f05bb52017-06-30 19:14:49 +0530446 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700447 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530448 *data_len = sizeof(eraseProgress);
449 return IPMI_CC_OK;
450 }
451
452 std::string service;
453
454 try
455 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700456 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf,
Tom Joseph2f05bb52017-06-30 19:14:49 +0530457 objectPaths.front());
458 }
459 catch (const std::runtime_error& e)
460 {
461 log<level::ERR>(e.what());
462 *data_len = 0;
463 return IPMI_CC_UNSPECIFIED_ERROR;
464 }
465
466 for (const auto& iter : objectPaths)
467 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700468 auto methodCall = bus.new_method_call(
469 service.c_str(), iter.c_str(), ipmi::sel::logDeleteIntf, "Delete");
Tom Joseph2f05bb52017-06-30 19:14:49 +0530470
471 auto reply = bus.call(methodCall);
472 if (reply.is_method_error())
473 {
474 *data_len = 0;
475 return IPMI_CC_UNSPECIFIED_ERROR;
476 }
477 }
478
479 // Invalidate the cache of dbus entry objects.
480 cache::paths.clear();
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700481 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530482 *data_len = sizeof(eraseProgress);
483 return IPMI_CC_OK;
484}
485
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500486ipmi_ret_t ipmi_storage_get_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700487 ipmi_request_t request,
488 ipmi_response_t response,
489 ipmi_data_len_t data_len,
490 ipmi_context_t context)
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500491{
Jason M. Bills851acb12019-02-04 14:06:57 -0800492 if (*data_len != 0)
493 {
494 *data_len = 0;
495 return IPMI_CC_REQ_DATA_LEN_INVALID;
496 }
497
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530498 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530499 uint64_t host_time_usec = 0;
500 uint32_t resp = 0;
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500501 std::stringstream hostTime;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500502
Lei YUe8939392017-06-15 10:45:05 +0800503 try
504 {
505 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
506 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
507 sdbusplus::message::variant<uint64_t> value;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530508
Lei YUe8939392017-06-15 10:45:05 +0800509 // Get host time
Patrick Venture0b02be92018-08-31 11:55:55 -0700510 auto method = bus.new_method_call(service.c_str(), HOST_TIME_PATH,
511 DBUS_PROPERTIES, "Get");
Lei YUe8939392017-06-15 10:45:05 +0800512
513 method.append(TIME_INTERFACE, PROPERTY_ELAPSED);
514 auto reply = bus.call(method);
515 if (reply.is_method_error())
516 {
517 log<level::ERR>("Error getting time",
518 entry("SERVICE=%s", service.c_str()),
519 entry("PATH=%s", HOST_TIME_PATH));
520 return IPMI_CC_UNSPECIFIED_ERROR;
521 }
522 reply.read(value);
Vernon Maueryf442e112019-04-09 11:44:36 -0700523 host_time_usec = std::get<uint64_t>(value);
Lei YUe8939392017-06-15 10:45:05 +0800524 }
525 catch (InternalFailure& e)
526 {
527 log<level::ERR>(e.what());
528 return IPMI_CC_UNSPECIFIED_ERROR;
529 }
530 catch (const std::runtime_error& e)
531 {
532 log<level::ERR>(e.what());
533 return IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530534 }
535
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500536 hostTime << "Host time:" << getTimeString(host_time_usec);
537 log<level::DEBUG>(hostTime.str().c_str());
538
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530539 // Time is really long int but IPMI wants just uint32. This works okay until
540 // the number of seconds since 1970 overflows uint32 size.. Still a whole
541 // lot of time here to even think about that.
542 resp = duration_cast<seconds>(microseconds(host_time_usec)).count();
543 resp = htole32(resp);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530544
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500545 // From the IPMI Spec 2.0, response should be a 32-bit value
546 *data_len = sizeof(resp);
547
548 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700549 std::memcpy(response, &resp, *data_len);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500550
Lei YUe8939392017-06-15 10:45:05 +0800551 return IPMI_CC_OK;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500552}
553
554ipmi_ret_t ipmi_storage_set_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700555 ipmi_request_t request,
556 ipmi_response_t response,
557 ipmi_data_len_t data_len,
558 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500559{
Jason M. Bills851acb12019-02-04 14:06:57 -0800560 if (*data_len != sizeof(uint32_t))
561 {
562 *data_len = 0;
563 return IPMI_CC_REQ_DATA_LEN_INVALID;
564 }
Lei YUe8939392017-06-15 10:45:05 +0800565 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530566 ipmi_ret_t rc = IPMI_CC_OK;
Lei YUe8939392017-06-15 10:45:05 +0800567 uint32_t secs = *static_cast<uint32_t*>(request);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530568 *data_len = 0;
Chris Austenb4f5b922015-10-13 12:44:43 -0500569
Lei YUe8939392017-06-15 10:45:05 +0800570 secs = le32toh(secs);
571 microseconds usec{seconds(secs)};
Norman James82330442015-11-19 16:53:26 -0600572
Lei YUe8939392017-06-15 10:45:05 +0800573 try
574 {
575 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
576 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
577 sdbusplus::message::variant<uint64_t> value{usec.count()};
578
579 // Set host time
Patrick Venture0b02be92018-08-31 11:55:55 -0700580 auto method = bus.new_method_call(service.c_str(), HOST_TIME_PATH,
581 DBUS_PROPERTIES, "Set");
Lei YUe8939392017-06-15 10:45:05 +0800582
583 method.append(TIME_INTERFACE, PROPERTY_ELAPSED, value);
584 auto reply = bus.call(method);
585 if (reply.is_method_error())
586 {
587 log<level::ERR>("Error setting time",
588 entry("SERVICE=%s", service.c_str()),
589 entry("PATH=%s", HOST_TIME_PATH));
590 rc = IPMI_CC_UNSPECIFIED_ERROR;
591 }
Norman James82330442015-11-19 16:53:26 -0600592 }
Lei YUe8939392017-06-15 10:45:05 +0800593 catch (InternalFailure& e)
594 {
595 log<level::ERR>(e.what());
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530596 rc = IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530597 }
Lei YUe8939392017-06-15 10:45:05 +0800598 catch (const std::runtime_error& e)
599 {
600 log<level::ERR>(e.what());
Norman James82330442015-11-19 16:53:26 -0600601 rc = IPMI_CC_UNSPECIFIED_ERROR;
602 }
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530603
Chris Austenb4f5b922015-10-13 12:44:43 -0500604 return rc;
605}
606
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500607ipmi_ret_t ipmi_storage_reserve_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700608 ipmi_request_t request,
609 ipmi_response_t response,
610 ipmi_data_len_t data_len,
611 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500612{
Jason M. Bills851acb12019-02-04 14:06:57 -0800613 if (*data_len != 0)
614 {
615 *data_len = 0;
616 return IPMI_CC_REQ_DATA_LEN_INVALID;
617 }
618
Chris Austenb4f5b922015-10-13 12:44:43 -0500619 ipmi_ret_t rc = IPMI_CC_OK;
Jason M. Bills13e67c82018-09-10 14:12:16 -0700620 unsigned short selResID = reserveSel();
Chris Austenb4f5b922015-10-13 12:44:43 -0500621
Jason M. Bills13e67c82018-09-10 14:12:16 -0700622 *data_len = sizeof(selResID);
Chris Austenb4f5b922015-10-13 12:44:43 -0500623
624 // Pack the actual response
Jason M. Bills13e67c82018-09-10 14:12:16 -0700625 std::memcpy(response, &selResID, *data_len);
Chris Austenb4f5b922015-10-13 12:44:43 -0500626
627 return rc;
628}
629
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500630ipmi_ret_t ipmi_storage_add_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700631 ipmi_request_t request,
632 ipmi_response_t response,
633 ipmi_data_len_t data_len,
634 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500635{
Jason M. Bills851acb12019-02-04 14:06:57 -0800636 if (*data_len != sizeof(ipmi_add_sel_request_t))
637 {
638 *data_len = 0;
639 return IPMI_CC_REQ_DATA_LEN_INVALID;
640 }
Chris Austenb4f5b922015-10-13 12:44:43 -0500641
642 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -0700643 ipmi_add_sel_request_t* p = (ipmi_add_sel_request_t*)request;
Chris Austen41a4b312015-10-25 03:45:42 -0500644 uint16_t recordid;
Chris Austenb4f5b922015-10-13 12:44:43 -0500645
Jason M. Bills13e67c82018-09-10 14:12:16 -0700646 // Per the IPMI spec, need to cancel the reservation when a SEL entry is
647 // added
648 cancelSELReservation();
649
Chris Austen313d95b2015-10-31 12:55:30 -0500650 recordid = ((uint16_t)p->eventdata[1] << 8) | p->eventdata[2];
Chris Austen41a4b312015-10-25 03:45:42 -0500651
Jason M. Bills13e67c82018-09-10 14:12:16 -0700652 *data_len = sizeof(recordid);
Chris Austenb4f5b922015-10-13 12:44:43 -0500653
654 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700655 std::memcpy(response, &p->eventdata[1], 2);
Chris Austenb4f5b922015-10-13 12:44:43 -0500656
Tom Josephb647d5b2017-10-31 17:25:33 +0530657 // Hostboot sends SEL with OEM record type 0xDE to indicate that there is
658 // a maintenance procedure associated with eSEL record.
659 static constexpr auto procedureType = 0xDE;
660 if (p->recordtype == procedureType)
661 {
662 // In the OEM record type 0xDE, byte 11 in the SEL record indicate the
663 // procedure number.
664 createProcedureLogEntry(p->sensortype);
665 }
Chris Austenb4f5b922015-10-13 12:44:43 -0500666
667 return rc;
668}
669
Patrick Venture0b02be92018-08-31 11:55:55 -0700670// Read FRU info area
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500671ipmi_ret_t ipmi_storage_get_fru_inv_area_info(
Patrick Venture0b02be92018-08-31 11:55:55 -0700672 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
673 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500674{
675 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500676 const FruInvenAreaInfoRequest* reqptr =
677 reinterpret_cast<const FruInvenAreaInfoRequest*>(request);
Tom Joseph187f5642018-03-29 13:49:06 +0530678
679 auto iter = frus.find(reqptr->fruID);
680 if (iter == frus.end())
681 {
682 *data_len = 0;
683 return IPMI_CC_SENSOR_INVALID;
684 }
685
Marri Devender Raocac383b2017-07-03 13:24:27 -0500686 try
687 {
688 const auto& fruArea = getFruAreaData(reqptr->fruID);
689 auto size = static_cast<uint16_t>(fruArea.size());
690 FruInvenAreaInfoResponse resp;
691 resp.sizems = size >> 8;
692 resp.sizels = size;
693 resp.access = static_cast<uint8_t>(AccessMode::bytes);
694
695 *data_len = sizeof(resp);
696
697 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700698 std::memcpy(response, &resp, *data_len);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500699 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700700 catch (const InternalFailure& e)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500701 {
702 rc = IPMI_CC_UNSPECIFIED_ERROR;
703 *data_len = 0;
704 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500705 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500706 return rc;
707}
708
Patrick Venture0b02be92018-08-31 11:55:55 -0700709// Read FRU data
710ipmi_ret_t ipmi_storage_read_fru_data(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
711 ipmi_request_t request,
712 ipmi_response_t response,
713 ipmi_data_len_t data_len,
714 ipmi_context_t context)
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500715{
716 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500717 const ReadFruDataRequest* reqptr =
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500718 reinterpret_cast<const ReadFruDataRequest*>(request);
Patrick Venture0b02be92018-08-31 11:55:55 -0700719 auto resptr = reinterpret_cast<ReadFruDataResponse*>(response);
Tom Joseph187f5642018-03-29 13:49:06 +0530720
721 auto iter = frus.find(reqptr->fruID);
722 if (iter == frus.end())
723 {
724 *data_len = 0;
725 return IPMI_CC_SENSOR_INVALID;
726 }
727
Marri Devender Raocac383b2017-07-03 13:24:27 -0500728 auto offset =
729 static_cast<uint16_t>(reqptr->offsetMS << 8 | reqptr->offsetLS);
730 try
731 {
732 const auto& fruArea = getFruAreaData(reqptr->fruID);
733 auto size = fruArea.size();
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500734
Tom Josephefcd68b2018-04-26 18:46:27 +0530735 if (offset >= size)
736 {
737 return IPMI_CC_PARM_OUT_OF_RANGE;
738 }
739
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500740 // Write the count of response data.
741 if ((offset + reqptr->count) <= size)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500742 {
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500743 resptr->count = reqptr->count;
744 }
745 else
746 {
747 resptr->count = size - offset;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500748 }
Ratan Gupta2848d602018-01-31 20:39:20 +0530749
Ratan Gupta2848d602018-01-31 20:39:20 +0530750 std::copy((fruArea.begin() + offset),
Patrick Venture0b02be92018-08-31 11:55:55 -0700751 (fruArea.begin() + offset + resptr->count), resptr->data);
Ratan Gupta2848d602018-01-31 20:39:20 +0530752
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500753 *data_len = resptr->count + 1; // additional one byte for count
Marri Devender Raocac383b2017-07-03 13:24:27 -0500754 }
755 catch (const InternalFailure& e)
756 {
757 rc = IPMI_CC_UNSPECIFIED_ERROR;
758 *data_len = 0;
759 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500760 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500761 return rc;
762}
763
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600764ipmi_ret_t ipmi_get_repository_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700765 ipmi_request_t request,
766 ipmi_response_t response,
767 ipmi_data_len_t data_len,
768 ipmi_context_t context)
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600769{
770 constexpr auto sdrVersion = 0x51;
Patrick Venture0b02be92018-08-31 11:55:55 -0700771 auto responseData = reinterpret_cast<GetRepositoryInfoResponse*>(response);
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600772
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700773 std::memset(responseData, 0, sizeof(GetRepositoryInfoResponse));
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600774
775 responseData->sdrVersion = sdrVersion;
776
777 uint16_t records = frus.size() + sensors.size();
778 responseData->recordCountMs = records >> 8;
779 responseData->recordCountLs = records;
780
781 responseData->freeSpace[0] = 0xFF;
782 responseData->freeSpace[1] = 0xFF;
783
784 *data_len = sizeof(GetRepositoryInfoResponse);
785
786 return IPMI_CC_OK;
787}
Chris Austenb4f5b922015-10-13 12:44:43 -0500788
Chris Austenb4f5b922015-10-13 12:44:43 -0500789void register_netfn_storage_functions()
790{
Tom05732372016-09-06 17:21:23 +0530791 // <Wildcard Command>
Patrick Venture0b02be92018-08-31 11:55:55 -0700792 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WILDCARD, NULL,
793 ipmi_storage_wildcard, PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500794
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530795 // <Get SEL Info>
Patrick Venture0b02be92018-08-31 11:55:55 -0700796 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO, NULL,
797 getSELInfo, PRIVILEGE_USER);
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530798
Tom05732372016-09-06 17:21:23 +0530799 // <Get SEL Time>
Patrick Venture0b02be92018-08-31 11:55:55 -0700800 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME, NULL,
801 ipmi_storage_get_sel_time, PRIVILEGE_USER);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500802
Tom05732372016-09-06 17:21:23 +0530803 // <Set SEL Time>
Patrick Venture0b02be92018-08-31 11:55:55 -0700804 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME, NULL,
805 ipmi_storage_set_sel_time, PRIVILEGE_OPERATOR);
Chris Austenb4f5b922015-10-13 12:44:43 -0500806
Tom05732372016-09-06 17:21:23 +0530807 // <Reserve SEL>
Patrick Venture0b02be92018-08-31 11:55:55 -0700808 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL, NULL,
809 ipmi_storage_reserve_sel, PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500810
Tom Josepha4953392017-06-30 19:09:47 +0530811 // <Get SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700812 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY, NULL,
813 getSELEntry, PRIVILEGE_USER);
Tom Josepha4953392017-06-30 19:09:47 +0530814
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530815 // <Delete SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700816 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_DELETE_SEL, NULL,
817 deleteSELEntry, PRIVILEGE_OPERATOR);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530818
Tom05732372016-09-06 17:21:23 +0530819 // <Add SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700820 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_ADD_SEL, NULL,
821 ipmi_storage_add_sel, PRIVILEGE_OPERATOR);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530822 // <Clear SEL>
Tom Joseph2f05bb52017-06-30 19:14:49 +0530823 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_CLEAR_SEL, NULL, clearSEL,
824 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500825 // <Get FRU Inventory Area Info>
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500826 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_FRU_INV_AREA_INFO, NULL,
Patrick Venture0b02be92018-08-31 11:55:55 -0700827 ipmi_storage_get_fru_inv_area_info,
828 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500829
830 // <Add READ FRU Data
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500831 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_READ_FRU_DATA, NULL,
Patrick Venture0b02be92018-08-31 11:55:55 -0700832 ipmi_storage_read_fru_data, PRIVILEGE_OPERATOR);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500833
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600834 // <Get Repository Info>
835 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_REPOSITORY_INFO,
Patrick Venture0b02be92018-08-31 11:55:55 -0700836 nullptr, ipmi_get_repository_info, PRIVILEGE_USER);
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600837
Tom Joseph5ca50952018-02-22 00:33:38 +0530838 // <Reserve SDR Repository>
Patrick Venture0b02be92018-08-31 11:55:55 -0700839 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SDR, nullptr,
840 ipmi_sen_reserve_sdr, PRIVILEGE_USER);
Tom Joseph5ca50952018-02-22 00:33:38 +0530841
842 // <Get SDR>
Patrick Venture0b02be92018-08-31 11:55:55 -0700843 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SDR, nullptr,
844 ipmi_sen_get_sdr, PRIVILEGE_USER);
Tom Joseph5ca50952018-02-22 00:33:38 +0530845
Marri Devender Rao908f7502017-07-10 01:49:54 -0500846 ipmi::fru::registerCallbackHandler();
Chris Austenb4f5b922015-10-13 12:44:43 -0500847 return;
848}