blob: 59dfdde69e25bf02a4ac01fcbe1fec5f491fb67d [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>
Tom Josepha4953392017-06-30 19:09:47 +05305#include <experimental/filesystem>
Lei YU52d91242017-10-17 22:52:28 +08006#include <mapper.h>
7#include <string>
8#include <systemd/sd-bus.h>
9
Tom Joseph6f7deaa2017-06-30 19:03:54 +053010#include <phosphor-logging/log.hpp>
Marri Devender Raocac383b2017-07-03 13:24:27 -050011#include <phosphor-logging/elog-errors.hpp>
Lei YU52d91242017-10-17 22:52:28 +080012#include <sdbusplus/server.hpp>
13
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -060014#include "fruread.hpp"
Lei YU52d91242017-10-17 22:52:28 +080015#include "host-ipmid/ipmid-api.h"
16#include "read_fru_data.hpp"
17#include "selutility.hpp"
18#include "storageaddsel.h"
19#include "storagehandler.h"
20#include "utils.hpp"
21#include "xyz/openbmc_project/Common/error.hpp"
22
Chris Austen41a4b312015-10-25 03:45:42 -050023
Chris Austenb4f5b922015-10-13 12:44:43 -050024void register_netfn_storage_functions() __attribute__((constructor));
25
Chris Austenb4f5b922015-10-13 12:44:43 -050026unsigned int g_sel_time = 0xFFFFFFFF;
Nan Li36c0cb62016-03-31 11:16:08 +080027extern unsigned short g_sel_reserve;
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -060028extern const ipmi::sensor::IdInfoMap sensors;
29extern const FruMap frus;
Chris Austenb4f5b922015-10-13 12:44:43 -050030
Lei YUe8939392017-06-15 10:45:05 +080031namespace {
32constexpr auto TIME_INTERFACE = "xyz.openbmc_project.Time.EpochTime";
33constexpr auto HOST_TIME_PATH = "/xyz/openbmc_project/time/host";
34constexpr auto DBUS_PROPERTIES = "org.freedesktop.DBus.Properties";
35constexpr auto PROPERTY_ELAPSED= "Elapsed";
36
37const char* getTimeString(const uint64_t& usecSinceEpoch)
38{
39 using namespace std::chrono;
40 system_clock::time_point tp{microseconds(usecSinceEpoch)};
41 auto t = system_clock::to_time_t(tp);
42 return std::ctime(&t);
43}
44}
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +053045
Tom Joseph6f7deaa2017-06-30 19:03:54 +053046namespace cache
47{
48 /*
49 * This cache contains the object paths of the logging entries sorted in the
50 * order of the filename(numeric order). The cache is initialized by
51 * invoking readLoggingObjectPaths with the cache as the parameter. The
52 * cache is invoked in the execution of the Get SEL info and Delete SEL
53 * entry command. The Get SEL Info command is typically invoked before the
54 * Get SEL entry command, so the cache is utilized for responding to Get SEL
55 * entry command. The cache is invalidated by clearing after Delete SEL
56 * entry and Clear SEL command.
57 */
58 ipmi::sel::ObjectPaths paths;
59
60} // namespace objectPathsCache
61
62using InternalFailure =
63 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
64using namespace phosphor::logging;
Marri Devender Raocac383b2017-07-03 13:24:27 -050065using namespace ipmi::fru;
66
67/**
68 * @enum Device access mode
69 */
70enum class AccessMode
71{
72 bytes, ///< Device is accessed by bytes
73 words ///< Device is accessed by words
74};
75
Tom Joseph6f7deaa2017-06-30 19:03:54 +053076
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -050077ipmi_ret_t ipmi_storage_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
78 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -050079 ipmi_data_len_t data_len, ipmi_context_t context)
80{
81 printf("Handling STORAGE WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
82 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +080083 ipmi_ret_t rc = IPMI_CC_INVALID;
Chris Austenb4f5b922015-10-13 12:44:43 -050084 *data_len = 0;
85 return rc;
86}
87
Tom Joseph6f7deaa2017-06-30 19:03:54 +053088ipmi_ret_t getSELInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
89 ipmi_request_t request, ipmi_response_t response,
90 ipmi_data_len_t data_len, ipmi_context_t context)
91{
92 std::vector<uint8_t> outPayload(sizeof(ipmi::sel::GetSELInfoResponse));
93 auto responseData = reinterpret_cast<ipmi::sel::GetSELInfoResponse*>
94 (outPayload.data());
95
96 responseData->selVersion = ipmi::sel::selVersion;
97 // Last erase timestamp is not available from log manager.
98 responseData->eraseTimeStamp = ipmi::sel::invalidTimeStamp;
99 responseData->operationSupport = ipmi::sel::operationSupport;
100
101 ipmi::sel::readLoggingObjectPaths(cache::paths);
102 responseData->entries = 0;
103 responseData->addTimeStamp = ipmi::sel::invalidTimeStamp;
104
105 if (!cache::paths.empty())
106 {
107 responseData->entries = static_cast<uint16_t>(cache::paths.size());
108
109 try
110 {
111 responseData->addTimeStamp = static_cast<uint32_t>(
112 (ipmi::sel::getEntryTimeStamp(cache::paths.back())
113 .count()));
114 }
115 catch (InternalFailure& e)
116 {
117 }
118 catch (const std::runtime_error& e)
119 {
120 log<level::ERR>(e.what());
121 }
122 }
123
124 memcpy(response, outPayload.data(), outPayload.size());
125 *data_len = outPayload.size();
126
127 return IPMI_CC_OK;
128}
129
Tom Josepha4953392017-06-30 19:09:47 +0530130ipmi_ret_t getSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
131 ipmi_request_t request, ipmi_response_t response,
132 ipmi_data_len_t data_len, ipmi_context_t context)
133{
134 auto requestData = reinterpret_cast<const ipmi::sel::GetSELEntryRequest*>
135 (request);
136
137 if (requestData->reservationID != 0)
138 {
139 if (g_sel_reserve != requestData->reservationID)
140 {
141 *data_len = 0;
142 return IPMI_CC_INVALID_RESERVATION_ID;
143 }
144 }
145
146 if (cache::paths.empty())
147 {
148 *data_len = 0;
149 return IPMI_CC_SENSOR_INVALID;
150 }
151
152 ipmi::sel::ObjectPaths::const_iterator iter;
153
154 // Check for the requested SEL Entry.
155 if (requestData->selRecordID == ipmi::sel::firstEntry)
156 {
157 iter = cache::paths.begin();
158 }
159 else if (requestData->selRecordID == ipmi::sel::lastEntry)
160 {
161 iter = cache::paths.end();
162 }
163 else
164 {
165 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
166 std::to_string(requestData->selRecordID);
167
168 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
169 if (iter == cache::paths.end())
170 {
171 *data_len = 0;
172 return IPMI_CC_SENSOR_INVALID;
173 }
174 }
175
176 ipmi::sel::GetSELEntryResponse record {};
177
178 // Convert the log entry into SEL record.
179 try
180 {
181 record = ipmi::sel::convertLogEntrytoSEL(*iter);
182 }
183 catch (InternalFailure& e)
184 {
185 *data_len = 0;
186 return IPMI_CC_UNSPECIFIED_ERROR;
187 }
188 catch (const std::runtime_error& e)
189 {
190 log<level::ERR>(e.what());
191 *data_len = 0;
192 return IPMI_CC_UNSPECIFIED_ERROR;
193 }
194
195
196 // Identify the next SEL record ID
197 if(iter != cache::paths.end())
198 {
199 ++iter;
200 if (iter == cache::paths.end())
201 {
202 record.nextRecordID = ipmi::sel::lastEntry;
203 }
204 else
205 {
206 namespace fs = std::experimental::filesystem;
207 fs::path path(*iter);
208 record.nextRecordID = static_cast<uint16_t>
209 (std::stoul(std::string(path.filename().c_str())));
210 }
211 }
212 else
213 {
214 record.nextRecordID = ipmi::sel::lastEntry;
215 }
216
217 if (requestData->readLength == ipmi::sel::entireRecord)
218 {
219 memcpy(response, &record, sizeof(record));
220 *data_len = sizeof(record);
221 }
222 else
223 {
224 if (requestData->offset >= ipmi::sel::selRecordSize ||
225 requestData->readLength > ipmi::sel::selRecordSize)
226 {
227 *data_len = 0;
228 return IPMI_CC_INVALID_FIELD_REQUEST;
229 }
230
231 auto diff = ipmi::sel::selRecordSize - requestData->offset;
232 auto readLength = std::min(diff,
233 static_cast<int>(requestData->readLength));
234
235 memcpy(response, &record.nextRecordID, sizeof(record.nextRecordID));
236 memcpy(static_cast<uint8_t*>(response) + sizeof(record.nextRecordID),
237 &record.recordID + requestData->offset, readLength);
238 *data_len = sizeof(record.nextRecordID) + readLength;
239 }
240
241 return IPMI_CC_OK;
242}
243
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530244ipmi_ret_t deleteSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
245 ipmi_request_t request, ipmi_response_t response,
246 ipmi_data_len_t data_len, ipmi_context_t context)
247{
248 namespace fs = std::experimental::filesystem;
249 auto requestData = reinterpret_cast<const ipmi::sel::DeleteSELEntryRequest*>
250 (request);
251
252 if (g_sel_reserve != requestData->reservationID)
253 {
254 *data_len = 0;
255 return IPMI_CC_INVALID_RESERVATION_ID;
256 }
257
258 ipmi::sel::readLoggingObjectPaths(cache::paths);
259
260 if (cache::paths.empty())
261 {
262 *data_len = 0;
263 return IPMI_CC_SENSOR_INVALID;
264 }
265
266 ipmi::sel::ObjectPaths::const_iterator iter;
267 uint16_t delRecordID = 0;
268
269 if (requestData->selRecordID == ipmi::sel::firstEntry)
270 {
271 iter = cache::paths.begin();
272 fs::path path(*iter);
273 delRecordID = static_cast<uint16_t>
274 (std::stoul(std::string(path.filename().c_str())));
275 }
276 else if (requestData->selRecordID == ipmi::sel::lastEntry)
277 {
278 iter = cache::paths.end();
279 fs::path path(*iter);
280 delRecordID = static_cast<uint16_t>
281 (std::stoul(std::string(path.filename().c_str())));
282 }
283 else
284 {
285 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
286 std::to_string(requestData->selRecordID);
287
288 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
289 if (iter == cache::paths.end())
290 {
291 *data_len = 0;
292 return IPMI_CC_SENSOR_INVALID;
293 }
294 delRecordID = requestData->selRecordID;
295 }
296
297 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
298 std::string service;
299
300 try
301 {
302 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf, *iter);
303 }
304 catch (const std::runtime_error& e)
305 {
306 log<level::ERR>(e.what());
307 *data_len = 0;
308 return IPMI_CC_UNSPECIFIED_ERROR;
309 }
310
311 auto methodCall = bus.new_method_call(service.c_str(),
312 (*iter).c_str(),
313 ipmi::sel::logDeleteIntf,
314 "Delete");
315 auto reply = bus.call(methodCall);
316 if (reply.is_method_error())
317 {
318 *data_len = 0;
319 return IPMI_CC_UNSPECIFIED_ERROR;
320 }
321
322 // Invalidate the cache of dbus entry objects.
323 cache::paths.clear();
324 memcpy(response, &delRecordID, sizeof(delRecordID));
325 *data_len = sizeof(delRecordID);
326
327 return IPMI_CC_OK;
328}
329
Tom Joseph2f05bb52017-06-30 19:14:49 +0530330ipmi_ret_t clearSEL(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
331 ipmi_response_t response, ipmi_data_len_t data_len,
332 ipmi_context_t context)
333{
334 auto requestData = reinterpret_cast<const ipmi::sel::ClearSELRequest*>
335 (request);
336
337 if (g_sel_reserve != requestData->reservationID)
338 {
339 *data_len = 0;
340 return IPMI_CC_INVALID_RESERVATION_ID;
341 }
342
343 if (requestData->charC != 'C' ||
344 requestData->charL != 'L' ||
345 requestData->charR != 'R')
346 {
347 *data_len = 0;
348 return IPMI_CC_INVALID_FIELD_REQUEST;
349 }
350
351 uint8_t eraseProgress = ipmi::sel::eraseComplete;
352
353 /*
354 * Erasure status cannot be fetched from DBUS, so always return erasure
355 * status as `erase completed`.
356 */
357 if (requestData->eraseOperation == ipmi::sel::getEraseStatus)
358 {
359 memcpy(response, &eraseProgress, sizeof(eraseProgress));
360 *data_len = sizeof(eraseProgress);
361 return IPMI_CC_OK;
362 }
363
364 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
365 auto depth = 0;
366
367 auto mapperCall = bus.new_method_call(ipmi::sel::mapperBusName,
368 ipmi::sel::mapperObjPath,
369 ipmi::sel::mapperIntf,
370 "GetSubTreePaths");
371 mapperCall.append(ipmi::sel::logBasePath);
372 mapperCall.append(depth);
373 mapperCall.append(ipmi::sel::ObjectPaths({ipmi::sel::logEntryIntf}));
374
375 auto reply = bus.call(mapperCall);
376 if (reply.is_method_error())
377 {
378 memcpy(response, &eraseProgress, sizeof(eraseProgress));
379 *data_len = sizeof(eraseProgress);
380 return IPMI_CC_OK;
381 }
382
383 ipmi::sel::ObjectPaths objectPaths;
384 reply.read(objectPaths);
385 if (objectPaths.empty())
386 {
387 memcpy(response, &eraseProgress, sizeof(eraseProgress));
388 *data_len = sizeof(eraseProgress);
389 return IPMI_CC_OK;
390 }
391
392 std::string service;
393
394 try
395 {
396 service = ipmi::getService(bus,
397 ipmi::sel::logDeleteIntf,
398 objectPaths.front());
399 }
400 catch (const std::runtime_error& e)
401 {
402 log<level::ERR>(e.what());
403 *data_len = 0;
404 return IPMI_CC_UNSPECIFIED_ERROR;
405 }
406
407 for (const auto& iter : objectPaths)
408 {
409 auto methodCall = bus.new_method_call(service.c_str(),
410 iter.c_str(),
411 ipmi::sel::logDeleteIntf,
412 "Delete");
413
414 auto reply = bus.call(methodCall);
415 if (reply.is_method_error())
416 {
417 *data_len = 0;
418 return IPMI_CC_UNSPECIFIED_ERROR;
419 }
420 }
421
422 // Invalidate the cache of dbus entry objects.
423 cache::paths.clear();
424 memcpy(response, &eraseProgress, sizeof(eraseProgress));
425 *data_len = sizeof(eraseProgress);
426 return IPMI_CC_OK;
427}
428
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500429ipmi_ret_t ipmi_storage_get_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
430 ipmi_request_t request, ipmi_response_t response,
431 ipmi_data_len_t data_len, ipmi_context_t context)
432{
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530433 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530434 uint64_t host_time_usec = 0;
435 uint32_t resp = 0;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500436
437 printf("IPMI Handling GET-SEL-TIME\n");
438
Lei YUe8939392017-06-15 10:45:05 +0800439 try
440 {
441 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
442 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
443 sdbusplus::message::variant<uint64_t> value;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530444
Lei YUe8939392017-06-15 10:45:05 +0800445 // Get host time
446 auto method = bus.new_method_call(service.c_str(),
447 HOST_TIME_PATH,
448 DBUS_PROPERTIES,
449 "Get");
450
451 method.append(TIME_INTERFACE, PROPERTY_ELAPSED);
452 auto reply = bus.call(method);
453 if (reply.is_method_error())
454 {
455 log<level::ERR>("Error getting time",
456 entry("SERVICE=%s", service.c_str()),
457 entry("PATH=%s", HOST_TIME_PATH));
458 return IPMI_CC_UNSPECIFIED_ERROR;
459 }
460 reply.read(value);
461 host_time_usec = value.get<uint64_t>();
462 }
463 catch (InternalFailure& e)
464 {
465 log<level::ERR>(e.what());
466 return IPMI_CC_UNSPECIFIED_ERROR;
467 }
468 catch (const std::runtime_error& e)
469 {
470 log<level::ERR>(e.what());
471 return IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530472 }
473
Lei YUe8939392017-06-15 10:45:05 +0800474 printf("Host time: %" PRIu64 ", %s",
475 host_time_usec, getTimeString(host_time_usec));
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530476
477 // Time is really long int but IPMI wants just uint32. This works okay until
478 // the number of seconds since 1970 overflows uint32 size.. Still a whole
479 // lot of time here to even think about that.
480 resp = duration_cast<seconds>(microseconds(host_time_usec)).count();
481 resp = htole32(resp);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530482
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500483 // From the IPMI Spec 2.0, response should be a 32-bit value
484 *data_len = sizeof(resp);
485
486 // Pack the actual response
487 memcpy(response, &resp, *data_len);
488
Lei YUe8939392017-06-15 10:45:05 +0800489 return IPMI_CC_OK;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500490}
491
492ipmi_ret_t ipmi_storage_set_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
493 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500494 ipmi_data_len_t data_len, ipmi_context_t context)
495{
Lei YUe8939392017-06-15 10:45:05 +0800496 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530497 ipmi_ret_t rc = IPMI_CC_OK;
Lei YUe8939392017-06-15 10:45:05 +0800498 uint32_t secs = *static_cast<uint32_t*>(request);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530499 *data_len = 0;
Chris Austenb4f5b922015-10-13 12:44:43 -0500500
Lei YUe8939392017-06-15 10:45:05 +0800501 printf("Handling Set-SEL-Time:[0x%X], Cmd:[0x%X], Data:[0x%X]\n",
502 netfn, cmd, secs);
Chris Austenb4f5b922015-10-13 12:44:43 -0500503
Lei YUe8939392017-06-15 10:45:05 +0800504 secs = le32toh(secs);
505 microseconds usec{seconds(secs)};
Norman James82330442015-11-19 16:53:26 -0600506
Lei YUe8939392017-06-15 10:45:05 +0800507 printf("To Set host time: %" PRIu64 ", %s",
508 usec.count(), getTimeString(usec.count()));
509
510 try
511 {
512 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
513 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
514 sdbusplus::message::variant<uint64_t> value{usec.count()};
515
516 // Set host time
517 auto method = bus.new_method_call(service.c_str(),
518 HOST_TIME_PATH,
519 DBUS_PROPERTIES,
520 "Set");
521
522 method.append(TIME_INTERFACE, PROPERTY_ELAPSED, value);
523 auto reply = bus.call(method);
524 if (reply.is_method_error())
525 {
526 log<level::ERR>("Error setting time",
527 entry("SERVICE=%s", service.c_str()),
528 entry("PATH=%s", HOST_TIME_PATH));
529 rc = IPMI_CC_UNSPECIFIED_ERROR;
530 }
Norman James82330442015-11-19 16:53:26 -0600531 }
Lei YUe8939392017-06-15 10:45:05 +0800532 catch (InternalFailure& e)
533 {
534 log<level::ERR>(e.what());
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530535 rc = IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530536 }
Lei YUe8939392017-06-15 10:45:05 +0800537 catch (const std::runtime_error& e)
538 {
539 log<level::ERR>(e.what());
Norman James82330442015-11-19 16:53:26 -0600540 rc = IPMI_CC_UNSPECIFIED_ERROR;
541 }
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530542
Chris Austenb4f5b922015-10-13 12:44:43 -0500543 return rc;
544}
545
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500546ipmi_ret_t ipmi_storage_reserve_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
547 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500548 ipmi_data_len_t data_len, ipmi_context_t context)
549{
Chris Austenb4f5b922015-10-13 12:44:43 -0500550 ipmi_ret_t rc = IPMI_CC_OK;
551
Nan Li36c0cb62016-03-31 11:16:08 +0800552 // IPMI spec, Reservation ID, the value simply increases against each execution of reserve_sel command.
553 if( ++g_sel_reserve == 0)
554 g_sel_reserve = 1;
Chris Austenb4f5b922015-10-13 12:44:43 -0500555
Nan Li36c0cb62016-03-31 11:16:08 +0800556 printf("IPMI Handling RESERVE-SEL 0x%04x\n", g_sel_reserve);
Chris Austen41a4b312015-10-25 03:45:42 -0500557
Chris Austenb4f5b922015-10-13 12:44:43 -0500558 *data_len = sizeof(g_sel_reserve);
559
560 // Pack the actual response
561 memcpy(response, &g_sel_reserve, *data_len);
562
563 return rc;
564}
565
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500566ipmi_ret_t ipmi_storage_add_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
567 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500568 ipmi_data_len_t data_len, ipmi_context_t context)
569{
570
571 ipmi_ret_t rc = IPMI_CC_OK;
Chris Austen41a4b312015-10-25 03:45:42 -0500572 ipmi_add_sel_request_t *p = (ipmi_add_sel_request_t*) request;
573 uint16_t recordid;
Chris Austenb4f5b922015-10-13 12:44:43 -0500574
Chris Austen313d95b2015-10-31 12:55:30 -0500575 recordid = ((uint16_t)p->eventdata[1] << 8) | p->eventdata[2];
Chris Austen41a4b312015-10-25 03:45:42 -0500576
577 printf("IPMI Handling ADD-SEL for record 0x%04x\n", recordid);
Chris Austenb4f5b922015-10-13 12:44:43 -0500578
579 *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);
610 try
611 {
612 const auto& fruArea = getFruAreaData(reqptr->fruID);
613 auto size = static_cast<uint16_t>(fruArea.size());
614 FruInvenAreaInfoResponse resp;
615 resp.sizems = size >> 8;
616 resp.sizels = size;
617 resp.access = static_cast<uint8_t>(AccessMode::bytes);
618
619 *data_len = sizeof(resp);
620
621 // Pack the actual response
622 memcpy(response, &resp, *data_len);
623 }
624 catch(const InternalFailure& e)
625 {
626 rc = IPMI_CC_UNSPECIFIED_ERROR;
627 *data_len = 0;
628 log<level::ERR>(e.what());
629 report<InternalFailure>();
630 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500631 return rc;
632}
633
634//Read FRU data
635ipmi_ret_t ipmi_storage_read_fru_data(
636 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
637 ipmi_response_t response, ipmi_data_len_t data_len,
638 ipmi_context_t context)
639{
640 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500641 const ReadFruDataRequest* reqptr =
642 reinterpret_cast<const ReadFruDataRequest*>(request);
643 auto offset =
644 static_cast<uint16_t>(reqptr->offsetMS << 8 | reqptr->offsetLS);
645 try
646 {
647 const auto& fruArea = getFruAreaData(reqptr->fruID);
648 auto size = fruArea.size();
649 if ((offset + reqptr->count) > size)
650 {
651 log<level::ERR>("Invalid offset and count",
Gunnar Millse4050f22017-10-19 16:36:45 -0500652 entry("OFFSET=%s", offset),
653 entry("COUNT=%s", reqptr->count),
654 entry("SIZE_OF_FRU_AREA=%s", size));
Marri Devender Raocac383b2017-07-03 13:24:27 -0500655 return IPMI_CC_INVALID;
656 }
Ratan Gupta2848d602018-01-31 20:39:20 +0530657
658 // Write the count of requested data.
659 auto buff = static_cast<uint8_t *>(response);
660 *buff = reqptr->count;
661 buff++;
662
663 std::copy((fruArea.begin() + offset),
664 (fruArea.begin() + offset + reqptr->count),
665 buff);
666
667 *data_len = reqptr->count + 1; // additional one byte for count
Marri Devender Raocac383b2017-07-03 13:24:27 -0500668 }
669 catch (const InternalFailure& e)
670 {
671 rc = IPMI_CC_UNSPECIFIED_ERROR;
672 *data_len = 0;
673 log<level::ERR>(e.what());
674 report<InternalFailure>();
675 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500676 return rc;
677}
678
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600679ipmi_ret_t ipmi_get_repository_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
680 ipmi_request_t request, ipmi_response_t response,
681 ipmi_data_len_t data_len, ipmi_context_t context)
682{
683 constexpr auto sdrVersion = 0x51;
684 auto responseData =
685 reinterpret_cast<GetRepositoryInfoResponse*>(response);
686
687 memset(responseData, 0 , sizeof(GetRepositoryInfoResponse));
688
689 responseData->sdrVersion = sdrVersion;
690
691 uint16_t records = frus.size() + sensors.size();
692 responseData->recordCountMs = records >> 8;
693 responseData->recordCountLs = records;
694
695 responseData->freeSpace[0] = 0xFF;
696 responseData->freeSpace[1] = 0xFF;
697
698 *data_len = sizeof(GetRepositoryInfoResponse);
699
700 return IPMI_CC_OK;
701}
Chris Austenb4f5b922015-10-13 12:44:43 -0500702
Chris Austenb4f5b922015-10-13 12:44:43 -0500703void register_netfn_storage_functions()
704{
Tom05732372016-09-06 17:21:23 +0530705 // <Wildcard Command>
Chris Austenb4f5b922015-10-13 12:44:43 -0500706 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_WILDCARD);
Tom05732372016-09-06 17:21:23 +0530707 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WILDCARD, NULL, ipmi_storage_wildcard,
708 PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500709
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530710 // <Get SEL Info>
711 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO);
712 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO, NULL, getSELInfo,
713 PRIVILEGE_USER);
714
Tom05732372016-09-06 17:21:23 +0530715 // <Get SEL Time>
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500716 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME);
Tom05732372016-09-06 17:21:23 +0530717 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME, NULL, ipmi_storage_get_sel_time,
718 PRIVILEGE_USER);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500719
Tom05732372016-09-06 17:21:23 +0530720 // <Set SEL Time>
Chris Austenb4f5b922015-10-13 12:44:43 -0500721 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME);
Tom05732372016-09-06 17:21:23 +0530722 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME, NULL, ipmi_storage_set_sel_time,
723 PRIVILEGE_OPERATOR);
Chris Austenb4f5b922015-10-13 12:44:43 -0500724
Tom05732372016-09-06 17:21:23 +0530725 // <Reserve SEL>
Chris Austenb4f5b922015-10-13 12:44:43 -0500726 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL);
Tom05732372016-09-06 17:21:23 +0530727 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL, NULL, ipmi_storage_reserve_sel,
728 PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500729
Tom Josepha4953392017-06-30 19:09:47 +0530730 // <Get SEL Entry>
731 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY);
732 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY, NULL, getSELEntry,
733 PRIVILEGE_USER);
734
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530735 // <Delete SEL Entry>
736 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_DELETE_SEL);
737 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_DELETE_SEL, NULL, deleteSELEntry,
738 PRIVILEGE_OPERATOR);
739
Tom05732372016-09-06 17:21:23 +0530740 // <Add SEL Entry>
Chris Austenb4f5b922015-10-13 12:44:43 -0500741 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_ADD_SEL);
Tom05732372016-09-06 17:21:23 +0530742 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_ADD_SEL, NULL, ipmi_storage_add_sel,
743 PRIVILEGE_OPERATOR);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530744 // <Clear SEL>
745 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_CLEAR_SEL);
746 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_CLEAR_SEL, NULL, clearSEL,
747 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500748 // <Get FRU Inventory Area Info>
749 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_STORAGE,
750 IPMI_CMD_GET_FRU_INV_AREA_INFO);
751 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_FRU_INV_AREA_INFO, NULL,
752 ipmi_storage_get_fru_inv_area_info, PRIVILEGE_OPERATOR);
753
754 // <Add READ FRU Data
755 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_STORAGE,
756 IPMI_CMD_READ_FRU_DATA);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500757 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_READ_FRU_DATA, NULL,
758 ipmi_storage_read_fru_data, PRIVILEGE_OPERATOR);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500759
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600760 // <Get Repository Info>
761 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_REPOSITORY_INFO,
762 nullptr, ipmi_get_repository_info,
763 PRIVILEGE_USER);
764
Marri Devender Rao908f7502017-07-10 01:49:54 -0500765 ipmi::fru::registerCallbackHandler();
Chris Austenb4f5b922015-10-13 12:44:43 -0500766 return;
767}
768