blob: f0997e8c1903231afdc64b799bd09b56e2517275 [file] [log] [blame]
Marri Devender Raocac383b2017-07-03 13:24:27 -05001#include <algorithm>
Lei YU52d91242017-10-17 22:52:28 +08002#include <arpa/inet.h>
3#include <chrono>
4#include <cstdio>
Vernon Mauery185b9f82018-07-20 10:52:36 -07005#if __has_include(<filesystem>)
6#include <filesystem>
7#elif __has_include(<experimental/filesystem>)
Tom Josepha4953392017-06-30 19:09:47 +05308#include <experimental/filesystem>
Vernon Mauery185b9f82018-07-20 10:52:36 -07009namespace std {
10 // splice experimental::filesystem into std
11 namespace filesystem = std::experimental::filesystem;
12}
13#else
14# error filesystem not available
15#endif
Lei YU52d91242017-10-17 22:52:28 +080016#include <mapper.h>
17#include <string>
18#include <systemd/sd-bus.h>
19
Tom Joseph6f7deaa2017-06-30 19:03:54 +053020#include <phosphor-logging/log.hpp>
Marri Devender Raocac383b2017-07-03 13:24:27 -050021#include <phosphor-logging/elog-errors.hpp>
Lei YU52d91242017-10-17 22:52:28 +080022#include <sdbusplus/server.hpp>
23
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -060024#include "fruread.hpp"
Lei YU52d91242017-10-17 22:52:28 +080025#include "host-ipmid/ipmid-api.h"
26#include "read_fru_data.hpp"
27#include "selutility.hpp"
28#include "storageaddsel.h"
29#include "storagehandler.h"
30#include "utils.hpp"
31#include "xyz/openbmc_project/Common/error.hpp"
Tom Joseph5ca50952018-02-22 00:33:38 +053032#include "sensorhandler.h"
Lei YU52d91242017-10-17 22:52:28 +080033
Chris Austen41a4b312015-10-25 03:45:42 -050034
Chris Austenb4f5b922015-10-13 12:44:43 -050035void register_netfn_storage_functions() __attribute__((constructor));
36
Chris Austenb4f5b922015-10-13 12:44:43 -050037unsigned int g_sel_time = 0xFFFFFFFF;
Nan Li36c0cb62016-03-31 11:16:08 +080038extern unsigned short g_sel_reserve;
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -060039extern const ipmi::sensor::IdInfoMap sensors;
40extern const FruMap frus;
Chris Austenb4f5b922015-10-13 12:44:43 -050041
Lei YUe8939392017-06-15 10:45:05 +080042namespace {
43constexpr auto TIME_INTERFACE = "xyz.openbmc_project.Time.EpochTime";
44constexpr auto HOST_TIME_PATH = "/xyz/openbmc_project/time/host";
45constexpr auto DBUS_PROPERTIES = "org.freedesktop.DBus.Properties";
46constexpr auto PROPERTY_ELAPSED= "Elapsed";
47
48const char* getTimeString(const uint64_t& usecSinceEpoch)
49{
50 using namespace std::chrono;
51 system_clock::time_point tp{microseconds(usecSinceEpoch)};
52 auto t = system_clock::to_time_t(tp);
53 return std::ctime(&t);
54}
55}
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +053056
Tom Joseph6f7deaa2017-06-30 19:03:54 +053057namespace cache
58{
59 /*
60 * This cache contains the object paths of the logging entries sorted in the
61 * order of the filename(numeric order). The cache is initialized by
62 * invoking readLoggingObjectPaths with the cache as the parameter. The
63 * cache is invoked in the execution of the Get SEL info and Delete SEL
64 * entry command. The Get SEL Info command is typically invoked before the
65 * Get SEL entry command, so the cache is utilized for responding to Get SEL
66 * entry command. The cache is invalidated by clearing after Delete SEL
67 * entry and Clear SEL command.
68 */
69 ipmi::sel::ObjectPaths paths;
70
71} // namespace objectPathsCache
72
73using InternalFailure =
74 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
75using namespace phosphor::logging;
Marri Devender Raocac383b2017-07-03 13:24:27 -050076using namespace ipmi::fru;
77
78/**
79 * @enum Device access mode
80 */
81enum class AccessMode
82{
83 bytes, ///< Device is accessed by bytes
84 words ///< Device is accessed by words
85};
86
Tom Joseph6f7deaa2017-06-30 19:03:54 +053087
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -050088ipmi_ret_t ipmi_storage_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
89 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -050090 ipmi_data_len_t data_len, ipmi_context_t context)
91{
Chris Austenb4f5b922015-10-13 12:44:43 -050092 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +080093 ipmi_ret_t rc = IPMI_CC_INVALID;
Chris Austenb4f5b922015-10-13 12:44:43 -050094 *data_len = 0;
95 return rc;
96}
97
Tom Joseph6f7deaa2017-06-30 19:03:54 +053098ipmi_ret_t getSELInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
99 ipmi_request_t request, ipmi_response_t response,
100 ipmi_data_len_t data_len, ipmi_context_t context)
101{
102 std::vector<uint8_t> outPayload(sizeof(ipmi::sel::GetSELInfoResponse));
103 auto responseData = reinterpret_cast<ipmi::sel::GetSELInfoResponse*>
104 (outPayload.data());
105
106 responseData->selVersion = ipmi::sel::selVersion;
107 // Last erase timestamp is not available from log manager.
108 responseData->eraseTimeStamp = ipmi::sel::invalidTimeStamp;
109 responseData->operationSupport = ipmi::sel::operationSupport;
110
111 ipmi::sel::readLoggingObjectPaths(cache::paths);
112 responseData->entries = 0;
113 responseData->addTimeStamp = ipmi::sel::invalidTimeStamp;
114
115 if (!cache::paths.empty())
116 {
117 responseData->entries = static_cast<uint16_t>(cache::paths.size());
118
119 try
120 {
121 responseData->addTimeStamp = static_cast<uint32_t>(
122 (ipmi::sel::getEntryTimeStamp(cache::paths.back())
123 .count()));
124 }
125 catch (InternalFailure& e)
126 {
127 }
128 catch (const std::runtime_error& e)
129 {
130 log<level::ERR>(e.what());
131 }
132 }
133
134 memcpy(response, outPayload.data(), outPayload.size());
135 *data_len = outPayload.size();
136
137 return IPMI_CC_OK;
138}
139
Tom Josepha4953392017-06-30 19:09:47 +0530140ipmi_ret_t getSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
141 ipmi_request_t request, ipmi_response_t response,
142 ipmi_data_len_t data_len, ipmi_context_t context)
143{
144 auto requestData = reinterpret_cast<const ipmi::sel::GetSELEntryRequest*>
145 (request);
146
147 if (requestData->reservationID != 0)
148 {
149 if (g_sel_reserve != requestData->reservationID)
150 {
151 *data_len = 0;
152 return IPMI_CC_INVALID_RESERVATION_ID;
153 }
154 }
155
156 if (cache::paths.empty())
157 {
158 *data_len = 0;
159 return IPMI_CC_SENSOR_INVALID;
160 }
161
162 ipmi::sel::ObjectPaths::const_iterator iter;
163
164 // Check for the requested SEL Entry.
165 if (requestData->selRecordID == ipmi::sel::firstEntry)
166 {
167 iter = cache::paths.begin();
168 }
169 else if (requestData->selRecordID == ipmi::sel::lastEntry)
170 {
171 iter = cache::paths.end();
172 }
173 else
174 {
175 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
176 std::to_string(requestData->selRecordID);
177
178 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
179 if (iter == cache::paths.end())
180 {
181 *data_len = 0;
182 return IPMI_CC_SENSOR_INVALID;
183 }
184 }
185
186 ipmi::sel::GetSELEntryResponse record {};
187
188 // Convert the log entry into SEL record.
189 try
190 {
191 record = ipmi::sel::convertLogEntrytoSEL(*iter);
192 }
193 catch (InternalFailure& e)
194 {
195 *data_len = 0;
196 return IPMI_CC_UNSPECIFIED_ERROR;
197 }
198 catch (const std::runtime_error& e)
199 {
200 log<level::ERR>(e.what());
201 *data_len = 0;
202 return IPMI_CC_UNSPECIFIED_ERROR;
203 }
204
205
206 // Identify the next SEL record ID
207 if(iter != cache::paths.end())
208 {
209 ++iter;
210 if (iter == cache::paths.end())
211 {
212 record.nextRecordID = ipmi::sel::lastEntry;
213 }
214 else
215 {
Vernon Mauery185b9f82018-07-20 10:52:36 -0700216 namespace fs = std::filesystem;
Tom Josepha4953392017-06-30 19:09:47 +0530217 fs::path path(*iter);
218 record.nextRecordID = static_cast<uint16_t>
219 (std::stoul(std::string(path.filename().c_str())));
220 }
221 }
222 else
223 {
224 record.nextRecordID = ipmi::sel::lastEntry;
225 }
226
227 if (requestData->readLength == ipmi::sel::entireRecord)
228 {
229 memcpy(response, &record, sizeof(record));
230 *data_len = sizeof(record);
231 }
232 else
233 {
234 if (requestData->offset >= ipmi::sel::selRecordSize ||
235 requestData->readLength > ipmi::sel::selRecordSize)
236 {
237 *data_len = 0;
238 return IPMI_CC_INVALID_FIELD_REQUEST;
239 }
240
241 auto diff = ipmi::sel::selRecordSize - requestData->offset;
242 auto readLength = std::min(diff,
243 static_cast<int>(requestData->readLength));
244
245 memcpy(response, &record.nextRecordID, sizeof(record.nextRecordID));
246 memcpy(static_cast<uint8_t*>(response) + sizeof(record.nextRecordID),
247 &record.recordID + requestData->offset, readLength);
248 *data_len = sizeof(record.nextRecordID) + readLength;
249 }
250
251 return IPMI_CC_OK;
252}
253
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530254ipmi_ret_t deleteSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
255 ipmi_request_t request, ipmi_response_t response,
256 ipmi_data_len_t data_len, ipmi_context_t context)
257{
258 namespace fs = std::experimental::filesystem;
259 auto requestData = reinterpret_cast<const ipmi::sel::DeleteSELEntryRequest*>
260 (request);
261
262 if (g_sel_reserve != requestData->reservationID)
263 {
264 *data_len = 0;
265 return IPMI_CC_INVALID_RESERVATION_ID;
266 }
267
268 ipmi::sel::readLoggingObjectPaths(cache::paths);
269
270 if (cache::paths.empty())
271 {
272 *data_len = 0;
273 return IPMI_CC_SENSOR_INVALID;
274 }
275
276 ipmi::sel::ObjectPaths::const_iterator iter;
277 uint16_t delRecordID = 0;
278
279 if (requestData->selRecordID == ipmi::sel::firstEntry)
280 {
281 iter = cache::paths.begin();
282 fs::path path(*iter);
283 delRecordID = static_cast<uint16_t>
284 (std::stoul(std::string(path.filename().c_str())));
285 }
286 else if (requestData->selRecordID == ipmi::sel::lastEntry)
287 {
288 iter = cache::paths.end();
289 fs::path path(*iter);
290 delRecordID = static_cast<uint16_t>
291 (std::stoul(std::string(path.filename().c_str())));
292 }
293 else
294 {
295 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
296 std::to_string(requestData->selRecordID);
297
298 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
299 if (iter == cache::paths.end())
300 {
301 *data_len = 0;
302 return IPMI_CC_SENSOR_INVALID;
303 }
304 delRecordID = requestData->selRecordID;
305 }
306
307 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
308 std::string service;
309
310 try
311 {
312 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf, *iter);
313 }
314 catch (const std::runtime_error& e)
315 {
316 log<level::ERR>(e.what());
317 *data_len = 0;
318 return IPMI_CC_UNSPECIFIED_ERROR;
319 }
320
321 auto methodCall = bus.new_method_call(service.c_str(),
322 (*iter).c_str(),
323 ipmi::sel::logDeleteIntf,
324 "Delete");
325 auto reply = bus.call(methodCall);
326 if (reply.is_method_error())
327 {
328 *data_len = 0;
329 return IPMI_CC_UNSPECIFIED_ERROR;
330 }
331
332 // Invalidate the cache of dbus entry objects.
333 cache::paths.clear();
334 memcpy(response, &delRecordID, sizeof(delRecordID));
335 *data_len = sizeof(delRecordID);
336
337 return IPMI_CC_OK;
338}
339
Tom Joseph2f05bb52017-06-30 19:14:49 +0530340ipmi_ret_t clearSEL(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
341 ipmi_response_t response, ipmi_data_len_t data_len,
342 ipmi_context_t context)
343{
344 auto requestData = reinterpret_cast<const ipmi::sel::ClearSELRequest*>
345 (request);
346
347 if (g_sel_reserve != requestData->reservationID)
348 {
349 *data_len = 0;
350 return IPMI_CC_INVALID_RESERVATION_ID;
351 }
352
353 if (requestData->charC != 'C' ||
354 requestData->charL != 'L' ||
355 requestData->charR != 'R')
356 {
357 *data_len = 0;
358 return IPMI_CC_INVALID_FIELD_REQUEST;
359 }
360
361 uint8_t eraseProgress = ipmi::sel::eraseComplete;
362
363 /*
364 * Erasure status cannot be fetched from DBUS, so always return erasure
365 * status as `erase completed`.
366 */
367 if (requestData->eraseOperation == ipmi::sel::getEraseStatus)
368 {
369 memcpy(response, &eraseProgress, sizeof(eraseProgress));
370 *data_len = sizeof(eraseProgress);
371 return IPMI_CC_OK;
372 }
373
374 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
375 auto depth = 0;
376
377 auto mapperCall = bus.new_method_call(ipmi::sel::mapperBusName,
378 ipmi::sel::mapperObjPath,
379 ipmi::sel::mapperIntf,
380 "GetSubTreePaths");
381 mapperCall.append(ipmi::sel::logBasePath);
382 mapperCall.append(depth);
383 mapperCall.append(ipmi::sel::ObjectPaths({ipmi::sel::logEntryIntf}));
384
385 auto reply = bus.call(mapperCall);
386 if (reply.is_method_error())
387 {
388 memcpy(response, &eraseProgress, sizeof(eraseProgress));
389 *data_len = sizeof(eraseProgress);
390 return IPMI_CC_OK;
391 }
392
393 ipmi::sel::ObjectPaths objectPaths;
394 reply.read(objectPaths);
395 if (objectPaths.empty())
396 {
397 memcpy(response, &eraseProgress, sizeof(eraseProgress));
398 *data_len = sizeof(eraseProgress);
399 return IPMI_CC_OK;
400 }
401
402 std::string service;
403
404 try
405 {
406 service = ipmi::getService(bus,
407 ipmi::sel::logDeleteIntf,
408 objectPaths.front());
409 }
410 catch (const std::runtime_error& e)
411 {
412 log<level::ERR>(e.what());
413 *data_len = 0;
414 return IPMI_CC_UNSPECIFIED_ERROR;
415 }
416
417 for (const auto& iter : objectPaths)
418 {
419 auto methodCall = bus.new_method_call(service.c_str(),
420 iter.c_str(),
421 ipmi::sel::logDeleteIntf,
422 "Delete");
423
424 auto reply = bus.call(methodCall);
425 if (reply.is_method_error())
426 {
427 *data_len = 0;
428 return IPMI_CC_UNSPECIFIED_ERROR;
429 }
430 }
431
432 // Invalidate the cache of dbus entry objects.
433 cache::paths.clear();
434 memcpy(response, &eraseProgress, sizeof(eraseProgress));
435 *data_len = sizeof(eraseProgress);
436 return IPMI_CC_OK;
437}
438
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500439ipmi_ret_t ipmi_storage_get_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
440 ipmi_request_t request, ipmi_response_t response,
441 ipmi_data_len_t data_len, ipmi_context_t context)
442{
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530443 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530444 uint64_t host_time_usec = 0;
445 uint32_t resp = 0;
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500446 std::stringstream hostTime;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500447
Lei YUe8939392017-06-15 10:45:05 +0800448 try
449 {
450 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
451 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
452 sdbusplus::message::variant<uint64_t> value;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530453
Lei YUe8939392017-06-15 10:45:05 +0800454 // Get host time
455 auto method = bus.new_method_call(service.c_str(),
456 HOST_TIME_PATH,
457 DBUS_PROPERTIES,
458 "Get");
459
460 method.append(TIME_INTERFACE, PROPERTY_ELAPSED);
461 auto reply = bus.call(method);
462 if (reply.is_method_error())
463 {
464 log<level::ERR>("Error getting time",
465 entry("SERVICE=%s", service.c_str()),
466 entry("PATH=%s", HOST_TIME_PATH));
467 return IPMI_CC_UNSPECIFIED_ERROR;
468 }
469 reply.read(value);
470 host_time_usec = value.get<uint64_t>();
471 }
472 catch (InternalFailure& e)
473 {
474 log<level::ERR>(e.what());
475 return IPMI_CC_UNSPECIFIED_ERROR;
476 }
477 catch (const std::runtime_error& e)
478 {
479 log<level::ERR>(e.what());
480 return IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530481 }
482
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500483 hostTime << "Host time:" << getTimeString(host_time_usec);
484 log<level::DEBUG>(hostTime.str().c_str());
485
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530486
487 // Time is really long int but IPMI wants just uint32. This works okay until
488 // the number of seconds since 1970 overflows uint32 size.. Still a whole
489 // lot of time here to even think about that.
490 resp = duration_cast<seconds>(microseconds(host_time_usec)).count();
491 resp = htole32(resp);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530492
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500493 // From the IPMI Spec 2.0, response should be a 32-bit value
494 *data_len = sizeof(resp);
495
496 // Pack the actual response
497 memcpy(response, &resp, *data_len);
498
Lei YUe8939392017-06-15 10:45:05 +0800499 return IPMI_CC_OK;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500500}
501
502ipmi_ret_t ipmi_storage_set_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
503 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500504 ipmi_data_len_t data_len, ipmi_context_t context)
505{
Lei YUe8939392017-06-15 10:45:05 +0800506 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530507 ipmi_ret_t rc = IPMI_CC_OK;
Lei YUe8939392017-06-15 10:45:05 +0800508 uint32_t secs = *static_cast<uint32_t*>(request);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530509 *data_len = 0;
Chris Austenb4f5b922015-10-13 12:44:43 -0500510
Lei YUe8939392017-06-15 10:45:05 +0800511 secs = le32toh(secs);
512 microseconds usec{seconds(secs)};
Norman James82330442015-11-19 16:53:26 -0600513
Lei YUe8939392017-06-15 10:45:05 +0800514 try
515 {
516 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
517 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
518 sdbusplus::message::variant<uint64_t> value{usec.count()};
519
520 // Set host time
521 auto method = bus.new_method_call(service.c_str(),
522 HOST_TIME_PATH,
523 DBUS_PROPERTIES,
524 "Set");
525
526 method.append(TIME_INTERFACE, PROPERTY_ELAPSED, value);
527 auto reply = bus.call(method);
528 if (reply.is_method_error())
529 {
530 log<level::ERR>("Error setting time",
531 entry("SERVICE=%s", service.c_str()),
532 entry("PATH=%s", HOST_TIME_PATH));
533 rc = IPMI_CC_UNSPECIFIED_ERROR;
534 }
Norman James82330442015-11-19 16:53:26 -0600535 }
Lei YUe8939392017-06-15 10:45:05 +0800536 catch (InternalFailure& e)
537 {
538 log<level::ERR>(e.what());
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530539 rc = IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530540 }
Lei YUe8939392017-06-15 10:45:05 +0800541 catch (const std::runtime_error& e)
542 {
543 log<level::ERR>(e.what());
Norman James82330442015-11-19 16:53:26 -0600544 rc = IPMI_CC_UNSPECIFIED_ERROR;
545 }
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530546
Chris Austenb4f5b922015-10-13 12:44:43 -0500547 return rc;
548}
549
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500550ipmi_ret_t ipmi_storage_reserve_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
551 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500552 ipmi_data_len_t data_len, ipmi_context_t context)
553{
Chris Austenb4f5b922015-10-13 12:44:43 -0500554 ipmi_ret_t rc = IPMI_CC_OK;
555
Nan Li36c0cb62016-03-31 11:16:08 +0800556 // IPMI spec, Reservation ID, the value simply increases against each execution of reserve_sel command.
557 if( ++g_sel_reserve == 0)
558 g_sel_reserve = 1;
Chris Austenb4f5b922015-10-13 12:44:43 -0500559
560 *data_len = sizeof(g_sel_reserve);
561
562 // Pack the actual response
563 memcpy(response, &g_sel_reserve, *data_len);
564
565 return rc;
566}
567
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500568ipmi_ret_t ipmi_storage_add_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
569 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500570 ipmi_data_len_t data_len, ipmi_context_t context)
571{
572
573 ipmi_ret_t rc = IPMI_CC_OK;
Chris Austen41a4b312015-10-25 03:45:42 -0500574 ipmi_add_sel_request_t *p = (ipmi_add_sel_request_t*) request;
575 uint16_t recordid;
Chris Austenb4f5b922015-10-13 12:44:43 -0500576
Chris Austen313d95b2015-10-31 12:55:30 -0500577 recordid = ((uint16_t)p->eventdata[1] << 8) | p->eventdata[2];
Chris Austen41a4b312015-10-25 03:45:42 -0500578
Chris Austenb4f5b922015-10-13 12:44:43 -0500579 *data_len = sizeof(g_sel_reserve);
580
581 // Pack the actual response
Chris Austen7cc33322015-11-11 00:20:22 -0600582 memcpy(response, &p->eventdata[1], 2);
Chris Austenb4f5b922015-10-13 12:44:43 -0500583
Tom Josephb647d5b2017-10-31 17:25:33 +0530584 // Hostboot sends SEL with OEM record type 0xDE to indicate that there is
585 // a maintenance procedure associated with eSEL record.
586 static constexpr auto procedureType = 0xDE;
587 if (p->recordtype == procedureType)
588 {
589 // In the OEM record type 0xDE, byte 11 in the SEL record indicate the
590 // procedure number.
591 createProcedureLogEntry(p->sensortype);
592 }
593 else
594 {
595 send_esel(recordid);
596 }
Chris Austenb4f5b922015-10-13 12:44:43 -0500597
598 return rc;
599}
600
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500601//Read FRU info area
602ipmi_ret_t ipmi_storage_get_fru_inv_area_info(
603 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
604 ipmi_response_t response, ipmi_data_len_t data_len,
605 ipmi_context_t context)
606{
607 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500608 const FruInvenAreaInfoRequest* reqptr =
609 reinterpret_cast<const FruInvenAreaInfoRequest*>(request);
Tom Joseph187f5642018-03-29 13:49:06 +0530610
611 auto iter = frus.find(reqptr->fruID);
612 if (iter == frus.end())
613 {
614 *data_len = 0;
615 return IPMI_CC_SENSOR_INVALID;
616 }
617
Marri Devender Raocac383b2017-07-03 13:24:27 -0500618 try
619 {
620 const auto& fruArea = getFruAreaData(reqptr->fruID);
621 auto size = static_cast<uint16_t>(fruArea.size());
622 FruInvenAreaInfoResponse resp;
623 resp.sizems = size >> 8;
624 resp.sizels = size;
625 resp.access = static_cast<uint8_t>(AccessMode::bytes);
626
627 *data_len = sizeof(resp);
628
629 // Pack the actual response
630 memcpy(response, &resp, *data_len);
631 }
632 catch(const InternalFailure& e)
633 {
634 rc = IPMI_CC_UNSPECIFIED_ERROR;
635 *data_len = 0;
636 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500637 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500638 return rc;
639}
640
641//Read FRU data
642ipmi_ret_t ipmi_storage_read_fru_data(
643 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
644 ipmi_response_t response, ipmi_data_len_t data_len,
645 ipmi_context_t context)
646{
647 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500648 const ReadFruDataRequest* reqptr =
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500649 reinterpret_cast<const ReadFruDataRequest*>(request);
650 auto resptr =
651 reinterpret_cast<ReadFruDataResponse*>(response);
Tom Joseph187f5642018-03-29 13:49:06 +0530652
653 auto iter = frus.find(reqptr->fruID);
654 if (iter == frus.end())
655 {
656 *data_len = 0;
657 return IPMI_CC_SENSOR_INVALID;
658 }
659
Marri Devender Raocac383b2017-07-03 13:24:27 -0500660 auto offset =
661 static_cast<uint16_t>(reqptr->offsetMS << 8 | reqptr->offsetLS);
662 try
663 {
664 const auto& fruArea = getFruAreaData(reqptr->fruID);
665 auto size = fruArea.size();
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500666
Tom Josephefcd68b2018-04-26 18:46:27 +0530667 if (offset >= size)
668 {
669 return IPMI_CC_PARM_OUT_OF_RANGE;
670 }
671
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500672 // Write the count of response data.
673 if ((offset + reqptr->count) <= size)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500674 {
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500675 resptr->count = reqptr->count;
676 }
677 else
678 {
679 resptr->count = size - offset;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500680 }
Ratan Gupta2848d602018-01-31 20:39:20 +0530681
Ratan Gupta2848d602018-01-31 20:39:20 +0530682 std::copy((fruArea.begin() + offset),
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500683 (fruArea.begin() + offset + resptr->count),
684 resptr->data);
Ratan Gupta2848d602018-01-31 20:39:20 +0530685
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500686 *data_len = resptr->count + 1; // additional one byte for count
Marri Devender Raocac383b2017-07-03 13:24:27 -0500687 }
688 catch (const InternalFailure& e)
689 {
690 rc = IPMI_CC_UNSPECIFIED_ERROR;
691 *data_len = 0;
692 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500693 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500694 return rc;
695}
696
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600697ipmi_ret_t ipmi_get_repository_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
698 ipmi_request_t request, ipmi_response_t response,
699 ipmi_data_len_t data_len, ipmi_context_t context)
700{
701 constexpr auto sdrVersion = 0x51;
702 auto responseData =
703 reinterpret_cast<GetRepositoryInfoResponse*>(response);
704
705 memset(responseData, 0 , sizeof(GetRepositoryInfoResponse));
706
707 responseData->sdrVersion = sdrVersion;
708
709 uint16_t records = frus.size() + sensors.size();
710 responseData->recordCountMs = records >> 8;
711 responseData->recordCountLs = records;
712
713 responseData->freeSpace[0] = 0xFF;
714 responseData->freeSpace[1] = 0xFF;
715
716 *data_len = sizeof(GetRepositoryInfoResponse);
717
718 return IPMI_CC_OK;
719}
Chris Austenb4f5b922015-10-13 12:44:43 -0500720
Chris Austenb4f5b922015-10-13 12:44:43 -0500721void register_netfn_storage_functions()
722{
Tom05732372016-09-06 17:21:23 +0530723 // <Wildcard Command>
Tom05732372016-09-06 17:21:23 +0530724 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WILDCARD, NULL, ipmi_storage_wildcard,
725 PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500726
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530727 // <Get SEL Info>
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530728 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO, NULL, getSELInfo,
729 PRIVILEGE_USER);
730
Tom05732372016-09-06 17:21:23 +0530731 // <Get SEL Time>
Tom05732372016-09-06 17:21:23 +0530732 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME, NULL, ipmi_storage_get_sel_time,
733 PRIVILEGE_USER);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500734
Tom05732372016-09-06 17:21:23 +0530735 // <Set SEL Time>
Tom05732372016-09-06 17:21:23 +0530736 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME, NULL, ipmi_storage_set_sel_time,
737 PRIVILEGE_OPERATOR);
Chris Austenb4f5b922015-10-13 12:44:43 -0500738
Tom05732372016-09-06 17:21:23 +0530739 // <Reserve SEL>
Tom05732372016-09-06 17:21:23 +0530740 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL, NULL, ipmi_storage_reserve_sel,
741 PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500742
Tom Josepha4953392017-06-30 19:09:47 +0530743 // <Get SEL Entry>
Tom Josepha4953392017-06-30 19:09:47 +0530744 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY, NULL, getSELEntry,
745 PRIVILEGE_USER);
746
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530747 // <Delete SEL Entry>
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530748 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_DELETE_SEL, NULL, deleteSELEntry,
749 PRIVILEGE_OPERATOR);
750
Tom05732372016-09-06 17:21:23 +0530751 // <Add SEL Entry>
Tom05732372016-09-06 17:21:23 +0530752 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_ADD_SEL, NULL, ipmi_storage_add_sel,
753 PRIVILEGE_OPERATOR);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530754 // <Clear SEL>
Tom Joseph2f05bb52017-06-30 19:14:49 +0530755 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_CLEAR_SEL, NULL, clearSEL,
756 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500757 // <Get FRU Inventory Area Info>
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500758 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_FRU_INV_AREA_INFO, NULL,
759 ipmi_storage_get_fru_inv_area_info, PRIVILEGE_OPERATOR);
760
761 // <Add READ FRU Data
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500762 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_READ_FRU_DATA, NULL,
763 ipmi_storage_read_fru_data, PRIVILEGE_OPERATOR);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500764
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600765 // <Get Repository Info>
766 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_REPOSITORY_INFO,
767 nullptr, ipmi_get_repository_info,
768 PRIVILEGE_USER);
769
Tom Joseph5ca50952018-02-22 00:33:38 +0530770 // <Reserve SDR Repository>
771 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SDR,
772 nullptr, ipmi_sen_reserve_sdr,
773 PRIVILEGE_USER);
774
775 // <Get SDR>
776 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SDR,
777 nullptr, ipmi_sen_get_sdr,
778 PRIVILEGE_USER);
779
Marri Devender Rao908f7502017-07-10 01:49:54 -0500780 ipmi::fru::registerCallbackHandler();
Chris Austenb4f5b922015-10-13 12:44:43 -0500781 return;
782}
783