blob: b8ea6f2ea14666523632b547b35476c83b02cfec [file] [log] [blame]
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001/*
2 * Copyright (c) 2018 Intel Corporation.
3 * Copyright (c) 2018-present Facebook.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include "xyz/openbmc_project/Common/error.hpp"
Vijay Khemkae7d23d02019-03-08 13:13:40 -080019
Cosmo Chou99d42b62024-08-15 10:42:47 +080020#include <boost/crc.hpp>
Patrick Williams2405ae92023-05-10 07:50:09 -050021#include <commandutils.hpp>
22#include <ipmid/api-types.hpp>
Vijay Khemka63c99be2020-05-27 19:14:35 -070023#include <ipmid/api.hpp>
Vijay Khemka1b6fae32019-03-25 17:43:01 -070024#include <ipmid/utils.hpp>
Vijay Khemka63c99be2020-05-27 19:14:35 -070025#include <nlohmann/json.hpp>
26#include <oemcommands.hpp>
Vijay Khemkae7d23d02019-03-08 13:13:40 -080027#include <phosphor-logging/log.hpp>
28#include <sdbusplus/bus.hpp>
Patrick Williams2405ae92023-05-10 07:50:09 -050029#include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
30#include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
31#include <xyz/openbmc_project/Control/Boot/Type/server.hpp>
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +053032
Vijay Khemka63c99be2020-05-27 19:14:35 -070033#include <array>
34#include <cstring>
35#include <fstream>
36#include <iomanip>
37#include <iostream>
Patrick Williams2405ae92023-05-10 07:50:09 -050038#include <regex>
Vijay Khemka63c99be2020-05-27 19:14:35 -070039#include <sstream>
Vijay Khemkae7d23d02019-03-08 13:13:40 -080040#include <string>
41#include <vector>
42
43#define SIZE_IANA_ID 3
44
45namespace ipmi
46{
Vijay Khemkaa7231892019-10-11 11:35:05 -070047
48using namespace phosphor::logging;
49
Karthikeyan Pasupathie1ff81f2022-11-21 17:54:46 +053050void getSelectorPosition(size_t& position);
Vijay Khemkae7d23d02019-03-08 13:13:40 -080051static void registerOEMFunctions() __attribute__((constructor));
Patrick Williamscd315e02022-07-22 19:26:52 -050052sdbusplus::bus_t dbus(ipmid_get_sd_bus_connection()); // from ipmid/api.h
Vijay Khemkae7d23d02019-03-08 13:13:40 -080053static constexpr size_t maxFRUStringLength = 0x3F;
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +053054constexpr uint8_t cmdSetSystemGuid = 0xEF;
Vijay Khemkae7d23d02019-03-08 13:13:40 -080055
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +053056constexpr uint8_t cmdSetQDimmInfo = 0x12;
57constexpr uint8_t cmdGetQDimmInfo = 0x13;
58
Cosmo Chou7ab87bb2024-06-28 10:47:44 +080059constexpr ipmi_ret_t ccInvalidParam = 0x80;
60
Vijay Khemka63c99be2020-05-27 19:14:35 -070061int plat_udbg_get_post_desc(uint8_t, uint8_t*, uint8_t, uint8_t*, uint8_t*,
62 uint8_t*);
63int plat_udbg_get_gpio_desc(uint8_t, uint8_t*, uint8_t*, uint8_t*, uint8_t*,
64 uint8_t*);
Patrick Williams5e589482024-07-13 16:18:13 -050065int plat_udbg_get_frame_data(uint8_t, uint8_t, uint8_t*, uint8_t*, uint8_t*);
Vijay Khemka63c99be2020-05-27 19:14:35 -070066ipmi_ret_t plat_udbg_control_panel(uint8_t, uint8_t, uint8_t, uint8_t*,
67 uint8_t*);
68int sendMeCmd(uint8_t, uint8_t, std::vector<uint8_t>&, std::vector<uint8_t>&);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -070069
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +053070int sendBicCmd(uint8_t, uint8_t, uint8_t, std::vector<uint8_t>&,
71 std::vector<uint8_t>&);
72
Vijay Khemkafeaa9812019-08-27 15:08:08 -070073nlohmann::json oemData __attribute__((init_priority(101)));
Vijay Khemka1b6fae32019-03-25 17:43:01 -070074
Cosmo Chou99d42b62024-08-15 10:42:47 +080075constexpr const char* certPath = "/mnt/data/host/bios-rootcert";
76
Vijay Khemkaf2246ce2020-05-27 14:26:35 -070077static constexpr size_t GUID_SIZE = 16;
78// TODO Make offset and location runtime configurable to ensure we
79// can make each define their own locations.
80static constexpr off_t OFFSET_SYS_GUID = 0x17F0;
81static constexpr const char* FRU_EEPROM = "/sys/bus/i2c/devices/6-0054/eeprom";
Delphine CC Chiu7bb45922023-04-10 13:34:04 +080082void flushOemData();
Vijay Khemkaf2246ce2020-05-27 14:26:35 -070083
Vijay Khemka1b6fae32019-03-25 17:43:01 -070084enum class LanParam : uint8_t
85{
86 INPROGRESS = 0,
87 AUTHSUPPORT = 1,
88 AUTHENABLES = 2,
89 IP = 3,
90 IPSRC = 4,
91 MAC = 5,
92 SUBNET = 6,
93 GATEWAY = 12,
94 VLAN = 20,
95 CIPHER_SUITE_COUNT = 22,
96 CIPHER_SUITE_ENTRIES = 23,
97 IPV6 = 59,
98};
99
Vijay Khemkaa7231892019-10-11 11:35:05 -0700100namespace network
101{
102
103constexpr auto ROOT = "/xyz/openbmc_project/network";
104constexpr auto SERVICE = "xyz.openbmc_project.Network";
105constexpr auto IPV4_TYPE = "ipv4";
106constexpr auto IPV6_TYPE = "ipv6";
107constexpr auto IPV4_PREFIX = "169.254";
108constexpr auto IPV6_PREFIX = "fe80";
109constexpr auto IP_INTERFACE = "xyz.openbmc_project.Network.IP";
110constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress";
Potin Lai8d1a81e2022-12-20 11:13:45 +0800111constexpr auto IPV4_PROTOCOL = "xyz.openbmc_project.Network.IP.Protocol.IPv4";
112constexpr auto IPV6_PROTOCOL = "xyz.openbmc_project.Network.IP.Protocol.IPv6";
Vijay Khemkaa7231892019-10-11 11:35:05 -0700113
Vijay Khemka63c99be2020-05-27 19:14:35 -0700114bool isLinkLocalIP(const std::string& address)
Vijay Khemkaa7231892019-10-11 11:35:05 -0700115{
116 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
117}
118
Patrick Williamscd315e02022-07-22 19:26:52 -0500119DbusObjectInfo getIPObject(sdbusplus::bus_t& bus, const std::string& interface,
Vijay Khemka63c99be2020-05-27 19:14:35 -0700120 const std::string& serviceRoot,
Potin Lai8d1a81e2022-12-20 11:13:45 +0800121 const std::string& protocol,
122 const std::string& ethdev)
Vijay Khemkaa7231892019-10-11 11:35:05 -0700123{
Potin Lai8d1a81e2022-12-20 11:13:45 +0800124 auto objectTree = getAllDbusObjects(bus, serviceRoot, interface, ethdev);
Vijay Khemkaa7231892019-10-11 11:35:05 -0700125
126 if (objectTree.empty())
127 {
128 log<level::ERR>("No Object has implemented the IP interface",
129 entry("INTERFACE=%s", interface.c_str()));
130 }
131
132 DbusObjectInfo objectInfo;
133
Vijay Khemka63c99be2020-05-27 19:14:35 -0700134 for (auto& object : objectTree)
Vijay Khemkaa7231892019-10-11 11:35:05 -0700135 {
Patrick Williams010dee02024-08-16 15:19:44 -0400136 auto variant =
137 ipmi::getDbusProperty(bus, object.second.begin()->first,
138 object.first, IP_INTERFACE, "Type");
Potin Lai8d1a81e2022-12-20 11:13:45 +0800139 if (std::get<std::string>(variant) != protocol)
140 {
141 continue;
142 }
143
144 variant = ipmi::getDbusProperty(bus, object.second.begin()->first,
145 object.first, IP_INTERFACE, "Address");
Vijay Khemkaa7231892019-10-11 11:35:05 -0700146
147 objectInfo = std::make_pair(object.first, object.second.begin()->first);
148
149 // if LinkLocalIP found look for Non-LinkLocalIP
150 if (isLinkLocalIP(std::get<std::string>(variant)))
151 {
152 continue;
153 }
154 else
155 {
156 break;
157 }
158 }
159 return objectInfo;
160}
161
162} // namespace network
163
Jayashree-Df0cf6652020-11-30 11:03:30 +0530164namespace boot
165{
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530166using BootSource =
167 sdbusplus::xyz::openbmc_project::Control::Boot::server::Source::Sources;
168using BootMode =
169 sdbusplus::xyz::openbmc_project::Control::Boot::server::Mode::Modes;
170using BootType =
171 sdbusplus::xyz::openbmc_project::Control::Boot::server::Type::Types;
Jayashree-Df0cf6652020-11-30 11:03:30 +0530172
Jayashree-Df0cf6652020-11-30 11:03:30 +0530173using IpmiValue = uint8_t;
174
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530175std::map<IpmiValue, BootSource> sourceIpmiToDbus = {
176 {0x0f, BootSource::Default}, {0x00, BootSource::RemovableMedia},
177 {0x01, BootSource::Network}, {0x02, BootSource::Disk},
Delphine CC Chiu7bb45922023-04-10 13:34:04 +0800178 {0x03, BootSource::ExternalMedia}, {0x04, BootSource::RemovableMedia},
179 {0x09, BootSource::Network}};
Jayashree-Df0cf6652020-11-30 11:03:30 +0530180
Delphine CC Chiuc0f918b2023-03-22 14:48:04 +0800181std::map<IpmiValue, BootMode> modeIpmiToDbus = {{0x04, BootMode::Setup},
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530182 {0x00, BootMode::Regular}};
Jayashree-Df0cf6652020-11-30 11:03:30 +0530183
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530184std::map<IpmiValue, BootType> typeIpmiToDbus = {{0x00, BootType::Legacy},
185 {0x01, BootType::EFI}};
Jayashree Dhanapal778147d2022-03-30 16:48:53 +0530186
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530187std::map<std::optional<BootSource>, IpmiValue> sourceDbusToIpmi = {
188 {BootSource::Default, 0x0f},
189 {BootSource::RemovableMedia, 0x00},
190 {BootSource::Network, 0x01},
191 {BootSource::Disk, 0x02},
192 {BootSource::ExternalMedia, 0x03}};
Jayashree-Df0cf6652020-11-30 11:03:30 +0530193
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530194std::map<std::optional<BootMode>, IpmiValue> modeDbusToIpmi = {
Delphine CC Chiuc0f918b2023-03-22 14:48:04 +0800195 {BootMode::Setup, 0x04}, {BootMode::Regular, 0x00}};
Jayashree-Df0cf6652020-11-30 11:03:30 +0530196
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530197std::map<std::optional<BootType>, IpmiValue> typeDbusToIpmi = {
198 {BootType::Legacy, 0x00}, {BootType::EFI, 0x01}};
Jayashree Dhanapal778147d2022-03-30 16:48:53 +0530199
Delphine CC Chiuc0f918b2023-03-22 14:48:04 +0800200static constexpr auto bootEnableIntf = "xyz.openbmc_project.Object.Enable";
Jayashree-Df0cf6652020-11-30 11:03:30 +0530201static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
202static constexpr auto bootSourceIntf =
203 "xyz.openbmc_project.Control.Boot.Source";
Jayashree Dhanapal778147d2022-03-30 16:48:53 +0530204static constexpr auto bootTypeIntf = "xyz.openbmc_project.Control.Boot.Type";
Jayashree-Df0cf6652020-11-30 11:03:30 +0530205static constexpr auto bootSourceProp = "BootSource";
206static constexpr auto bootModeProp = "BootMode";
Jayashree Dhanapal778147d2022-03-30 16:48:53 +0530207static constexpr auto bootTypeProp = "BootType";
Delphine CC Chiuc0f918b2023-03-22 14:48:04 +0800208static constexpr auto bootEnableProp = "Enabled";
Jayashree-Df0cf6652020-11-30 11:03:30 +0530209
Jayashree-Df0cf6652020-11-30 11:03:30 +0530210std::tuple<std::string, std::string> objPath(size_t id)
211{
212 std::string hostName = "host" + std::to_string(id);
Patrick Williams010dee02024-08-16 15:19:44 -0400213 std::string bootObjPath =
214 "/xyz/openbmc_project/control/" + hostName + "/boot";
Jayashree-Df0cf6652020-11-30 11:03:30 +0530215 return std::make_tuple(std::move(bootObjPath), std::move(hostName));
216}
217
Delphine CC Chiu7bb45922023-04-10 13:34:04 +0800218/* Helper functions to set boot order */
219void setBootOrder(std::string bootObjPath, const std::vector<uint8_t>& bootSeq,
220 std::string bootOrderKey)
221{
222 if (bootSeq.size() != SIZE_BOOT_ORDER)
223 {
224 phosphor::logging::log<phosphor::logging::level::ERR>(
225 "Invalid Boot order length received");
226 return;
227 }
228
229 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
230
231 uint8_t mode = bootSeq.front();
232
233 // SETTING BOOT MODE PROPERTY
234 uint8_t bootModeBit = mode & 0x04;
235 auto bootValue = ipmi::boot::modeIpmiToDbus.at(bootModeBit);
236
237 std::string bootOption =
238 sdbusplus::message::convert_to_string<boot::BootMode>(bootValue);
239
Patrick Williams010dee02024-08-16 15:19:44 -0400240 std::string service =
241 getService(*dbus, ipmi::boot::bootModeIntf, bootObjPath);
Delphine CC Chiu7bb45922023-04-10 13:34:04 +0800242 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootModeIntf,
243 ipmi::boot::bootModeProp, bootOption);
244
245 // SETTING BOOT SOURCE PROPERTY
246 auto bootOrder = ipmi::boot::sourceIpmiToDbus.at(bootSeq.at(1));
247 std::string bootSource =
248 sdbusplus::message::convert_to_string<boot::BootSource>(bootOrder);
249
250 service = getService(*dbus, ipmi::boot::bootSourceIntf, bootObjPath);
251 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootSourceIntf,
252 ipmi::boot::bootSourceProp, bootSource);
253
254 // SETTING BOOT TYPE PROPERTY
255 uint8_t bootTypeBit = mode & 0x01;
256 auto bootTypeVal = ipmi::boot::typeIpmiToDbus.at(bootTypeBit);
257
258 std::string bootType =
259 sdbusplus::message::convert_to_string<boot::BootType>(bootTypeVal);
260
261 service = getService(*dbus, ipmi::boot::bootTypeIntf, bootObjPath);
262
263 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootTypeIntf,
264 ipmi::boot::bootTypeProp, bootType);
265
266 // Set the valid bit to boot enabled property
267 service = getService(*dbus, ipmi::boot::bootEnableIntf, bootObjPath);
268
269 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootEnableIntf,
270 ipmi::boot::bootEnableProp,
271 (mode & BOOT_MODE_BOOT_FLAG) ? true : false);
272
273 nlohmann::json bootMode;
274
275 bootMode["UEFI"] = (mode & BOOT_MODE_UEFI) ? true : false;
276 bootMode["CMOS_CLR"] = (mode & BOOT_MODE_CMOS_CLR) ? true : false;
277 bootMode["FORCE_BOOT"] = (mode & BOOT_MODE_FORCE_BOOT) ? true : false;
278 bootMode["BOOT_FLAG"] = (mode & BOOT_MODE_BOOT_FLAG) ? true : false;
279 oemData[bootOrderKey][KEY_BOOT_MODE] = bootMode;
280
281 /* Initialize boot sequence array */
282 oemData[bootOrderKey][KEY_BOOT_SEQ] = {};
283 for (size_t i = 1; i < SIZE_BOOT_ORDER; i++)
284 {
285 if (bootSeq.at(i) >= BOOT_SEQ_ARRAY_SIZE)
286 oemData[bootOrderKey][KEY_BOOT_SEQ][i - 1] = "NA";
287 else
288 oemData[bootOrderKey][KEY_BOOT_SEQ][i - 1] =
289 bootSeqDefine[bootSeq.at(i)];
290 }
291
292 flushOemData();
293}
294
295void getBootOrder(std::string bootObjPath, std::vector<uint8_t>& bootSeq,
296 std::string hostName)
297{
298 if (oemData.find(hostName) == oemData.end())
299 {
300 /* Return default boot order 0100090203ff */
301 bootSeq.push_back(BOOT_MODE_UEFI);
302 bootSeq.push_back(static_cast<uint8_t>(bootMap["USB_DEV"]));
303 bootSeq.push_back(static_cast<uint8_t>(bootMap["NET_IPV6"]));
304 bootSeq.push_back(static_cast<uint8_t>(bootMap["SATA_HDD"]));
305 bootSeq.push_back(static_cast<uint8_t>(bootMap["SATA_CD"]));
306 bootSeq.push_back(0xff);
307
308 phosphor::logging::log<phosphor::logging::level::INFO>(
309 "Set default boot order");
310 setBootOrder(bootObjPath, bootSeq, hostName);
311 return;
312 }
313
314 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
315
316 // GETTING PROPERTY OF MODE INTERFACE
317
Patrick Williams010dee02024-08-16 15:19:44 -0400318 std::string service =
319 getService(*dbus, ipmi::boot::bootModeIntf, bootObjPath);
320 Value variant =
321 getDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootModeIntf,
322 ipmi::boot::bootModeProp);
Delphine CC Chiu7bb45922023-04-10 13:34:04 +0800323
324 auto bootMode = sdbusplus::message::convert_from_string<boot::BootMode>(
325 std::get<std::string>(variant));
326
327 uint8_t bootOption = ipmi::boot::modeDbusToIpmi.at(bootMode);
328
329 // GETTING PROPERTY OF TYPE INTERFACE
330
331 service = getService(*dbus, ipmi::boot::bootTypeIntf, bootObjPath);
Patrick Williams010dee02024-08-16 15:19:44 -0400332 variant =
333 getDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootTypeIntf,
334 ipmi::boot::bootTypeProp);
Delphine CC Chiu7bb45922023-04-10 13:34:04 +0800335
336 auto bootType = sdbusplus::message::convert_from_string<boot::BootType>(
337 std::get<std::string>(variant));
338
339 // Get the valid bit to boot enabled property
340 service = getService(*dbus, ipmi::boot::bootEnableIntf, bootObjPath);
Patrick Williams010dee02024-08-16 15:19:44 -0400341 variant =
342 getDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootEnableIntf,
343 ipmi::boot::bootEnableProp);
Delphine CC Chiu7bb45922023-04-10 13:34:04 +0800344
345 bool validFlag = std::get<bool>(variant);
346
347 uint8_t bootTypeVal = ipmi::boot::typeDbusToIpmi.at(bootType);
348
349 bootSeq.push_back(bootOption | bootTypeVal);
350
351 if (validFlag)
352 {
353 bootSeq.front() |= BOOT_MODE_BOOT_FLAG;
354 }
355
356 nlohmann::json bootModeJson = oemData[hostName][KEY_BOOT_MODE];
357 if (bootModeJson["CMOS_CLR"])
358 bootSeq.front() |= BOOT_MODE_CMOS_CLR;
359
360 for (int i = 1; i < SIZE_BOOT_ORDER; i++)
361 {
362 std::string seqStr = oemData[hostName][KEY_BOOT_SEQ][i - 1];
363 if (bootMap.find(seqStr) != bootMap.end())
364 bootSeq.push_back(bootMap[seqStr]);
365 else
366 bootSeq.push_back(0xff);
367 }
368}
369
Jayashree-Df0cf6652020-11-30 11:03:30 +0530370} // namespace boot
371
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700372//----------------------------------------------------------------------
373// Helper functions for storing oem data
374//----------------------------------------------------------------------
375
376void flushOemData()
377{
378 std::ofstream file(JSON_OEM_DATA_FILE);
379 file << oemData;
Vijay Khemkafeaa9812019-08-27 15:08:08 -0700380 file.close();
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700381 return;
382}
383
Vijay Khemka63c99be2020-05-27 19:14:35 -0700384std::string bytesToStr(uint8_t* byte, int len)
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700385{
386 std::stringstream ss;
387 int i;
388
389 ss << std::hex;
390 for (i = 0; i < len; i++)
391 {
392 ss << std::setw(2) << std::setfill('0') << (int)byte[i];
393 }
394
395 return ss.str();
396}
397
Vijay Khemka63c99be2020-05-27 19:14:35 -0700398int strToBytes(std::string& str, uint8_t* data)
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700399{
400 std::string sstr;
Willy Tue39f9392022-06-15 13:24:20 -0700401 size_t i;
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700402
403 for (i = 0; i < (str.length()) / 2; i++)
404 {
405 sstr = str.substr(i * 2, 2);
406 data[i] = (uint8_t)std::strtol(sstr.c_str(), NULL, 16);
407 }
408 return i;
409}
410
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +0530411int readDimmType(std::string& data, uint8_t param)
412{
413 nlohmann::json dimmObj;
414 /* Get dimm type names stored in json file */
415 std::ifstream file(JSON_DIMM_TYPE_FILE);
416 if (file)
417 {
418 file >> dimmObj;
419 file.close();
420 }
421 else
422 {
423 phosphor::logging::log<phosphor::logging::level::ERR>(
424 "DIMM type names file not found",
425 phosphor::logging::entry("DIMM_TYPE_FILE=%s", JSON_DIMM_TYPE_FILE));
426 return -1;
427 }
428
429 std::string dimmKey = "dimm_type" + std::to_string(param);
430 auto obj = dimmObj[dimmKey]["short_name"];
431 data = obj;
432 return 0;
433}
434
Vijay Khemka63c99be2020-05-27 19:14:35 -0700435ipmi_ret_t getNetworkData(uint8_t lan_param, char* data)
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700436{
437 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Williamscd315e02022-07-22 19:26:52 -0500438 sdbusplus::bus_t bus(ipmid_get_sd_bus_connection());
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700439
440 const std::string ethdevice = "eth0";
441
442 switch (static_cast<LanParam>(lan_param))
443 {
Vijay Khemkad1194022020-05-27 18:58:33 -0700444 case LanParam::IP:
445 {
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700446 std::string ipaddress;
Vijay Khemkaa7231892019-10-11 11:35:05 -0700447 auto ipObjectInfo = ipmi::network::getIPObject(
Potin Lai8d1a81e2022-12-20 11:13:45 +0800448 bus, ipmi::network::IP_INTERFACE, ipmi::network::ROOT,
449 ipmi::network::IPV4_PROTOCOL, ethdevice);
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700450
451 auto properties = ipmi::getAllDbusProperties(
452 bus, ipObjectInfo.second, ipObjectInfo.first,
453 ipmi::network::IP_INTERFACE);
454
Patrick Williamsef0efbc2020-05-13 11:26:51 -0500455 ipaddress = std::get<std::string>(properties["Address"]);
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700456
457 std::strcpy(data, ipaddress.c_str());
458 }
459 break;
460
Vijay Khemkad1194022020-05-27 18:58:33 -0700461 case LanParam::IPV6:
462 {
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700463 std::string ipaddress;
Vijay Khemkaa7231892019-10-11 11:35:05 -0700464 auto ipObjectInfo = ipmi::network::getIPObject(
Potin Lai8d1a81e2022-12-20 11:13:45 +0800465 bus, ipmi::network::IP_INTERFACE, ipmi::network::ROOT,
466 ipmi::network::IPV6_PROTOCOL, ethdevice);
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700467
468 auto properties = ipmi::getAllDbusProperties(
469 bus, ipObjectInfo.second, ipObjectInfo.first,
470 ipmi::network::IP_INTERFACE);
471
Patrick Williamsef0efbc2020-05-13 11:26:51 -0500472 ipaddress = std::get<std::string>(properties["Address"]);
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700473
474 std::strcpy(data, ipaddress.c_str());
475 }
476 break;
477
Vijay Khemkad1194022020-05-27 18:58:33 -0700478 case LanParam::MAC:
479 {
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700480 std::string macAddress;
481 auto macObjectInfo =
482 ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE,
483 ipmi::network::ROOT, ethdevice);
484
485 auto variant = ipmi::getDbusProperty(
486 bus, macObjectInfo.second, macObjectInfo.first,
487 ipmi::network::MAC_INTERFACE, "MACAddress");
488
Patrick Williamsef0efbc2020-05-13 11:26:51 -0500489 macAddress = std::get<std::string>(variant);
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700490
491 sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT,
492 (data), (data + 1), (data + 2), (data + 3), (data + 4),
493 (data + 5));
494 std::strcpy(data, macAddress.c_str());
495 }
496 break;
497
498 default:
499 rc = IPMI_CC_PARM_OUT_OF_RANGE;
500 }
501 return rc;
502}
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800503
Karthikeyan Pasupathi39836ff2022-01-17 12:20:06 +0530504bool isMultiHostPlatform()
505{
506 bool platform;
Jayashree Dhanapal4ec80562022-06-28 15:41:47 +0530507 if (hostInstances == "0")
Karthikeyan Pasupathi39836ff2022-01-17 12:20:06 +0530508 {
509 platform = false;
510 }
511 else
512 {
513 platform = true;
514 }
515 return platform;
516}
517
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800518// return code: 0 successful
Vijay Khemka63c99be2020-05-27 19:14:35 -0700519int8_t getFruData(std::string& data, std::string& name)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800520{
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530521 size_t pos;
522 static constexpr const auto depth = 0;
523 std::vector<std::string> paths;
524 std::string machinePath;
525 std::string baseBoard = "Baseboard";
526
527 bool platform = isMultiHostPlatform();
528 if (platform == true)
529 {
Karthikeyan Pasupathie1ff81f2022-11-21 17:54:46 +0530530 getSelectorPosition(pos);
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530531 }
532
533 sd_bus* bus = NULL;
534 int ret = sd_bus_default_system(&bus);
535 if (ret < 0)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800536 {
537 phosphor::logging::log<phosphor::logging::level::ERR>(
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530538 "Failed to connect to system bus",
539 phosphor::logging::entry("ERRNO=0x%X", -ret));
540 sd_bus_unref(bus);
541 return -1;
542 }
Patrick Williamscd315e02022-07-22 19:26:52 -0500543 sdbusplus::bus_t dbus(bus);
Patrick Williams010dee02024-08-16 15:19:44 -0400544 auto mapperCall = dbus.new_method_call(
545 "xyz.openbmc_project.ObjectMapper",
546 "/xyz/openbmc_project/object_mapper",
547 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths");
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530548 static constexpr std::array<const char*, 1> interface = {
549 "xyz.openbmc_project.Inventory.Decorator.Asset"};
550 mapperCall.append("/xyz/openbmc_project/inventory/", depth, interface);
551
552 try
553 {
554 auto reply = dbus.call(mapperCall);
555 reply.read(paths);
556 }
557 catch (sdbusplus::exception_t& e)
558 {
559 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800560 return -1;
561 }
562
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530563 for (const auto& path : paths)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800564 {
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530565 if (platform == true)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800566 {
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530567 if (pos == BMC_POS)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800568 {
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530569 machinePath = baseBoard;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800570 }
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530571 else
572 {
573 machinePath = "_" + std::to_string(pos);
574 }
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800575 }
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530576 else
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800577 {
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530578 machinePath = baseBoard;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800579 }
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530580
581 auto found = path.find(machinePath);
Patrick Williams123cbcc2022-06-24 06:13:59 -0500582 if (found == std::string::npos)
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530583 {
584 continue;
585 }
586
587 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
588 std::string service = getService(
589 *dbus, "xyz.openbmc_project.Inventory.Decorator.Asset", path);
590
591 auto Value = ipmi::getDbusProperty(
592 *dbus, service, path,
593 "xyz.openbmc_project.Inventory.Decorator.Asset", name);
594
595 data = std::get<std::string>(Value);
596 return 0;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800597 }
598 return -1;
599}
600
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +0530601int8_t sysConfig(std::vector<std::string>& data, size_t pos)
602{
603 nlohmann::json sysObj;
604 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(pos);
605 std::string result, typeName;
606 uint8_t res[MAX_BUF];
607
608 /* Get sysConfig data stored in json file */
609 std::ifstream file(JSON_OEM_DATA_FILE);
610 if (file)
611 {
612 file >> sysObj;
613 file.close();
614 }
615 else
616 {
617 phosphor::logging::log<phosphor::logging::level::ERR>(
618 "oemData file not found",
619 phosphor::logging::entry("OEM_DATA_FILE=%s", JSON_OEM_DATA_FILE));
620 return -1;
621 }
622
623 if (sysObj.find(dimmInfo) == sysObj.end())
624 {
625 phosphor::logging::log<phosphor::logging::level::ERR>(
626 "sysconfig key not available",
627 phosphor::logging::entry("SYS_JSON_KEY=%s", dimmInfo.c_str()));
628 return -1;
629 }
630 /* Get dimm type names stored in json file */
631 nlohmann::json dimmObj;
632 std::ifstream dimmFile(JSON_DIMM_TYPE_FILE);
633 if (file)
634 {
635 dimmFile >> dimmObj;
636 dimmFile.close();
637 }
638 else
639 {
640 phosphor::logging::log<phosphor::logging::level::ERR>(
641 "DIMM type names file not found",
642 phosphor::logging::entry("DIMM_TYPE_FILE=%s", JSON_DIMM_TYPE_FILE));
643 return -1;
644 }
645 std::vector<std::string> a;
646 for (auto& j : dimmObj.items())
647 {
648 std::string name = j.key();
649 a.push_back(name);
650 }
651
652 uint8_t len = a.size();
653 for (uint8_t ii = 0; ii < len; ii++)
654 {
655 std::string indKey = std::to_string(ii);
656 std::string speedSize = sysObj[dimmInfo][indKey][DIMM_SPEED];
657 strToBytes(speedSize, res);
658 auto speed = (res[1] << 8 | res[0]);
659 size_t dimmSize = ((res[3] << 8 | res[2]) / 1000);
660
661 if (dimmSize == 0)
662 {
663 std::cerr << "Dimm information not available for slot_" +
664 std::to_string(ii)
665 << std::endl;
666 continue;
667 }
668 std::string type = sysObj[dimmInfo][indKey][DIMM_TYPE];
669 std::string dualInlineMem = sysObj[dimmInfo][indKey][KEY_DIMM_TYPE];
670 strToBytes(type, res);
671 size_t dimmType = res[0];
672 if (dimmVenMap.find(dimmType) == dimmVenMap.end())
673 {
674 typeName = "unknown";
675 }
676 else
677 {
678 typeName = dimmVenMap[dimmType];
679 }
680 result = dualInlineMem + "/" + typeName + "/" + std::to_string(speed) +
681 "MHz" + "/" + std::to_string(dimmSize) + "GB";
682 data.push_back(result);
683 }
684 return 0;
685}
686
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +0530687int8_t procInfo(std::string& result, size_t pos)
688{
689 std::vector<char> data;
690 uint8_t res[MAX_BUF];
691 std::string procIndex = "00";
692 nlohmann::json proObj;
693 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(pos);
694 /* Get processor data stored in json file */
695 std::ifstream file(JSON_OEM_DATA_FILE);
696 if (file)
697 {
698 file >> proObj;
699 file.close();
700 }
701 else
702 {
703 phosphor::logging::log<phosphor::logging::level::ERR>(
704 "oemData file not found",
705 phosphor::logging::entry("OEM_DATA_FILE=%s", JSON_OEM_DATA_FILE));
706 return -1;
707 }
708 if (proObj.find(procInfo) == proObj.end())
709 {
710 phosphor::logging::log<phosphor::logging::level::ERR>(
711 "processor info key not available",
712 phosphor::logging::entry("PROC_JSON_KEY=%s", procInfo.c_str()));
713 return -1;
714 }
715 std::string procName = proObj[procInfo][procIndex][KEY_PROC_NAME];
716 std::string basicInfo = proObj[procInfo][procIndex][KEY_BASIC_INFO];
717 // Processor Product Name
718 strToBytes(procName, res);
719 data.assign(reinterpret_cast<char*>(&res),
720 reinterpret_cast<char*>(&res) + sizeof(res));
721
722 std::string s(data.begin(), data.end());
723 std::regex regex(" ");
724 std::vector<std::string> productName(
725 std::sregex_token_iterator(s.begin(), s.end(), regex, -1),
726 std::sregex_token_iterator());
727
728 // Processor core and frequency
729 strToBytes(basicInfo, res);
730 uint16_t coreNum = res[0];
731 double procFrequency = (float)(res[4] << 8 | res[3]) / 1000;
732 result = "CPU:" + productName[2] + "/" + std::to_string(procFrequency) +
733 "GHz" + "/" + std::to_string(coreNum) + "c";
734 return 0;
735}
736
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800737typedef struct
738{
739 uint8_t cur_power_state;
740 uint8_t last_power_event;
741 uint8_t misc_power_state;
742 uint8_t front_panel_button_cap_status;
743} ipmi_get_chassis_status_t;
744
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800745//----------------------------------------------------------------------
746// Get Debug Frame Info
747//----------------------------------------------------------------------
Patrick Williams010dee02024-08-16 15:19:44 -0400748ipmi_ret_t ipmiOemDbgGetFrameInfo(
749 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
750 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800751{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700752 uint8_t* req = reinterpret_cast<uint8_t*>(request);
753 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Peter Yinb340aa22024-07-08 16:07:55 +0800754 uint8_t num_frames = debugCardFrameSize;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800755
756 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
757 res[SIZE_IANA_ID] = num_frames;
758 *data_len = SIZE_IANA_ID + 1;
759
760 return IPMI_CC_OK;
761}
762
763//----------------------------------------------------------------------
764// Get Debug Updated Frames
765//----------------------------------------------------------------------
Patrick Williams010dee02024-08-16 15:19:44 -0400766ipmi_ret_t ipmiOemDbgGetUpdFrames(
767 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
768 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800769{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700770 uint8_t* req = reinterpret_cast<uint8_t*>(request);
771 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800772 uint8_t num_updates = 3;
773 *data_len = 4;
774
775 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
776 res[SIZE_IANA_ID] = num_updates;
777 *data_len = SIZE_IANA_ID + num_updates + 1;
778 res[SIZE_IANA_ID + 1] = 1; // info page update
779 res[SIZE_IANA_ID + 2] = 2; // cri sel update
780 res[SIZE_IANA_ID + 3] = 3; // cri sensor update
781
782 return IPMI_CC_OK;
783}
784
785//----------------------------------------------------------------------
786// Get Debug POST Description
787//----------------------------------------------------------------------
Patrick Williams010dee02024-08-16 15:19:44 -0400788ipmi_ret_t ipmiOemDbgGetPostDesc(
789 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
790 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800791{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700792 uint8_t* req = reinterpret_cast<uint8_t*>(request);
793 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800794 uint8_t index = 0;
795 uint8_t next = 0;
796 uint8_t end = 0;
797 uint8_t phase = 0;
Vijay Khemkacc0d6d92019-08-27 14:51:17 -0700798 uint8_t descLen = 0;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800799 int ret;
800
801 index = req[3];
802 phase = req[4];
803
Vijay Khemkacc0d6d92019-08-27 14:51:17 -0700804 ret = plat_udbg_get_post_desc(index, &next, phase, &end, &descLen, &res[8]);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800805 if (ret)
806 {
807 memcpy(res, req, SIZE_IANA_ID); // IANA ID
808 *data_len = SIZE_IANA_ID;
809 return IPMI_CC_UNSPECIFIED_ERROR;
810 }
811
812 memcpy(res, req, SIZE_IANA_ID); // IANA ID
813 res[3] = index;
814 res[4] = next;
815 res[5] = phase;
816 res[6] = end;
Vijay Khemkacc0d6d92019-08-27 14:51:17 -0700817 res[7] = descLen;
818 *data_len = SIZE_IANA_ID + 5 + descLen;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800819
820 return IPMI_CC_OK;
821}
822
823//----------------------------------------------------------------------
824// Get Debug GPIO Description
825//----------------------------------------------------------------------
Patrick Williams010dee02024-08-16 15:19:44 -0400826ipmi_ret_t ipmiOemDbgGetGpioDesc(
827 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
828 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800829{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700830 uint8_t* req = reinterpret_cast<uint8_t*>(request);
831 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800832
Vijay Khemka38183d62019-08-28 16:19:33 -0700833 uint8_t index = 0;
834 uint8_t next = 0;
835 uint8_t level = 0;
836 uint8_t pinDef = 0;
837 uint8_t descLen = 0;
838 int ret;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800839
Vijay Khemka38183d62019-08-28 16:19:33 -0700840 index = req[3];
841
842 ret = plat_udbg_get_gpio_desc(index, &next, &level, &pinDef, &descLen,
843 &res[8]);
844 if (ret)
845 {
846 memcpy(res, req, SIZE_IANA_ID); // IANA ID
847 *data_len = SIZE_IANA_ID;
848 return IPMI_CC_UNSPECIFIED_ERROR;
849 }
850
851 memcpy(res, req, SIZE_IANA_ID); // IANA ID
852 res[3] = index;
853 res[4] = next;
854 res[5] = level;
855 res[6] = pinDef;
856 res[7] = descLen;
857 *data_len = SIZE_IANA_ID + 5 + descLen;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800858
859 return IPMI_CC_OK;
860}
861
862//----------------------------------------------------------------------
863// Get Debug Frame Data
864//----------------------------------------------------------------------
Patrick Williams010dee02024-08-16 15:19:44 -0400865ipmi_ret_t ipmiOemDbgGetFrameData(
866 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
867 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800868{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700869 uint8_t* req = reinterpret_cast<uint8_t*>(request);
870 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800871 uint8_t frame;
872 uint8_t page;
873 uint8_t next;
874 uint8_t count;
875 int ret;
876
877 frame = req[3];
878 page = req[4];
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800879
880 ret = plat_udbg_get_frame_data(frame, page, &next, &count, &res[7]);
881 if (ret)
882 {
883 memcpy(res, req, SIZE_IANA_ID); // IANA ID
884 *data_len = SIZE_IANA_ID;
885 return IPMI_CC_UNSPECIFIED_ERROR;
886 }
887
888 memcpy(res, req, SIZE_IANA_ID); // IANA ID
889 res[3] = frame;
890 res[4] = page;
891 res[5] = next;
892 res[6] = count;
893 *data_len = SIZE_IANA_ID + 4 + count;
894
895 return IPMI_CC_OK;
896}
897
898//----------------------------------------------------------------------
899// Get Debug Control Panel
900//----------------------------------------------------------------------
Patrick Williams010dee02024-08-16 15:19:44 -0400901ipmi_ret_t ipmiOemDbgGetCtrlPanel(
902 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
903 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800904{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700905 uint8_t* req = reinterpret_cast<uint8_t*>(request);
906 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800907
908 uint8_t panel;
909 uint8_t operation;
910 uint8_t item;
911 uint8_t count;
912 ipmi_ret_t ret;
913
914 panel = req[3];
915 operation = req[4];
916 item = req[5];
917
918 ret = plat_udbg_control_panel(panel, operation, item, &count, &res[3]);
919
920 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
921 *data_len = SIZE_IANA_ID + count;
922
923 return ret;
924}
925
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800926//----------------------------------------------------------------------
927// Set Dimm Info (CMD_OEM_SET_DIMM_INFO)
928//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -0700929ipmi_ret_t ipmiOemSetDimmInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
930 ipmi_response_t, ipmi_data_len_t data_len,
931 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800932{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700933 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700934
935 uint8_t index = req[0];
936 uint8_t type = req[1];
937 uint16_t speed;
938 uint32_t size;
939
940 memcpy(&speed, &req[2], 2);
941 memcpy(&size, &req[4], 4);
942
943 std::stringstream ss;
944 ss << std::hex;
945 ss << std::setw(2) << std::setfill('0') << (int)index;
946
947 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_INDEX] = index;
948 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_TYPE] = type;
949 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_SPEED] = speed;
950 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_SIZE] = size;
951
952 flushOemData();
953
954 *data_len = 0;
955
956 return IPMI_CC_OK;
957}
958
959//----------------------------------------------------------------------
960// Get Board ID (CMD_OEM_GET_BOARD_ID)
961//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -0700962ipmi_ret_t ipmiOemGetBoardID(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
963 ipmi_response_t, ipmi_data_len_t data_len,
964 ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700965{
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700966 /* TODO: Needs to implement this after GPIO implementation */
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800967 *data_len = 0;
968
969 return IPMI_CC_OK;
970}
971
Bonnie Lo4ae63e72023-02-09 15:27:54 +0800972//----------------------------------------------------------------------
973// Get port 80 record (CMD_OEM_GET_80PORT_RECORD)
974//----------------------------------------------------------------------
975ipmi::RspType<std::vector<uint8_t>>
976 ipmiOemGet80PortRecord(ipmi::Context::ptr ctx)
977{
978 auto postCodeService = "xyz.openbmc_project.State.Boot.PostCode" +
979 std::to_string(ctx->hostIdx + 1);
980 auto postCodeObjPath = "/xyz/openbmc_project/State/Boot/PostCode" +
981 std::to_string(ctx->hostIdx + 1);
982 constexpr auto postCodeInterface =
983 "xyz.openbmc_project.State.Boot.PostCode";
984 const static uint16_t lastestPostCodeIndex = 1;
985 constexpr const auto maxPostCodeLen =
986 224; // The length must be lower than IPMB limitation
987 size_t startIndex = 0;
988
989 std::vector<std::tuple<uint64_t, std::vector<uint8_t>>> postCodes;
990 std::vector<uint8_t> resData;
991
992 auto conn = getSdBus();
993 /* Get the post codes by calling GetPostCodes method */
Patrick Williams010dee02024-08-16 15:19:44 -0400994 auto msg =
995 conn->new_method_call(postCodeService.c_str(), postCodeObjPath.c_str(),
996 postCodeInterface, "GetPostCodes");
Bonnie Lo4ae63e72023-02-09 15:27:54 +0800997 msg.append(lastestPostCodeIndex);
998
999 try
1000 {
1001 auto reply = conn->call(msg);
1002 reply.read(postCodes);
1003 }
1004 catch (const sdbusplus::exception::SdBusError& e)
1005 {
1006 phosphor::logging::log<phosphor::logging::level::ERR>(
1007 "IPMI Get80PortRecord Failed in call method",
1008 phosphor::logging::entry("ERROR=%s", e.what()));
1009 return ipmi::responseUnspecifiedError();
1010 }
1011
1012 /* Get post code data */
1013 for (size_t i = 0; i < postCodes.size(); ++i)
1014 {
1015 uint64_t primaryPostCode = std::get<uint64_t>(postCodes[i]);
1016 for (int j = postCodeSize - 1; j >= 0; --j)
1017 {
1018 uint8_t postCode =
1019 ((primaryPostCode >> (sizeof(uint64_t) * j)) & 0xFF);
1020 resData.emplace_back(postCode);
1021 }
1022 }
1023
1024 std::vector<uint8_t> response;
1025 if (resData.size() > maxPostCodeLen)
1026 {
1027 startIndex = resData.size() - maxPostCodeLen;
1028 }
1029
1030 response.assign(resData.begin() + startIndex, resData.end());
1031
1032 return ipmi::responseSuccess(response);
1033}
1034
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001035//----------------------------------------------------------------------
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001036// Set Boot Order (CMD_OEM_SET_BOOT_ORDER)
1037//----------------------------------------------------------------------
Jayashree-Df0cf6652020-11-30 11:03:30 +05301038ipmi::RspType<std::vector<uint8_t>>
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001039 ipmiOemSetBootOrder(ipmi::Context::ptr ctx, std::vector<uint8_t> bootSeq)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001040{
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001041 size_t len = bootSeq.size();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001042
1043 if (len != SIZE_BOOT_ORDER)
1044 {
1045 phosphor::logging::log<phosphor::logging::level::ERR>(
1046 "Invalid Boot order length received");
Jayashree-Df0cf6652020-11-30 11:03:30 +05301047 return ipmi::responseReqDataLenInvalid();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001048 }
1049
Jayashree Dhanapal4ec80562022-06-28 15:41:47 +05301050 std::optional<size_t> hostId = findHost(ctx->hostIdx);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001051
Jayashree-Df0cf6652020-11-30 11:03:30 +05301052 if (!hostId)
1053 {
1054 phosphor::logging::log<phosphor::logging::level::ERR>(
1055 "Invalid Host Id received");
1056 return ipmi::responseInvalidCommand();
1057 }
1058 auto [bootObjPath, hostName] = ipmi::boot::objPath(*hostId);
1059
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001060 ipmi::boot::setBootOrder(bootObjPath, bootSeq, hostName);
Jayashree-Df0cf6652020-11-30 11:03:30 +05301061
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001062 return ipmi::responseSuccess(bootSeq);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001063}
1064
1065//----------------------------------------------------------------------
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001066// Get Boot Order (CMD_OEM_GET_BOOT_ORDER)
1067//----------------------------------------------------------------------
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001068ipmi::RspType<std::vector<uint8_t>> ipmiOemGetBootOrder(ipmi::Context::ptr ctx)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001069{
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001070 std::vector<uint8_t> bootSeq;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001071
Jayashree Dhanapal4ec80562022-06-28 15:41:47 +05301072 std::optional<size_t> hostId = findHost(ctx->hostIdx);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001073
Jayashree-Df0cf6652020-11-30 11:03:30 +05301074 if (!hostId)
1075 {
1076 phosphor::logging::log<phosphor::logging::level::ERR>(
1077 "Invalid Host Id received");
1078 return ipmi::responseInvalidCommand();
1079 }
1080 auto [bootObjPath, hostName] = ipmi::boot::objPath(*hostId);
1081
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001082 ipmi::boot::getBootOrder(bootObjPath, bootSeq, hostName);
Jayashree-Df0cf6652020-11-30 11:03:30 +05301083
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001084 return ipmi::responseSuccess(bootSeq);
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001085}
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001086// Set Machine Config Info (CMD_OEM_SET_MACHINE_CONFIG_INFO)
1087//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001088ipmi_ret_t ipmiOemSetMachineCfgInfo(ipmi_netfn_t, ipmi_cmd_t,
1089 ipmi_request_t request, ipmi_response_t,
1090 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001091{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001092 machineConfigInfo_t* req = reinterpret_cast<machineConfigInfo_t*>(request);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001093 uint8_t len = *data_len;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001094
1095 *data_len = 0;
1096
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001097 if (len < sizeof(machineConfigInfo_t))
1098 {
1099 phosphor::logging::log<phosphor::logging::level::ERR>(
1100 "Invalid machine configuration length received");
1101 return IPMI_CC_REQ_DATA_LEN_INVALID;
1102 }
1103
Vijay Khemka63c99be2020-05-27 19:14:35 -07001104 if (req->chassis_type >= sizeof(chassisType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001105 oemData[KEY_MC_CONFIG][KEY_MC_CHAS_TYPE] = "UNKNOWN";
1106 else
1107 oemData[KEY_MC_CONFIG][KEY_MC_CHAS_TYPE] =
1108 chassisType[req->chassis_type];
1109
Vijay Khemka63c99be2020-05-27 19:14:35 -07001110 if (req->mb_type >= sizeof(mbType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001111 oemData[KEY_MC_CONFIG][KEY_MC_MB_TYPE] = "UNKNOWN";
1112 else
1113 oemData[KEY_MC_CONFIG][KEY_MC_MB_TYPE] = mbType[req->mb_type];
1114
1115 oemData[KEY_MC_CONFIG][KEY_MC_PROC_CNT] = req->proc_cnt;
1116 oemData[KEY_MC_CONFIG][KEY_MC_MEM_CNT] = req->mem_cnt;
1117 oemData[KEY_MC_CONFIG][KEY_MC_HDD35_CNT] = req->hdd35_cnt;
1118 oemData[KEY_MC_CONFIG][KEY_MC_HDD25_CNT] = req->hdd25_cnt;
1119
Vijay Khemka63c99be2020-05-27 19:14:35 -07001120 if (req->riser_type >= sizeof(riserType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001121 oemData[KEY_MC_CONFIG][KEY_MC_RSR_TYPE] = "UNKNOWN";
1122 else
1123 oemData[KEY_MC_CONFIG][KEY_MC_RSR_TYPE] = riserType[req->riser_type];
1124
1125 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC] = {};
1126 int i = 0;
1127 if (req->pcie_card_loc & BIT_0)
1128 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT1";
1129 if (req->pcie_card_loc & BIT_1)
1130 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT2";
1131 if (req->pcie_card_loc & BIT_2)
1132 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT3";
1133 if (req->pcie_card_loc & BIT_3)
1134 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT4";
1135
Vijay Khemka63c99be2020-05-27 19:14:35 -07001136 if (req->slot1_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001137 oemData[KEY_MC_CONFIG][KEY_MC_SLOT1_TYPE] = "UNKNOWN";
1138 else
1139 oemData[KEY_MC_CONFIG][KEY_MC_SLOT1_TYPE] =
1140 pcieType[req->slot1_pcie_type];
1141
Vijay Khemka63c99be2020-05-27 19:14:35 -07001142 if (req->slot2_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001143 oemData[KEY_MC_CONFIG][KEY_MC_SLOT2_TYPE] = "UNKNOWN";
1144 else
1145 oemData[KEY_MC_CONFIG][KEY_MC_SLOT2_TYPE] =
1146 pcieType[req->slot2_pcie_type];
1147
Vijay Khemka63c99be2020-05-27 19:14:35 -07001148 if (req->slot3_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001149 oemData[KEY_MC_CONFIG][KEY_MC_SLOT3_TYPE] = "UNKNOWN";
1150 else
1151 oemData[KEY_MC_CONFIG][KEY_MC_SLOT3_TYPE] =
1152 pcieType[req->slot3_pcie_type];
1153
Vijay Khemka63c99be2020-05-27 19:14:35 -07001154 if (req->slot4_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001155 oemData[KEY_MC_CONFIG][KEY_MC_SLOT4_TYPE] = "UNKNOWN";
1156 else
1157 oemData[KEY_MC_CONFIG][KEY_MC_SLOT4_TYPE] =
1158 pcieType[req->slot4_pcie_type];
1159
1160 oemData[KEY_MC_CONFIG][KEY_MC_AEP_CNT] = req->aep_mem_cnt;
1161
1162 flushOemData();
1163
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001164 return IPMI_CC_OK;
1165}
1166
1167//----------------------------------------------------------------------
1168// Set POST start (CMD_OEM_SET_POST_START)
1169//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001170ipmi_ret_t ipmiOemSetPostStart(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1171 ipmi_response_t, ipmi_data_len_t data_len,
1172 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001173{
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001174 phosphor::logging::log<phosphor::logging::level::INFO>("POST Start Event");
1175
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001176 /* Do nothing, return success */
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001177 *data_len = 0;
1178 return IPMI_CC_OK;
1179}
1180
1181//----------------------------------------------------------------------
1182// Set POST End (CMD_OEM_SET_POST_END)
1183//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001184ipmi_ret_t ipmiOemSetPostEnd(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1185 ipmi_response_t, ipmi_data_len_t data_len,
1186 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001187{
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001188 struct timespec ts;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001189
1190 phosphor::logging::log<phosphor::logging::level::INFO>("POST End Event");
1191
1192 *data_len = 0;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001193
1194 // Timestamp post end time.
1195 clock_gettime(CLOCK_REALTIME, &ts);
1196 oemData[KEY_TS_SLED] = ts.tv_sec;
1197 flushOemData();
1198
1199 // Sync time with system
1200 // TODO: Add code for syncing time
1201
1202 return IPMI_CC_OK;
1203}
1204
1205//----------------------------------------------------------------------
1206// Set PPIN Info (CMD_OEM_SET_PPIN_INFO)
1207//----------------------------------------------------------------------
1208// Inform BMC about PPIN data of 8 bytes for each CPU
1209//
1210// Request:
1211// Byte 1:8 – CPU0 PPIN data
1212// Optional:
1213// Byte 9:16 – CPU1 PPIN data
1214//
1215// Response:
1216// Byte 1 – Completion Code
Willy Tue39f9392022-06-15 13:24:20 -07001217ipmi_ret_t ipmiOemSetPPINInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1218 ipmi_response_t, ipmi_data_len_t data_len,
1219 ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001220{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001221 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001222 std::string ppinStr;
1223 int len;
1224
1225 if (*data_len > SIZE_CPU_PPIN * 2)
1226 len = SIZE_CPU_PPIN * 2;
1227 else
1228 len = *data_len;
1229 *data_len = 0;
1230
1231 ppinStr = bytesToStr(req, len);
1232 oemData[KEY_PPIN_INFO] = ppinStr.c_str();
1233 flushOemData();
1234
1235 return IPMI_CC_OK;
1236}
1237
1238//----------------------------------------------------------------------
1239// Set ADR Trigger (CMD_OEM_SET_ADR_TRIGGER)
1240//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001241ipmi_ret_t ipmiOemSetAdrTrigger(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1242 ipmi_response_t, ipmi_data_len_t data_len,
1243 ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001244{
1245 /* Do nothing, return success */
1246 *data_len = 0;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001247 return IPMI_CC_OK;
1248}
1249
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001250// Helper function to set guid at offset in EEPROM
Willy Tue39f9392022-06-15 13:24:20 -07001251[[maybe_unused]] static int setGUID(off_t offset, uint8_t* guid)
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001252{
1253 int fd = -1;
1254 ssize_t len;
1255 int ret = 0;
cchouxb2ae88b2023-09-13 00:35:36 +08001256 std::string eepromPath = FRU_EEPROM;
1257
1258 // find the eeprom path of MB FRU
1259 auto device = getMbFruDevice();
1260 if (device)
1261 {
1262 auto [bus, address] = *device;
1263 std::stringstream ss;
1264 ss << "/sys/bus/i2c/devices/" << static_cast<int>(bus) << "-"
1265 << std::setw(4) << std::setfill('0') << std::hex
1266 << static_cast<int>(address) << "/eeprom";
1267 eepromPath = ss.str();
1268 }
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001269
1270 errno = 0;
1271
1272 // Check if file is present
cchouxb2ae88b2023-09-13 00:35:36 +08001273 if (access(eepromPath.c_str(), F_OK) == -1)
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001274 {
cchouxb2ae88b2023-09-13 00:35:36 +08001275 std::cerr << "Unable to access: " << eepromPath << std::endl;
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001276 return errno;
1277 }
1278
1279 // Open the file
cchouxb2ae88b2023-09-13 00:35:36 +08001280 fd = open(eepromPath.c_str(), O_WRONLY);
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001281 if (fd == -1)
1282 {
cchouxb2ae88b2023-09-13 00:35:36 +08001283 std::cerr << "Unable to open: " << eepromPath << std::endl;
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001284 return errno;
1285 }
1286
1287 // seek to the offset
1288 lseek(fd, offset, SEEK_SET);
1289
1290 // Write bytes to location
1291 len = write(fd, guid, GUID_SIZE);
1292 if (len != GUID_SIZE)
1293 {
1294 phosphor::logging::log<phosphor::logging::level::ERR>(
1295 "GUID write data to EEPROM failed");
1296 ret = errno;
1297 }
1298
1299 close(fd);
1300 return ret;
1301}
1302
1303//----------------------------------------------------------------------
1304// Set System GUID (CMD_OEM_SET_SYSTEM_GUID)
1305//----------------------------------------------------------------------
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05301306#if BIC_ENABLED
Bonnie Lo3f671272022-10-12 15:46:45 +08001307ipmi::RspType<> ipmiOemSetSystemGuid(ipmi::Context::ptr ctx,
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05301308 std::vector<uint8_t> reqData)
1309{
1310 std::vector<uint8_t> respData;
1311
1312 if (reqData.size() != GUID_SIZE) // 16bytes
1313 {
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05301314 return ipmi::responseReqDataLenInvalid();
1315 }
1316
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05301317 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
1318
1319 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, reqData, respData))
1320 return ipmi::responseUnspecifiedError();
1321
1322 return ipmi::responseSuccess();
1323}
1324
1325#else
Potin Laid5353ca2022-08-11 04:52:11 +00001326ipmi_ret_t ipmiOemSetSystemGuid(ipmi_netfn_t, ipmi_cmd_t,
1327 ipmi_request_t request, ipmi_response_t,
1328 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001329{
1330 uint8_t* req = reinterpret_cast<uint8_t*>(request);
1331
1332 if (*data_len != GUID_SIZE) // 16bytes
1333 {
1334 *data_len = 0;
1335 return IPMI_CC_REQ_DATA_LEN_INVALID;
1336 }
1337
1338 *data_len = 0;
1339
1340 if (setGUID(OFFSET_SYS_GUID, req))
1341 {
1342 return IPMI_CC_UNSPECIFIED_ERROR;
1343 }
1344 return IPMI_CC_OK;
1345}
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05301346#endif
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001347
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001348//----------------------------------------------------------------------
1349// Set Bios Flash Info (CMD_OEM_SET_BIOS_FLASH_INFO)
1350//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001351ipmi_ret_t ipmiOemSetBiosFlashInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1352 ipmi_response_t, ipmi_data_len_t data_len,
1353 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001354{
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001355 /* Do nothing, return success */
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001356 *data_len = 0;
1357 return IPMI_CC_OK;
1358}
1359
1360//----------------------------------------------------------------------
1361// Set PPR (CMD_OEM_SET_PPR)
1362//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001363ipmi_ret_t ipmiOemSetPpr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1364 ipmi_response_t, ipmi_data_len_t data_len,
1365 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001366{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001367 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001368 uint8_t pprCnt, pprAct, pprIndex;
1369 uint8_t selParam = req[0];
1370 uint8_t len = *data_len;
1371 std::stringstream ss;
1372 std::string str;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001373
1374 *data_len = 0;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001375
1376 switch (selParam)
1377 {
1378 case PPR_ACTION:
1379 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) ==
1380 oemData[KEY_PPR].end())
1381 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1382
1383 pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1384 if (pprCnt == 0)
1385 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1386
1387 pprAct = req[1];
1388 /* Check if ppr is enabled or disabled */
1389 if (!(pprAct & 0x80))
1390 pprAct = 0;
1391
1392 oemData[KEY_PPR][KEY_PPR_ACTION] = pprAct;
1393 break;
1394 case PPR_ROW_COUNT:
1395 if (req[1] > 100)
1396 return IPMI_CC_PARM_OUT_OF_RANGE;
1397
1398 oemData[KEY_PPR][KEY_PPR_ROW_COUNT] = req[1];
1399 break;
1400 case PPR_ROW_ADDR:
1401 pprIndex = req[1];
1402 if (pprIndex > 100)
1403 return IPMI_CC_PARM_OUT_OF_RANGE;
1404
1405 if (len < PPR_ROW_ADDR_LEN + 1)
1406 {
1407 phosphor::logging::log<phosphor::logging::level::ERR>(
1408 "Invalid PPR Row Address length received");
1409 return IPMI_CC_REQ_DATA_LEN_INVALID;
1410 }
1411
1412 ss << std::hex;
1413 ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1414
1415 oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex;
1416
1417 str = bytesToStr(&req[1], PPR_ROW_ADDR_LEN);
1418 oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR] = str.c_str();
1419 break;
1420 case PPR_HISTORY_DATA:
1421 pprIndex = req[1];
1422 if (pprIndex > 100)
1423 return IPMI_CC_PARM_OUT_OF_RANGE;
1424
1425 if (len < PPR_HST_DATA_LEN + 1)
1426 {
1427 phosphor::logging::log<phosphor::logging::level::ERR>(
1428 "Invalid PPR history data length received");
1429 return IPMI_CC_REQ_DATA_LEN_INVALID;
1430 }
1431
1432 ss << std::hex;
1433 ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1434
1435 oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex;
1436
1437 str = bytesToStr(&req[1], PPR_HST_DATA_LEN);
1438 oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA] = str.c_str();
1439 break;
1440 default:
1441 return IPMI_CC_PARM_OUT_OF_RANGE;
1442 break;
1443 }
1444
1445 flushOemData();
1446
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001447 return IPMI_CC_OK;
1448}
1449
1450//----------------------------------------------------------------------
1451// Get PPR (CMD_OEM_GET_PPR)
1452//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001453ipmi_ret_t ipmiOemGetPpr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1454 ipmi_response_t response, ipmi_data_len_t data_len,
1455 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001456{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001457 uint8_t* req = reinterpret_cast<uint8_t*>(request);
1458 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001459 uint8_t pprCnt, pprIndex;
1460 uint8_t selParam = req[0];
1461 std::stringstream ss;
1462 std::string str;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001463
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001464 /* Any failure will return zero length data */
1465 *data_len = 0;
1466
1467 switch (selParam)
1468 {
1469 case PPR_ACTION:
1470 res[0] = 0;
1471 *data_len = 1;
1472
1473 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) !=
1474 oemData[KEY_PPR].end())
1475 {
1476 pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1477 if (pprCnt != 0)
1478 {
1479 if (oemData[KEY_PPR].find(KEY_PPR_ACTION) !=
1480 oemData[KEY_PPR].end())
1481 {
1482 res[0] = oemData[KEY_PPR][KEY_PPR_ACTION];
1483 }
1484 }
1485 }
1486 break;
1487 case PPR_ROW_COUNT:
1488 res[0] = 0;
1489 *data_len = 1;
1490 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) !=
1491 oemData[KEY_PPR].end())
1492 res[0] = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1493 break;
1494 case PPR_ROW_ADDR:
1495 pprIndex = req[1];
1496 if (pprIndex > 100)
1497 return IPMI_CC_PARM_OUT_OF_RANGE;
1498
1499 ss << std::hex;
1500 ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1501
1502 if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end())
1503 return IPMI_CC_PARM_OUT_OF_RANGE;
1504
1505 if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_ROW_ADDR) ==
1506 oemData[KEY_PPR][ss.str()].end())
1507 return IPMI_CC_PARM_OUT_OF_RANGE;
1508
1509 str = oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR];
1510 *data_len = strToBytes(str, res);
1511 break;
1512 case PPR_HISTORY_DATA:
1513 pprIndex = req[1];
1514 if (pprIndex > 100)
1515 return IPMI_CC_PARM_OUT_OF_RANGE;
1516
1517 ss << std::hex;
1518 ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1519
1520 if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end())
1521 return IPMI_CC_PARM_OUT_OF_RANGE;
1522
1523 if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_HST_DATA) ==
1524 oemData[KEY_PPR][ss.str()].end())
1525 return IPMI_CC_PARM_OUT_OF_RANGE;
1526
1527 str = oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA];
1528 *data_len = strToBytes(str, res);
1529 break;
1530 default:
1531 return IPMI_CC_PARM_OUT_OF_RANGE;
1532 break;
1533 }
1534
1535 return IPMI_CC_OK;
1536}
1537
1538/* FB OEM QC Commands */
1539
1540//----------------------------------------------------------------------
1541// Set Proc Info (CMD_OEM_Q_SET_PROC_INFO)
1542//----------------------------------------------------------------------
1543//"Request:
1544// Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first
1545// Byte 4 – Processor Index, 0 base
1546// Byte 5 – Parameter Selector
1547// Byte 6..N – Configuration parameter data (see below for Parameters
1548// of Processor Information)
1549// Response:
1550// Byte 1 – Completion code
1551//
1552// Parameter#1: (Processor Product Name)
1553//
1554// Byte 1..48 –Product name(ASCII code)
1555// Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz
1556//
1557// Param#2: Processor Basic Information
1558// Byte 1 – Core Number
1559// Byte 2 – Thread Number (LSB)
1560// Byte 3 – Thread Number (MSB)
1561// Byte 4 – Processor frequency in MHz (LSB)
1562// Byte 5 – Processor frequency in MHz (MSB)
1563// Byte 6..7 – Revision
1564//
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301565
Patrick Williams010dee02024-08-16 15:19:44 -04001566ipmi::RspType<> ipmiOemQSetProcInfo(
1567 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t procIndex,
1568 uint8_t paramSel, std::vector<uint8_t> request)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001569{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001570 uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001571 std::stringstream ss;
1572 std::string str;
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301573 uint8_t len = request.size();
1574 auto hostId = findHost(ctx->hostIdx);
1575 if (!hostId)
1576 {
1577 phosphor::logging::log<phosphor::logging::level::ERR>(
1578 "Invalid Host Id received");
1579 return ipmi::responseInvalidCommand();
1580 }
1581 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(*hostId);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001582 /* check for requested data params */
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301583 if (len < 5 || paramSel < 1 || paramSel >= numParam)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001584 {
1585 phosphor::logging::log<phosphor::logging::level::ERR>(
1586 "Invalid parameter received");
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301587 return ipmi::responseParmOutOfRange();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001588 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001589 ss << std::hex;
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301590 ss << std::setw(2) << std::setfill('0') << (int)procIndex;
1591 oemData[procInfo][ss.str()][KEY_PROC_INDEX] = procIndex;
1592 str = bytesToStr(request.data(), len);
1593 oemData[procInfo][ss.str()][cpuInfoKey[paramSel]] = str.c_str();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001594 flushOemData();
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301595 return ipmi::responseSuccess();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001596}
1597
1598//----------------------------------------------------------------------
1599// Get Proc Info (CMD_OEM_Q_GET_PROC_INFO)
1600//----------------------------------------------------------------------
1601// Request:
1602// Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first
1603// Byte 4 – Processor Index, 0 base
1604// Byte 5 – Parameter Selector
1605// Response:
1606// Byte 1 – Completion code
1607// Byte 2..N – Configuration Parameter Data (see below for Parameters
1608// of Processor Information)
1609//
1610// Parameter#1: (Processor Product Name)
1611//
1612// Byte 1..48 –Product name(ASCII code)
1613// Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz
1614//
1615// Param#2: Processor Basic Information
1616// Byte 1 – Core Number
1617// Byte 2 – Thread Number (LSB)
1618// Byte 3 – Thread Number (MSB)
1619// Byte 4 – Processor frequency in MHz (LSB)
1620// Byte 5 – Processor frequency in MHz (MSB)
1621// Byte 6..7 – Revision
1622//
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301623
1624ipmi::RspType<std::vector<uint8_t>>
1625 ipmiOemQGetProcInfo(ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t,
1626 uint8_t procIndex, uint8_t paramSel)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001627{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001628 uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001629 std::stringstream ss;
1630 std::string str;
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301631 uint8_t res[MAX_BUF];
1632 auto hostId = findHost(ctx->hostIdx);
1633 if (!hostId)
1634 {
1635 phosphor::logging::log<phosphor::logging::level::ERR>(
1636 "Invalid Host Id received");
1637 return ipmi::responseInvalidCommand();
1638 }
1639 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(*hostId);
1640 if (paramSel < 1 || paramSel >= numParam)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001641 {
1642 phosphor::logging::log<phosphor::logging::level::ERR>(
1643 "Invalid parameter received");
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301644 return ipmi::responseParmOutOfRange();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001645 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001646 ss << std::hex;
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301647 ss << std::setw(2) << std::setfill('0') << (int)procIndex;
1648 if (oemData[procInfo].find(ss.str()) == oemData[procInfo].end())
1649 return ipmi::responseCommandNotAvailable();
1650 if (oemData[procInfo][ss.str()].find(cpuInfoKey[paramSel]) ==
1651 oemData[procInfo][ss.str()].end())
1652 return ipmi::responseCommandNotAvailable();
1653 str = oemData[procInfo][ss.str()][cpuInfoKey[paramSel]];
1654 int dataLen = strToBytes(str, res);
1655 std::vector<uint8_t> response(&res[0], &res[dataLen]);
1656 return ipmi::responseSuccess(response);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001657}
1658
1659//----------------------------------------------------------------------
1660// Set Dimm Info (CMD_OEM_Q_SET_DIMM_INFO)
1661//----------------------------------------------------------------------
1662// Request:
1663// Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first
1664// Byte 4 – DIMM Index, 0 base
1665// Byte 5 – Parameter Selector
1666// Byte 6..N – Configuration parameter data (see below for Parameters
1667// of DIMM Information)
1668// Response:
1669// Byte 1 – Completion code
1670//
1671// Param#1 (DIMM Location):
1672// Byte 1 – DIMM Present
1673// Byte 1 – DIMM Present
1674// 01h – Present
1675// FFh – Not Present
1676// Byte 2 – Node Number, 0 base
1677// Byte 3 – Channel Number , 0 base
1678// Byte 4 – DIMM Number , 0 base
1679//
1680// Param#2 (DIMM Type):
1681// Byte 1 – DIMM Type
1682// Bit [7:6]
1683// For DDR3
1684// 00 – Normal Voltage (1.5V)
1685// 01 – Ultra Low Voltage (1.25V)
1686// 10 – Low Voltage (1.35V)
1687// 11 – Reserved
1688// For DDR4
1689// 00 – Reserved
1690// 01 – Reserved
1691// 10 – Reserved
1692// 11 – Normal Voltage (1.2V)
1693// Bit [5:0]
1694// 0x00 – SDRAM
1695// 0x01 – DDR-1 RAM
1696// 0x02 – Rambus
1697// 0x03 – DDR-2 RAM
1698// 0x04 – FBDIMM
1699// 0x05 – DDR-3 RAM
1700// 0x06 – DDR-4 RAM
1701//
1702// Param#3 (DIMM Speed):
1703// Byte 1..2 – DIMM speed in MHz, LSB
1704// Byte 3..6 – DIMM size in Mbytes, LSB
1705//
1706// Param#4 (Module Part Number):
1707// Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C)
1708//
1709// Param#5 (Module Serial Number):
1710// Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C)
1711//
1712// Param#6 (Module Manufacturer ID):
1713// Byte 1 - Module Manufacturer ID, LSB
1714// Byte 2 - Module Manufacturer ID, MSB
1715//
Patrick Williams010dee02024-08-16 15:19:44 -04001716ipmi::RspType<> ipmiOemQSetDimmInfo(
1717 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t dimmIndex,
1718 uint8_t paramSel, std::vector<uint8_t> request)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001719{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001720 uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001721 std::stringstream ss;
1722 std::string str;
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301723 uint8_t len = request.size();
1724 std::string dimmType;
1725 readDimmType(dimmType, dimmIndex);
Patrick Williams6d9e9a72022-07-18 10:30:50 -05001726 auto hostId = findHost(ctx->hostIdx);
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301727 if (!hostId)
1728 {
1729 phosphor::logging::log<phosphor::logging::level::ERR>(
1730 "Invalid Host Id received");
1731 return ipmi::responseInvalidCommand();
1732 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001733
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301734 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(*hostId);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001735
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301736 if (len < 3 || paramSel < 1 || paramSel >= numParam)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001737 {
1738 phosphor::logging::log<phosphor::logging::level::ERR>(
1739 "Invalid parameter received");
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301740 return ipmi::responseParmOutOfRange();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001741 }
1742
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001743 ss << std::hex;
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301744 ss << (int)dimmIndex;
1745 oemData[dimmInfo][ss.str()][KEY_DIMM_INDEX] = dimmIndex;
1746 oemData[dimmInfo][ss.str()][KEY_DIMM_TYPE] = dimmType;
1747 str = bytesToStr(request.data(), len);
1748 oemData[dimmInfo][ss.str()][dimmInfoKey[paramSel]] = str.c_str();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001749 flushOemData();
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301750 return ipmi::responseSuccess();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001751}
1752
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001753// Get Dimm Info (CMD_OEM_Q_GET_DIMM_INFO)
1754//----------------------------------------------------------------------
1755// Request:
1756// Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first
1757// Byte 4 – DIMM Index, 0 base
1758// Byte 5 – Parameter Selector
1759// Byte 6..N – Configuration parameter data (see below for Parameters
1760// of DIMM Information)
1761// Response:
1762// Byte 1 – Completion code
1763// Byte 2..N – Configuration Parameter Data (see Table_1213h Parameters
1764// of DIMM Information)
1765//
1766// Param#1 (DIMM Location):
1767// Byte 1 – DIMM Present
1768// Byte 1 – DIMM Present
1769// 01h – Present
1770// FFh – Not Present
1771// Byte 2 – Node Number, 0 base
1772// Byte 3 – Channel Number , 0 base
1773// Byte 4 – DIMM Number , 0 base
1774//
1775// Param#2 (DIMM Type):
1776// Byte 1 – DIMM Type
1777// Bit [7:6]
1778// For DDR3
1779// 00 – Normal Voltage (1.5V)
1780// 01 – Ultra Low Voltage (1.25V)
1781// 10 – Low Voltage (1.35V)
1782// 11 – Reserved
1783// For DDR4
1784// 00 – Reserved
1785// 01 – Reserved
1786// 10 – Reserved
1787// 11 – Normal Voltage (1.2V)
1788// Bit [5:0]
1789// 0x00 – SDRAM
1790// 0x01 – DDR-1 RAM
1791// 0x02 – Rambus
1792// 0x03 – DDR-2 RAM
1793// 0x04 – FBDIMM
1794// 0x05 – DDR-3 RAM
1795// 0x06 – DDR-4 RAM
1796//
1797// Param#3 (DIMM Speed):
1798// Byte 1..2 – DIMM speed in MHz, LSB
1799// Byte 3..6 – DIMM size in Mbytes, LSB
1800//
1801// Param#4 (Module Part Number):
1802// Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C)
1803//
1804// Param#5 (Module Serial Number):
1805// Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C)
1806//
1807// Param#6 (Module Manufacturer ID):
1808// Byte 1 - Module Manufacturer ID, LSB
1809// Byte 2 - Module Manufacturer ID, MSB
1810//
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301811ipmi::RspType<std::vector<uint8_t>>
1812 ipmiOemQGetDimmInfo(ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t,
1813 uint8_t dimmIndex, uint8_t paramSel)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001814{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001815 uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*);
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301816 uint8_t res[MAX_BUF];
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001817 std::stringstream ss;
1818 std::string str;
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301819 std::string dimmType;
1820 readDimmType(dimmType, dimmIndex);
Patrick Williams6d9e9a72022-07-18 10:30:50 -05001821 auto hostId = findHost(ctx->hostIdx);
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301822 if (!hostId)
1823 {
1824 phosphor::logging::log<phosphor::logging::level::ERR>(
1825 "Invalid Host Id received");
1826 return ipmi::responseInvalidCommand();
1827 }
1828 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(*hostId);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001829
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301830 if (paramSel < 1 || paramSel >= numParam)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001831 {
1832 phosphor::logging::log<phosphor::logging::level::ERR>(
1833 "Invalid parameter received");
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301834 return ipmi::responseParmOutOfRange();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001835 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001836 ss << std::hex;
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301837 ss << (int)dimmIndex;
1838 oemData[dimmInfo][ss.str()][KEY_DIMM_TYPE] = dimmType;
1839 if (oemData[dimmInfo].find(ss.str()) == oemData[dimmInfo].end())
1840 return ipmi::responseCommandNotAvailable();
1841 if (oemData[dimmInfo][ss.str()].find(dimmInfoKey[paramSel]) ==
1842 oemData[dimmInfo][ss.str()].end())
1843 return ipmi::responseCommandNotAvailable();
1844 str = oemData[dimmInfo][ss.str()][dimmInfoKey[paramSel]];
1845 int data_length = strToBytes(str, res);
1846 std::vector<uint8_t> response(&res[0], &res[data_length]);
1847 return ipmi::responseSuccess(response);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001848}
1849
1850//----------------------------------------------------------------------
1851// Set Drive Info (CMD_OEM_Q_SET_DRIVE_INFO)
1852//----------------------------------------------------------------------
1853// BIOS issue this command to provide HDD information to BMC.
1854//
1855// BIOS just can get information by standard ATA / SMART command for
1856// OB SATA controller.
1857// BIOS can get
1858// 1. Serial Number
1859// 2. Model Name
1860// 3. HDD FW Version
1861// 4. HDD Capacity
1862// 5. HDD WWN
1863//
1864// Use Get HDD info Param #5 to know the MAX HDD info index.
1865//
1866// Request:
1867// Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first
1868// Byte 4 –
1869// [7:4] Reserved
1870// [3:0] HDD Controller Type
1871// 0x00 – BIOS
1872// 0x01 – Expander
1873// 0x02 – LSI
1874// Byte 5 – HDD Info Index, 0 base
1875// Byte 6 – Parameter Selector
1876// Byte 7..N – Configuration parameter data (see Table_1415h Parameters of HDD
1877// Information)
1878//
1879// Response:
1880// Byte 1 – Completion Code
1881//
1882// Param#0 (HDD Location):
1883// Byte 1 – Controller
1884// [7:3] Device Number
1885// [2:0] Function Number
1886// For Intel C610 series (Wellsburg)
1887// D31:F2 (0xFA) – SATA control 1
1888// D31:F5 (0xFD) – SATA control 2
1889// D17:F4 (0x8C) – sSata control
1890// Byte 2 – Port Number
1891// Byte 3 – Location (0xFF: No HDD Present)
1892// BIOS default set Byte 3 to 0xFF, if No HDD Present. And then skip send param
1893// #1~4, #6, #7 to BMC (still send param #5) BIOS default set Byte 3 to 0, if
1894// the HDD present. BMC or other people who know the HDD location has
1895// responsibility for update Location info
1896//
1897// Param#1 (Serial Number):
1898// Bytes 1..33: HDD Serial Number
1899//
1900// Param#2 (Model Name):
1901// Byte 1..33 – HDD Model Name
1902//
1903// Param#3 (HDD FW Version):
1904// Byte 1..17 –HDD FW version
1905//
1906// Param#4 (Capacity):
1907// Byte 1..4 –HDD Block Size, LSB
1908// Byte 5..12 - HDD Block Number, LSB
1909// HDD Capacity = HDD Block size * HDD BLock number (Unit Byte)
1910//
1911// Param#5 (Max HDD Quantity):
1912// Byte 1 - Max HDD Quantity
1913// Max supported port numbers in this PCH
1914//
1915// Param#6 (HDD Type)
1916// Byte 1 – HDD Type
1917// 0h – Reserved
1918// 1h – SAS
1919// 2h – SATA
1920// 3h – PCIE SSD (NVME)
1921//
1922// Param#7 (HDD WWN)
1923// Data 1...8: HDD World Wide Name, LSB
1924//
Willy Tue39f9392022-06-15 13:24:20 -07001925ipmi_ret_t ipmiOemQSetDriveInfo(ipmi_netfn_t, ipmi_cmd_t,
1926 ipmi_request_t request, ipmi_response_t,
1927 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001928{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001929 qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request);
1930 uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001931 uint8_t ctrlType = req->hddCtrlType & 0x0f;
1932 std::stringstream ss;
1933 std::string str;
1934 uint8_t len = *data_len;
1935
1936 *data_len = 0;
1937
1938 /* check for requested data params */
1939 if (len < 6 || req->paramSel < 1 || req->paramSel >= numParam ||
1940 ctrlType > 2)
1941 {
1942 phosphor::logging::log<phosphor::logging::level::ERR>(
1943 "Invalid parameter received");
1944 return IPMI_CC_PARM_OUT_OF_RANGE;
1945 }
1946
1947 len = len - 6; // Get Actual data length
1948
1949 ss << std::hex;
1950 ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex;
1951 oemData[KEY_Q_DRIVE_INFO][KEY_HDD_CTRL_TYPE] = req->hddCtrlType;
1952 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()][KEY_HDD_INDEX] =
1953 req->hddIndex;
1954
1955 str = bytesToStr(req->data, len);
1956 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()]
1957 [driveInfoKey[req->paramSel]] = str.c_str();
1958 flushOemData();
1959
1960 return IPMI_CC_OK;
1961}
1962
1963//----------------------------------------------------------------------
1964// Get Drive Info (CMD_OEM_Q_GET_DRIVE_INFO)
1965//----------------------------------------------------------------------
1966// BMC needs to check HDD presented or not first. If NOT presented, return
1967// completion code 0xD5.
1968//
1969// Request:
1970// Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first
1971// Byte 4 –
1972//[7:4] Reserved
1973//[3:0] HDD Controller Type
1974// 0x00 – BIOS
1975// 0x01 – Expander
1976// 0x02 – LSI
1977// Byte 5 – HDD Index, 0 base
1978// Byte 6 – Parameter Selector (See Above Set HDD Information)
1979// Response:
1980// Byte 1 – Completion Code
1981// 0xD5 – Not support in current status (HDD Not Present)
1982// Byte 2..N – Configuration parameter data (see Table_1415h Parameters of HDD
1983// Information)
1984//
Patrick Williams010dee02024-08-16 15:19:44 -04001985ipmi_ret_t ipmiOemQGetDriveInfo(
1986 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
1987 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001988{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001989 qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request);
1990 uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*);
1991 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001992 uint8_t ctrlType = req->hddCtrlType & 0x0f;
1993 std::stringstream ss;
1994 std::string str;
1995
1996 *data_len = 0;
1997
1998 /* check for requested data params */
1999 if (req->paramSel < 1 || req->paramSel >= numParam || ctrlType > 2)
2000 {
2001 phosphor::logging::log<phosphor::logging::level::ERR>(
2002 "Invalid parameter received");
2003 return IPMI_CC_PARM_OUT_OF_RANGE;
2004 }
2005
2006 if (oemData[KEY_Q_DRIVE_INFO].find(ctrlTypeKey[ctrlType]) ==
2007 oemData[KEY_Q_DRIVE_INFO].end())
2008 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2009
2010 ss << std::hex;
2011 ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex;
2012
2013 if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]].find(ss.str()) ==
2014 oemData[KEY_Q_DRIVE_INFO].end())
2015 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2016
2017 if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()].find(
2018 dimmInfoKey[req->paramSel]) ==
2019 oemData[KEY_Q_DRIVE_INFO][ss.str()].end())
2020 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2021
2022 str = oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()]
2023 [dimmInfoKey[req->paramSel]];
2024 *data_len = strToBytes(str, res);
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002025
2026 return IPMI_CC_OK;
2027}
2028
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302029/* Helper function for sending DCMI commands to ME/BIC and
2030 * getting response back
2031 */
2032ipmi::RspType<std::vector<uint8_t>>
2033 sendDCMICmd([[maybe_unused]] ipmi::Context::ptr ctx,
2034 [[maybe_unused]] uint8_t cmd, std::vector<uint8_t>& cmdData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002035{
2036 std::vector<uint8_t> respData;
2037
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302038#if BIC_ENABLED
2039
2040 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
2041
2042 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, cmdData, respData))
2043 {
2044 return ipmi::responseUnspecifiedError();
2045 }
2046
2047#else
2048
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002049 /* Add group id as first byte to request for ME command */
2050 cmdData.insert(cmdData.begin(), groupDCMI);
2051
2052 if (sendMeCmd(ipmi::netFnGroup, cmd, cmdData, respData))
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302053 {
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002054 return ipmi::responseUnspecifiedError();
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302055 }
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002056
2057 /* Remove group id as first byte as it will be added by IPMID */
2058 respData.erase(respData.begin());
2059
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302060#endif
2061
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002062 return ipmi::responseSuccess(std::move(respData));
2063}
2064
2065/* DCMI Command handellers. */
2066
Patrick Williams010dee02024-08-16 15:19:44 -04002067ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMIGetPowerReading(
2068 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002069{
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302070 return sendDCMICmd(ctx, ipmi::dcmi::cmdGetPowerReading, reqData);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002071}
2072
Patrick Williams010dee02024-08-16 15:19:44 -04002073ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMIGetPowerLimit(
2074 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002075{
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302076 return sendDCMICmd(ctx, ipmi::dcmi::cmdGetPowerLimit, reqData);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002077}
2078
Patrick Williams010dee02024-08-16 15:19:44 -04002079ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMISetPowerLimit(
2080 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002081{
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302082 return sendDCMICmd(ctx, ipmi::dcmi::cmdSetPowerLimit, reqData);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002083}
2084
Patrick Williams010dee02024-08-16 15:19:44 -04002085ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMIApplyPowerLimit(
2086 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002087{
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302088 return sendDCMICmd(ctx, ipmi::dcmi::cmdActDeactivatePwrLimit, reqData);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002089}
2090
Cosmo Chou99d42b62024-08-15 10:42:47 +08002091// Https Boot related functions
Patrick Williams010dee02024-08-16 15:19:44 -04002092ipmi::RspType<std::vector<uint8_t>> ipmiOemGetHttpsData(
2093 [[maybe_unused]] ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Cosmo Chou99d42b62024-08-15 10:42:47 +08002094{
2095 if (reqData.size() < sizeof(HttpsDataReq))
2096 return ipmi::responseReqDataLenInvalid();
2097
2098 const auto* pReq = reinterpret_cast<const HttpsDataReq*>(reqData.data());
2099 std::error_code ec;
2100 auto fileSize = std::filesystem::file_size(certPath, ec);
2101 if (ec)
2102 return ipmi::responseUnspecifiedError();
2103
2104 if (pReq->offset >= fileSize)
2105 return ipmi::responseInvalidFieldRequest();
2106
2107 std::ifstream file(certPath, std::ios::binary);
2108 if (!file)
2109 return ipmi::responseUnspecifiedError();
2110
2111 auto readLen = std::min<uint16_t>(pReq->length, fileSize - pReq->offset);
2112 std::vector<uint8_t> resData(readLen + 1);
2113 resData[0] = readLen;
2114 file.seekg(pReq->offset);
2115 file.read(reinterpret_cast<char*>(resData.data() + 1), readLen);
2116
2117 return ipmi::responseSuccess(resData);
2118}
2119
Patrick Williams010dee02024-08-16 15:19:44 -04002120ipmi::RspType<std::vector<uint8_t>> ipmiOemGetHttpsAttr(
2121 [[maybe_unused]] ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Cosmo Chou99d42b62024-08-15 10:42:47 +08002122{
2123 if (reqData.size() < sizeof(HttpsBootAttr))
2124 return ipmi::responseReqDataLenInvalid();
2125
2126 std::vector<uint8_t> resData;
2127
2128 switch (static_cast<HttpsBootAttr>(reqData[0]))
2129 {
2130 case HttpsBootAttr::certSize:
2131 {
2132 std::error_code ec;
2133 auto fileSize = std::filesystem::file_size(certPath, ec);
2134 if (ec || fileSize > std::numeric_limits<uint16_t>::max())
2135 return ipmi::responseUnspecifiedError();
2136
2137 uint16_t size = static_cast<uint16_t>(fileSize);
2138 resData.resize(sizeof(uint16_t));
2139 std::memcpy(resData.data(), &size, sizeof(uint16_t));
2140 break;
2141 }
2142 case HttpsBootAttr::certCrc:
2143 {
2144 std::ifstream file(certPath, std::ios::binary);
2145 if (!file)
2146 return ipmi::responseUnspecifiedError();
2147
2148 boost::crc_32_type result;
2149 char data[1024];
2150 while (file.read(data, sizeof(data)))
2151 result.process_bytes(data, file.gcount());
2152 if (file.gcount() > 0)
2153 result.process_bytes(data, file.gcount());
2154
2155 uint32_t crc = result.checksum();
2156 resData.resize(sizeof(uint32_t));
2157 std::memcpy(resData.data(), &crc, sizeof(uint32_t));
2158 break;
2159 }
2160 default:
2161 return ipmi::responseInvalidFieldRequest();
2162 }
2163
2164 return ipmi::responseSuccess(resData);
2165}
2166
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002167// OEM Crashdump related functions
2168static ipmi_ret_t setDumpState(CrdState& currState, CrdState newState)
2169{
2170 switch (newState)
2171 {
2172 case CrdState::waitData:
2173 if (currState == CrdState::packing)
2174 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2175 break;
2176 case CrdState::packing:
2177 if (currState != CrdState::waitData)
2178 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2179 break;
2180 case CrdState::free:
2181 break;
2182 default:
2183 return IPMI_CC_UNSPECIFIED_ERROR;
2184 }
2185 currState = newState;
2186
2187 return IPMI_CC_OK;
2188}
2189
2190static ipmi_ret_t handleMcaBank(const CrashDumpHdr& hdr,
2191 std::span<const uint8_t> data,
2192 CrdState& currState, std::stringstream& ss)
2193{
2194 if (data.size() < sizeof(CrdMcaBank))
2195 return IPMI_CC_REQ_DATA_LEN_INVALID;
2196
2197 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2198 if (res)
2199 return res;
2200
2201 const auto* pBank = reinterpret_cast<const CrdMcaBank*>(data.data());
2202 ss << std::format(" Bank ID : 0x{:02X}, Core ID : 0x{:02X}\n",
2203 hdr.bankHdr.bankId, hdr.bankHdr.coreId);
2204 ss << std::format(" MCA_CTRL : 0x{:016X}\n", pBank->mcaCtrl);
2205 ss << std::format(" MCA_STATUS : 0x{:016X}\n", pBank->mcaSts);
2206 ss << std::format(" MCA_ADDR : 0x{:016X}\n", pBank->mcaAddr);
2207 ss << std::format(" MCA_MISC0 : 0x{:016X}\n", pBank->mcaMisc0);
2208 ss << std::format(" MCA_CTRL_MASK : 0x{:016X}\n", pBank->mcaCtrlMask);
2209 ss << std::format(" MCA_CONFIG : 0x{:016X}\n", pBank->mcaConfig);
2210 ss << std::format(" MCA_IPID : 0x{:016X}\n", pBank->mcaIpid);
2211 ss << std::format(" MCA_SYND : 0x{:016X}\n", pBank->mcaSynd);
2212 ss << std::format(" MCA_DESTAT : 0x{:016X}\n", pBank->mcaDestat);
2213 ss << std::format(" MCA_DEADDR : 0x{:016X}\n", pBank->mcaDeaddr);
2214 ss << std::format(" MCA_MISC1 : 0x{:016X}\n", pBank->mcaMisc1);
2215 ss << "\n";
2216
2217 return IPMI_CC_OK;
2218}
2219
2220template <typename T>
2221static ipmi_ret_t handleVirtualBank(std::span<const uint8_t> data,
2222 CrdState& currState, std::stringstream& ss)
2223{
2224 if (data.size() < sizeof(T))
2225 return IPMI_CC_REQ_DATA_LEN_INVALID;
2226
2227 const auto* pBank = reinterpret_cast<const T*>(data.data());
2228
2229 if (data.size() < sizeof(T) + sizeof(BankCorePair) * pBank->mcaCount)
2230 return IPMI_CC_REQ_DATA_LEN_INVALID;
2231
2232 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2233 if (res)
2234 return res;
2235
2236 ss << " Virtual Bank\n";
2237 ss << std::format(" S5_RESET_STATUS : 0x{:08X}\n", pBank->s5ResetSts);
2238 ss << std::format(" PM_BREAKEVENT : 0x{:08X}\n", pBank->breakevent);
2239 if constexpr (std::is_same_v<T, CrdVirtualBankV3>)
2240 {
2241 ss << std::format(" WARMCOLDRSTSTATUS : 0x{:08X}\n", pBank->rstSts);
2242 }
2243 ss << std::format(" PROCESSOR NUMBER : 0x{:04X}\n", pBank->procNum);
2244 ss << std::format(" APIC ID : 0x{:08X}\n", pBank->apicId);
2245 ss << std::format(" EAX : 0x{:08X}\n", pBank->eax);
2246 ss << std::format(" EBX : 0x{:08X}\n", pBank->ebx);
2247 ss << std::format(" ECX : 0x{:08X}\n", pBank->ecx);
2248 ss << std::format(" EDX : 0x{:08X}\n", pBank->edx);
2249 ss << " VALID LIST : ";
2250 for (size_t i = 0; i < pBank->mcaCount; i++)
2251 {
2252 ss << std::format("(0x{:02X},0x{:02X}) ", pBank->mcaList[i].bankId,
2253 pBank->mcaList[i].coreId);
2254 }
2255 ss << "\n\n";
2256
2257 return IPMI_CC_OK;
2258}
2259
2260static ipmi_ret_t handleCpuWdtBank(std::span<const uint8_t> data,
2261 CrdState& currState, std::stringstream& ss)
2262{
2263 if (data.size() < sizeof(CrdCpuWdtBank))
2264 return IPMI_CC_REQ_DATA_LEN_INVALID;
2265
2266 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2267 if (res)
2268 return res;
2269
2270 const auto* pBank = reinterpret_cast<const CrdCpuWdtBank*>(data.data());
2271 for (size_t i = 0; i < ccmNum; i++)
2272 {
2273 ss << std::format(" [CCM{}]\n", i);
2274 ss << std::format(" HwAssertStsHi : 0x{:08X}\n",
2275 pBank->hwAssertStsHi[i]);
2276 ss << std::format(" HwAssertStsLo : 0x{:08X}\n",
2277 pBank->hwAssertStsLo[i]);
2278 ss << std::format(" OrigWdtAddrLogHi : 0x{:08X}\n",
2279 pBank->origWdtAddrLogHi[i]);
2280 ss << std::format(" OrigWdtAddrLogLo : 0x{:08X}\n",
2281 pBank->origWdtAddrLogLo[i]);
2282 ss << std::format(" HwAssertMskHi : 0x{:08X}\n",
2283 pBank->hwAssertMskHi[i]);
2284 ss << std::format(" HwAssertMskLo : 0x{:08X}\n",
2285 pBank->hwAssertMskLo[i]);
2286 ss << std::format(" OrigWdtAddrLogStat : 0x{:08X}\n",
2287 pBank->origWdtAddrLogStat[i]);
2288 }
2289 ss << "\n";
2290
2291 return IPMI_CC_OK;
2292}
2293
2294template <size_t N>
Patrick Williams010dee02024-08-16 15:19:44 -04002295static ipmi_ret_t
2296 handleHwAssertBank(const char* name, std::span<const uint8_t> data,
2297 CrdState& currState, std::stringstream& ss)
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002298{
2299 if (data.size() < sizeof(CrdHwAssertBank<N>))
2300 return IPMI_CC_REQ_DATA_LEN_INVALID;
2301
2302 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2303 if (res)
2304 return res;
2305
2306 const CrdHwAssertBank<N>* pBank =
2307 reinterpret_cast<const CrdHwAssertBank<N>*>(data.data());
2308
2309 for (size_t i = 0; i < N; i++)
2310 {
2311 ss << std::format(" [{}{}]\n", name, i);
2312 ss << std::format(" HwAssertStsHi : 0x{:08X}\n",
2313 pBank->hwAssertStsHi[i]);
2314 ss << std::format(" HwAssertStsLo : 0x{:08X}\n",
2315 pBank->hwAssertStsLo[i]);
2316 ss << std::format(" HwAssertMskHi : 0x{:08X}\n",
2317 pBank->hwAssertMskHi[i]);
2318 ss << std::format(" HwAssertMskLo : 0x{:08X}\n",
2319 pBank->hwAssertMskLo[i]);
2320 }
2321 ss << "\n";
2322
2323 return IPMI_CC_OK;
2324}
2325
2326static ipmi_ret_t handlePcieAerBank(std::span<const uint8_t> data,
2327 CrdState& currState, std::stringstream& ss)
2328{
2329 if (data.size() < sizeof(CrdPcieAerBank))
2330 return IPMI_CC_REQ_DATA_LEN_INVALID;
2331
2332 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2333 if (res)
2334 return res;
2335
2336 const auto* pBank = reinterpret_cast<const CrdPcieAerBank*>(data.data());
2337 ss << std::format(" [Bus{} Dev{} Fun{}]\n", pBank->bus, pBank->dev,
2338 pBank->fun);
2339 ss << std::format(" Command : 0x{:04X}\n",
2340 pBank->cmd);
2341 ss << std::format(" Status : 0x{:04X}\n",
2342 pBank->sts);
2343 ss << std::format(" Slot : 0x{:04X}\n",
2344 pBank->slot);
2345 ss << std::format(" Secondary Bus : 0x{:02X}\n",
2346 pBank->secondBus);
2347 ss << std::format(" Vendor ID : 0x{:04X}\n",
2348 pBank->vendorId);
2349 ss << std::format(" Device ID : 0x{:04X}\n",
2350 pBank->devId);
2351 ss << std::format(" Class Code : 0x{:02X}{:04X}\n",
2352 pBank->classCodeHi, pBank->classCodeLo);
2353 ss << std::format(" Bridge: Secondary Status : 0x{:04X}\n",
2354 pBank->secondSts);
2355 ss << std::format(" Bridge: Control : 0x{:04X}\n",
2356 pBank->ctrl);
2357 ss << std::format(" Uncorrectable Error Status : 0x{:08X}\n",
2358 pBank->uncorrErrSts);
2359 ss << std::format(" Uncorrectable Error Mask : 0x{:08X}\n",
2360 pBank->uncorrErrMsk);
2361 ss << std::format(" Uncorrectable Error Severity : 0x{:08X}\n",
2362 pBank->uncorrErrSeverity);
2363 ss << std::format(" Correctable Error Status : 0x{:08X}\n",
2364 pBank->corrErrSts);
2365 ss << std::format(" Correctable Error Mask : 0x{:08X}\n",
2366 pBank->corrErrMsk);
2367 ss << std::format(" Header Log DW0 : 0x{:08X}\n",
2368 pBank->hdrLogDw0);
2369 ss << std::format(" Header Log DW1 : 0x{:08X}\n",
2370 pBank->hdrLogDw1);
2371 ss << std::format(" Header Log DW2 : 0x{:08X}\n",
2372 pBank->hdrLogDw2);
2373 ss << std::format(" Header Log DW3 : 0x{:08X}\n",
2374 pBank->hdrLogDw3);
2375 ss << std::format(" Root Error Status : 0x{:08X}\n",
2376 pBank->rootErrSts);
2377 ss << std::format(" Correctable Error Source ID : 0x{:04X}\n",
2378 pBank->corrErrSrcId);
2379 ss << std::format(" Error Source ID : 0x{:04X}\n",
2380 pBank->errSrcId);
2381 ss << std::format(" Lane Error Status : 0x{:08X}\n",
2382 pBank->laneErrSts);
2383 ss << "\n";
2384
2385 return IPMI_CC_OK;
2386}
2387
2388static ipmi_ret_t handleWdtRegBank(std::span<const uint8_t> data,
2389 CrdState& currState, std::stringstream& ss)
2390{
2391 if (data.size() < sizeof(CrdWdtRegBank))
2392 return IPMI_CC_REQ_DATA_LEN_INVALID;
2393
2394 const auto* pBank = reinterpret_cast<const CrdWdtRegBank*>(data.data());
2395 if (data.size() < sizeof(CrdWdtRegBank) + sizeof(uint32_t) * pBank->count)
2396 return IPMI_CC_REQ_DATA_LEN_INVALID;
2397
2398 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2399 if (res)
2400 return res;
2401
2402 ss << std::format(" [NBIO{}] {}\n", pBank->nbio, pBank->name);
2403 ss << std::format(" Address: 0x{:08X}\n", pBank->addr);
2404 ss << std::format(" Data Count: {}\n", pBank->count);
2405 ss << " Data:\n";
2406 for (size_t i = 0; i < pBank->count; i++)
2407 {
2408 ss << std::format(" {}: 0x{:08X}\n", i, pBank->data[i]);
2409 }
2410 ss << "\n";
2411
2412 return IPMI_CC_OK;
2413}
2414
2415static ipmi_ret_t handleCrdHdrBank(std::span<const uint8_t> data,
2416 CrdState& currState, std::stringstream& ss)
2417{
2418 if (data.size() < sizeof(CrdHdrBank))
2419 return IPMI_CC_REQ_DATA_LEN_INVALID;
2420
2421 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2422 if (res)
2423 return res;
2424
2425 const auto* pBank = reinterpret_cast<const CrdHdrBank*>(data.data());
2426 ss << " Crashdump Header\n";
2427 ss << std::format(" CPU PPIN : 0x{:016X}\n", pBank->ppin);
2428 ss << std::format(" UCODE VERSION : 0x{:08X}\n", pBank->ucodeVer);
2429 ss << std::format(" PMIO 80h : 0x{:08X}\n", pBank->pmio);
2430 ss << std::format(
2431 " BIT0 - SMN Parity/SMN Timeouts PSP/SMU Parity and ECC/SMN On-Package Link Error : {}\n",
2432 pBank->pmio & 0x1);
2433 ss << std::format(" BIT2 - PSP Parity and ECC : {}\n",
2434 (pBank->pmio & 0x4) >> 2);
2435 ss << std::format(" BIT3 - SMN Timeouts SMU : {}\n",
2436 (pBank->pmio & 0x8) >> 3);
2437 ss << std::format(" BIT4 - SMN Off-Package Link Packet Error : {}\n",
2438 (pBank->pmio & 0x10) >> 4);
2439 ss << "\n";
2440
2441 return IPMI_CC_OK;
2442}
2443
2444static std::string getFilename(const std::filesystem::path& dir,
2445 const std::string& prefix)
2446{
2447 std::vector<int> indices;
2448 std::regex pattern(prefix + "(\\d+)\\.txt");
2449
2450 for (const auto& entry : std::filesystem::directory_iterator(dir))
2451 {
2452 std::string filename = entry.path().filename().string();
2453 std::smatch match;
2454 if (std::regex_match(filename, match, pattern))
2455 indices.push_back(std::stoi(match[1]));
2456 }
2457
2458 std::sort(indices.rbegin(), indices.rend());
2459 while (indices.size() > 2) // keep 3 files, so remove if more than 2
2460 {
2461 std::filesystem::remove(
2462 dir / (prefix + std::to_string(indices.back()) + ".txt"));
2463 indices.pop_back();
2464 }
2465
2466 int nextIndex = indices.empty() ? 1 : indices.front() + 1;
2467 return prefix + std::to_string(nextIndex) + ".txt";
2468}
2469
2470static ipmi_ret_t handleCtrlBank(std::span<const uint8_t> data,
2471 CrdState& currState, std::stringstream& ss)
2472{
2473 if (data.empty())
2474 return IPMI_CC_REQ_DATA_LEN_INVALID;
2475
2476 switch (static_cast<CrdCtrl>(data[0]))
2477 {
2478 case CrdCtrl::getState:
2479 break;
2480 case CrdCtrl::finish:
2481 {
2482 ipmi_ret_t res = setDumpState(currState, CrdState::packing);
2483 if (res)
2484 return res;
2485
2486 const std::filesystem::path dumpDir = "/var/lib/fb-ipmi-oem";
2487 std::string filename = getFilename(dumpDir, "crashdump_");
2488 std::ofstream outFile(dumpDir / filename);
2489 if (!outFile.is_open())
2490 return IPMI_CC_UNSPECIFIED_ERROR;
2491
2492 auto now = std::chrono::system_clock::to_time_t(
2493 std::chrono::system_clock::now());
2494 outFile << "Crash Dump generated at: "
2495 << std::put_time(std::localtime(&now), "%Y-%m-%d %H:%M:%S")
2496 << "\n\n";
2497 outFile << ss.str();
2498 outFile.close();
2499 ss.str("");
2500 ss.clear();
2501 setDumpState(currState, CrdState::free);
2502 break;
2503 }
2504 default:
2505 return ccInvalidParam;
2506 }
2507
2508 return IPMI_CC_OK;
2509}
2510
Patrick Williams010dee02024-08-16 15:19:44 -04002511ipmi::RspType<std::vector<uint8_t>> ipmiOemCrashdump(
2512 [[maybe_unused]] ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002513{
2514 static CrdState dumpState = CrdState::free;
2515 static std::stringstream ss;
2516
2517 if (reqData.size() < sizeof(CrashDumpHdr))
2518 return ipmi::responseReqDataLenInvalid();
2519
2520 const auto* pHdr = reinterpret_cast<const CrashDumpHdr*>(reqData.data());
2521 std::span<const uint8_t> bData{reqData.data() + sizeof(CrashDumpHdr),
2522 reqData.size() - sizeof(CrashDumpHdr)};
2523 ipmi_ret_t res;
2524
2525 switch (pHdr->bankHdr.bankType)
2526 {
2527 case BankType::mca:
2528 res = handleMcaBank(*pHdr, bData, dumpState, ss);
2529 break;
2530 case BankType::virt:
2531 if (pHdr->bankHdr.version >= 3)
2532 {
2533 res = handleVirtualBank<CrdVirtualBankV3>(bData, dumpState, ss);
2534 break;
2535 }
2536 res = handleVirtualBank<CrdVirtualBankV2>(bData, dumpState, ss);
2537 break;
2538 case BankType::cpuWdt:
2539 res = handleCpuWdtBank(bData, dumpState, ss);
2540 break;
2541 case BankType::tcdx:
2542 res = handleHwAssertBank<tcdxNum>("TCDX", bData, dumpState, ss);
2543 break;
2544 case BankType::cake:
2545 res = handleHwAssertBank<cakeNum>("CAKE", bData, dumpState, ss);
2546 break;
2547 case BankType::pie0:
2548 res = handleHwAssertBank<pie0Num>("PIE", bData, dumpState, ss);
2549 break;
2550 case BankType::iom:
2551 res = handleHwAssertBank<iomNum>("IOM", bData, dumpState, ss);
2552 break;
2553 case BankType::ccix:
2554 res = handleHwAssertBank<ccixNum>("CCIX", bData, dumpState, ss);
2555 break;
2556 case BankType::cs:
2557 res = handleHwAssertBank<csNum>("CS", bData, dumpState, ss);
2558 break;
2559 case BankType::pcieAer:
2560 res = handlePcieAerBank(bData, dumpState, ss);
2561 break;
2562 case BankType::wdtReg:
2563 res = handleWdtRegBank(bData, dumpState, ss);
2564 break;
2565 case BankType::ctrl:
2566 res = handleCtrlBank(bData, dumpState, ss);
2567 if (res == IPMI_CC_OK &&
2568 static_cast<CrdCtrl>(bData[0]) == CrdCtrl::getState)
2569 {
2570 return ipmi::responseSuccess(
2571 std::vector<uint8_t>{static_cast<uint8_t>(dumpState)});
2572 }
2573 break;
2574 case BankType::crdHdr:
2575 res = handleCrdHdrBank(bData, dumpState, ss);
2576 break;
2577 default:
2578 return ipmi::responseInvalidFieldRequest();
2579 }
2580
2581 return ipmi::response(res);
2582}
2583
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002584static void registerOEMFunctions(void)
2585{
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002586 /* Get OEM data from json file */
2587 std::ifstream file(JSON_OEM_DATA_FILE);
2588 if (file)
Vijay Khemkafeaa9812019-08-27 15:08:08 -07002589 {
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002590 file >> oemData;
Vijay Khemkafeaa9812019-08-27 15:08:08 -07002591 file.close();
2592 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002593
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002594 phosphor::logging::log<phosphor::logging::level::INFO>(
2595 "Registering OEM commands");
Vijay Khemka7c0aea42020-03-05 13:31:53 -08002596
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002597 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_INFO,
2598 NULL, ipmiOemDbgGetFrameInfo,
2599 PRIVILEGE_USER); // get debug frame info
2600 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ,
2601 CMD_OEM_USB_DBG_GET_UPDATED_FRAMES, NULL,
2602 ipmiOemDbgGetUpdFrames,
2603 PRIVILEGE_USER); // get debug updated frames
2604 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_POST_DESC,
2605 NULL, ipmiOemDbgGetPostDesc,
2606 PRIVILEGE_USER); // get debug post description
2607 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_GPIO_DESC,
2608 NULL, ipmiOemDbgGetGpioDesc,
2609 PRIVILEGE_USER); // get debug gpio description
2610 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_DATA,
2611 NULL, ipmiOemDbgGetFrameData,
2612 PRIVILEGE_USER); // get debug frame data
2613 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_CTRL_PANEL,
2614 NULL, ipmiOemDbgGetCtrlPanel,
2615 PRIVILEGE_USER); // get debug control panel
2616 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_DIMM_INFO, NULL,
2617 ipmiOemSetDimmInfo,
2618 PRIVILEGE_USER); // Set Dimm Info
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002619 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_GET_BOARD_ID, NULL,
2620 ipmiOemGetBoardID,
2621 PRIVILEGE_USER); // Get Board ID
Bonnie Lo4ae63e72023-02-09 15:27:54 +08002622 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnOemOne,
2623 CMD_OEM_GET_80PORT_RECORD, ipmi::Privilege::User,
2624 ipmiOemGet80PortRecord); // Get 80 Port Record
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002625 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_MACHINE_CONFIG_INFO, NULL,
2626 ipmiOemSetMachineCfgInfo,
2627 PRIVILEGE_USER); // Set Machine Config Info
2628 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_POST_START, NULL,
2629 ipmiOemSetPostStart,
2630 PRIVILEGE_USER); // Set POST start
2631 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_POST_END, NULL,
2632 ipmiOemSetPostEnd,
2633 PRIVILEGE_USER); // Set POST End
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002634 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_PPIN_INFO, NULL,
2635 ipmiOemSetPPINInfo,
2636 PRIVILEGE_USER); // Set PPIN Info
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05302637#if BIC_ENABLED
2638
2639 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2640 ipmi::cmdSetSystemGuid, ipmi::Privilege::User,
2641 ipmiOemSetSystemGuid);
2642#else
2643
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07002644 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_SYSTEM_GUID, NULL,
2645 ipmiOemSetSystemGuid,
2646 PRIVILEGE_USER); // Set System GUID
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05302647#endif
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002648 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_ADR_TRIGGER, NULL,
2649 ipmiOemSetAdrTrigger,
2650 PRIVILEGE_USER); // Set ADR Trigger
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002651 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_BIOS_FLASH_INFO, NULL,
2652 ipmiOemSetBiosFlashInfo,
2653 PRIVILEGE_USER); // Set Bios Flash Info
2654 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_PPR, NULL, ipmiOemSetPpr,
2655 PRIVILEGE_USER); // Set PPR
2656 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_GET_PPR, NULL, ipmiOemGetPpr,
2657 PRIVILEGE_USER); // Get PPR
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002658 /* FB OEM QC Commands */
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05302659 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour,
2660 CMD_OEM_Q_SET_PROC_INFO, ipmi::Privilege::User,
2661 ipmiOemQSetProcInfo); // Set Proc Info
2662 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour,
2663 CMD_OEM_Q_GET_PROC_INFO, ipmi::Privilege::User,
2664 ipmiOemQGetProcInfo); // Get Proc Info
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05302665 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour,
2666 ipmi::cmdSetQDimmInfo, ipmi::Privilege::User,
2667 ipmiOemQSetDimmInfo); // Set Dimm Info
2668 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour,
2669 ipmi::cmdGetQDimmInfo, ipmi::Privilege::User,
2670 ipmiOemQGetDimmInfo); // Get Dimm Info
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002671 ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_DRIVE_INFO, NULL,
2672 ipmiOemQSetDriveInfo,
2673 PRIVILEGE_USER); // Set Drive Info
2674 ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_DRIVE_INFO, NULL,
2675 ipmiOemQGetDriveInfo,
2676 PRIVILEGE_USER); // Get Drive Info
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002677
2678 /* FB OEM DCMI Commands as per DCMI spec 1.5 Section 6 */
Patrick Williams010dee02024-08-16 15:19:44 -04002679 ipmi::registerGroupHandler(
2680 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdGetPowerReading,
2681 ipmi::Privilege::User,
2682 ipmiOemDCMIGetPowerReading); // Get Power Reading
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002683
Patrick Williams010dee02024-08-16 15:19:44 -04002684 ipmi::registerGroupHandler(
2685 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdGetPowerLimit,
2686 ipmi::Privilege::User,
2687 ipmiOemDCMIGetPowerLimit); // Get Power Limit
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002688
Patrick Williams010dee02024-08-16 15:19:44 -04002689 ipmi::registerGroupHandler(
2690 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdSetPowerLimit,
2691 ipmi::Privilege::Operator,
2692 ipmiOemDCMISetPowerLimit); // Set Power Limit
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002693
Patrick Williams010dee02024-08-16 15:19:44 -04002694 ipmi::registerGroupHandler(
2695 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdActDeactivatePwrLimit,
2696 ipmi::Privilege::Operator,
2697 ipmiOemDCMIApplyPowerLimit); // Apply Power Limit
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002698
Jayashree-Df0cf6652020-11-30 11:03:30 +05302699 /* FB OEM BOOT ORDER COMMANDS */
2700 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2701 CMD_OEM_GET_BOOT_ORDER, ipmi::Privilege::User,
2702 ipmiOemGetBootOrder); // Get Boot Order
2703
2704 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2705 CMD_OEM_SET_BOOT_ORDER, ipmi::Privilege::User,
2706 ipmiOemSetBootOrder); // Set Boot Order
2707
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002708 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
Cosmo Chou99d42b62024-08-15 10:42:47 +08002709 CMD_OEM_GET_HTTPS_BOOT_DATA, ipmi::Privilege::User,
2710 ipmiOemGetHttpsData);
2711
2712 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2713 CMD_OEM_GET_HTTPS_BOOT_ATTR, ipmi::Privilege::User,
2714 ipmiOemGetHttpsAttr);
2715
2716 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002717 CMD_OEM_CRASHDUMP, ipmi::Privilege::User,
2718 ipmiOemCrashdump);
2719
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002720 return;
2721}
2722
2723} // namespace ipmi