blob: 99b28c27c854d8c5e2669d625a40f9d5a47bc662 [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>
Liora Guo4006fe72025-08-19 15:21:24 +080036#include <functional>
Vijay Khemka63c99be2020-05-27 19:14:35 -070037#include <iomanip>
38#include <iostream>
Liora Guo4006fe72025-08-19 15:21:24 +080039#include <optional>
Patrick Williams2405ae92023-05-10 07:50:09 -050040#include <regex>
Vijay Khemka63c99be2020-05-27 19:14:35 -070041#include <sstream>
Vijay Khemkae7d23d02019-03-08 13:13:40 -080042#include <string>
43#include <vector>
44
45#define SIZE_IANA_ID 3
46
47namespace ipmi
48{
Vijay Khemkaa7231892019-10-11 11:35:05 -070049
50using namespace phosphor::logging;
51
Karthikeyan Pasupathie1ff81f2022-11-21 17:54:46 +053052void getSelectorPosition(size_t& position);
Vijay Khemkae7d23d02019-03-08 13:13:40 -080053static void registerOEMFunctions() __attribute__((constructor));
Patrick Williamscd315e02022-07-22 19:26:52 -050054sdbusplus::bus_t dbus(ipmid_get_sd_bus_connection()); // from ipmid/api.h
Vijay Khemkae7d23d02019-03-08 13:13:40 -080055static constexpr size_t maxFRUStringLength = 0x3F;
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +053056constexpr uint8_t cmdSetSystemGuid = 0xEF;
Vijay Khemkae7d23d02019-03-08 13:13:40 -080057
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +053058constexpr uint8_t cmdSetQDimmInfo = 0x12;
59constexpr uint8_t cmdGetQDimmInfo = 0x13;
60
Cosmo Chou7ab87bb2024-06-28 10:47:44 +080061constexpr ipmi_ret_t ccInvalidParam = 0x80;
62
Vijay Khemka63c99be2020-05-27 19:14:35 -070063int plat_udbg_get_post_desc(uint8_t, uint8_t*, uint8_t, uint8_t*, uint8_t*,
64 uint8_t*);
65int plat_udbg_get_gpio_desc(uint8_t, uint8_t*, uint8_t*, uint8_t*, uint8_t*,
66 uint8_t*);
Patrick Williams5e589482024-07-13 16:18:13 -050067int plat_udbg_get_frame_data(uint8_t, uint8_t, uint8_t*, uint8_t*, uint8_t*);
Vijay Khemka63c99be2020-05-27 19:14:35 -070068ipmi_ret_t plat_udbg_control_panel(uint8_t, uint8_t, uint8_t, uint8_t*,
69 uint8_t*);
70int sendMeCmd(uint8_t, uint8_t, std::vector<uint8_t>&, std::vector<uint8_t>&);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -070071
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +053072int sendBicCmd(uint8_t, uint8_t, uint8_t, std::vector<uint8_t>&,
73 std::vector<uint8_t>&);
74
Vijay Khemkafeaa9812019-08-27 15:08:08 -070075nlohmann::json oemData __attribute__((init_priority(101)));
Vijay Khemka1b6fae32019-03-25 17:43:01 -070076
Cosmo Chou99d42b62024-08-15 10:42:47 +080077constexpr const char* certPath = "/mnt/data/host/bios-rootcert";
78
Vijay Khemkaf2246ce2020-05-27 14:26:35 -070079static constexpr size_t GUID_SIZE = 16;
80// TODO Make offset and location runtime configurable to ensure we
81// can make each define their own locations.
82static constexpr off_t OFFSET_SYS_GUID = 0x17F0;
83static constexpr const char* FRU_EEPROM = "/sys/bus/i2c/devices/6-0054/eeprom";
Delphine CC Chiu7bb45922023-04-10 13:34:04 +080084void flushOemData();
Vijay Khemkaf2246ce2020-05-27 14:26:35 -070085
Vijay Khemka1b6fae32019-03-25 17:43:01 -070086enum class LanParam : uint8_t
87{
88 INPROGRESS = 0,
89 AUTHSUPPORT = 1,
90 AUTHENABLES = 2,
91 IP = 3,
92 IPSRC = 4,
93 MAC = 5,
94 SUBNET = 6,
95 GATEWAY = 12,
96 VLAN = 20,
97 CIPHER_SUITE_COUNT = 22,
98 CIPHER_SUITE_ENTRIES = 23,
99 IPV6 = 59,
100};
101
Vijay Khemkaa7231892019-10-11 11:35:05 -0700102namespace network
103{
104
105constexpr auto ROOT = "/xyz/openbmc_project/network";
106constexpr auto SERVICE = "xyz.openbmc_project.Network";
107constexpr auto IPV4_TYPE = "ipv4";
108constexpr auto IPV6_TYPE = "ipv6";
109constexpr auto IPV4_PREFIX = "169.254";
110constexpr auto IPV6_PREFIX = "fe80";
111constexpr auto IP_INTERFACE = "xyz.openbmc_project.Network.IP";
112constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress";
Potin Lai8d1a81e2022-12-20 11:13:45 +0800113constexpr auto IPV4_PROTOCOL = "xyz.openbmc_project.Network.IP.Protocol.IPv4";
114constexpr auto IPV6_PROTOCOL = "xyz.openbmc_project.Network.IP.Protocol.IPv6";
Vijay Khemkaa7231892019-10-11 11:35:05 -0700115
Vijay Khemka63c99be2020-05-27 19:14:35 -0700116bool isLinkLocalIP(const std::string& address)
Vijay Khemkaa7231892019-10-11 11:35:05 -0700117{
118 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
119}
120
Patrick Williamscd315e02022-07-22 19:26:52 -0500121DbusObjectInfo getIPObject(sdbusplus::bus_t& bus, const std::string& interface,
Vijay Khemka63c99be2020-05-27 19:14:35 -0700122 const std::string& serviceRoot,
Potin Lai8d1a81e2022-12-20 11:13:45 +0800123 const std::string& protocol,
124 const std::string& ethdev)
Vijay Khemkaa7231892019-10-11 11:35:05 -0700125{
Potin Lai8d1a81e2022-12-20 11:13:45 +0800126 auto objectTree = getAllDbusObjects(bus, serviceRoot, interface, ethdev);
Vijay Khemkaa7231892019-10-11 11:35:05 -0700127
128 if (objectTree.empty())
129 {
130 log<level::ERR>("No Object has implemented the IP interface",
131 entry("INTERFACE=%s", interface.c_str()));
132 }
133
134 DbusObjectInfo objectInfo;
135
Vijay Khemka63c99be2020-05-27 19:14:35 -0700136 for (auto& object : objectTree)
Vijay Khemkaa7231892019-10-11 11:35:05 -0700137 {
Patrick Williams010dee02024-08-16 15:19:44 -0400138 auto variant =
139 ipmi::getDbusProperty(bus, object.second.begin()->first,
140 object.first, IP_INTERFACE, "Type");
Potin Lai8d1a81e2022-12-20 11:13:45 +0800141 if (std::get<std::string>(variant) != protocol)
142 {
143 continue;
144 }
145
146 variant = ipmi::getDbusProperty(bus, object.second.begin()->first,
147 object.first, IP_INTERFACE, "Address");
Vijay Khemkaa7231892019-10-11 11:35:05 -0700148
149 objectInfo = std::make_pair(object.first, object.second.begin()->first);
150
151 // if LinkLocalIP found look for Non-LinkLocalIP
152 if (isLinkLocalIP(std::get<std::string>(variant)))
153 {
154 continue;
155 }
156 else
157 {
158 break;
159 }
160 }
161 return objectInfo;
162}
163
164} // namespace network
165
Jayashree-Df0cf6652020-11-30 11:03:30 +0530166namespace boot
167{
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530168using BootSource =
169 sdbusplus::xyz::openbmc_project::Control::Boot::server::Source::Sources;
170using BootMode =
171 sdbusplus::xyz::openbmc_project::Control::Boot::server::Mode::Modes;
172using BootType =
173 sdbusplus::xyz::openbmc_project::Control::Boot::server::Type::Types;
Jayashree-Df0cf6652020-11-30 11:03:30 +0530174
Jayashree-Df0cf6652020-11-30 11:03:30 +0530175using IpmiValue = uint8_t;
176
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530177std::map<IpmiValue, BootSource> sourceIpmiToDbus = {
178 {0x0f, BootSource::Default}, {0x00, BootSource::RemovableMedia},
179 {0x01, BootSource::Network}, {0x02, BootSource::Disk},
Delphine CC Chiu7bb45922023-04-10 13:34:04 +0800180 {0x03, BootSource::ExternalMedia}, {0x04, BootSource::RemovableMedia},
181 {0x09, BootSource::Network}};
Jayashree-Df0cf6652020-11-30 11:03:30 +0530182
Delphine CC Chiuc0f918b2023-03-22 14:48:04 +0800183std::map<IpmiValue, BootMode> modeIpmiToDbus = {{0x04, BootMode::Setup},
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530184 {0x00, BootMode::Regular}};
Jayashree-Df0cf6652020-11-30 11:03:30 +0530185
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530186std::map<IpmiValue, BootType> typeIpmiToDbus = {{0x00, BootType::Legacy},
187 {0x01, BootType::EFI}};
Jayashree Dhanapal778147d2022-03-30 16:48:53 +0530188
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530189std::map<std::optional<BootSource>, IpmiValue> sourceDbusToIpmi = {
190 {BootSource::Default, 0x0f},
191 {BootSource::RemovableMedia, 0x00},
192 {BootSource::Network, 0x01},
193 {BootSource::Disk, 0x02},
194 {BootSource::ExternalMedia, 0x03}};
Jayashree-Df0cf6652020-11-30 11:03:30 +0530195
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530196std::map<std::optional<BootMode>, IpmiValue> modeDbusToIpmi = {
Delphine CC Chiuc0f918b2023-03-22 14:48:04 +0800197 {BootMode::Setup, 0x04}, {BootMode::Regular, 0x00}};
Jayashree-Df0cf6652020-11-30 11:03:30 +0530198
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530199std::map<std::optional<BootType>, IpmiValue> typeDbusToIpmi = {
200 {BootType::Legacy, 0x00}, {BootType::EFI, 0x01}};
Jayashree Dhanapal778147d2022-03-30 16:48:53 +0530201
Delphine CC Chiuc0f918b2023-03-22 14:48:04 +0800202static constexpr auto bootEnableIntf = "xyz.openbmc_project.Object.Enable";
Jayashree-Df0cf6652020-11-30 11:03:30 +0530203static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
204static constexpr auto bootSourceIntf =
205 "xyz.openbmc_project.Control.Boot.Source";
Jayashree Dhanapal778147d2022-03-30 16:48:53 +0530206static constexpr auto bootTypeIntf = "xyz.openbmc_project.Control.Boot.Type";
Jayashree-Df0cf6652020-11-30 11:03:30 +0530207static constexpr auto bootSourceProp = "BootSource";
208static constexpr auto bootModeProp = "BootMode";
Jayashree Dhanapal778147d2022-03-30 16:48:53 +0530209static constexpr auto bootTypeProp = "BootType";
Delphine CC Chiuc0f918b2023-03-22 14:48:04 +0800210static constexpr auto bootEnableProp = "Enabled";
Jayashree-Df0cf6652020-11-30 11:03:30 +0530211
Jayashree-Df0cf6652020-11-30 11:03:30 +0530212std::tuple<std::string, std::string> objPath(size_t id)
213{
214 std::string hostName = "host" + std::to_string(id);
Patrick Williams010dee02024-08-16 15:19:44 -0400215 std::string bootObjPath =
216 "/xyz/openbmc_project/control/" + hostName + "/boot";
Jayashree-Df0cf6652020-11-30 11:03:30 +0530217 return std::make_tuple(std::move(bootObjPath), std::move(hostName));
218}
219
Delphine CC Chiu7bb45922023-04-10 13:34:04 +0800220/* Helper functions to set boot order */
221void setBootOrder(std::string bootObjPath, const std::vector<uint8_t>& bootSeq,
222 std::string bootOrderKey)
223{
224 if (bootSeq.size() != SIZE_BOOT_ORDER)
225 {
226 phosphor::logging::log<phosphor::logging::level::ERR>(
227 "Invalid Boot order length received");
228 return;
229 }
230
231 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
232
233 uint8_t mode = bootSeq.front();
234
235 // SETTING BOOT MODE PROPERTY
236 uint8_t bootModeBit = mode & 0x04;
237 auto bootValue = ipmi::boot::modeIpmiToDbus.at(bootModeBit);
238
239 std::string bootOption =
240 sdbusplus::message::convert_to_string<boot::BootMode>(bootValue);
241
Patrick Williams010dee02024-08-16 15:19:44 -0400242 std::string service =
243 getService(*dbus, ipmi::boot::bootModeIntf, bootObjPath);
Delphine CC Chiu7bb45922023-04-10 13:34:04 +0800244 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootModeIntf,
245 ipmi::boot::bootModeProp, bootOption);
246
247 // SETTING BOOT SOURCE PROPERTY
248 auto bootOrder = ipmi::boot::sourceIpmiToDbus.at(bootSeq.at(1));
249 std::string bootSource =
250 sdbusplus::message::convert_to_string<boot::BootSource>(bootOrder);
251
252 service = getService(*dbus, ipmi::boot::bootSourceIntf, bootObjPath);
253 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootSourceIntf,
254 ipmi::boot::bootSourceProp, bootSource);
255
256 // SETTING BOOT TYPE PROPERTY
257 uint8_t bootTypeBit = mode & 0x01;
258 auto bootTypeVal = ipmi::boot::typeIpmiToDbus.at(bootTypeBit);
259
260 std::string bootType =
261 sdbusplus::message::convert_to_string<boot::BootType>(bootTypeVal);
262
263 service = getService(*dbus, ipmi::boot::bootTypeIntf, bootObjPath);
264
265 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootTypeIntf,
266 ipmi::boot::bootTypeProp, bootType);
267
268 // Set the valid bit to boot enabled property
269 service = getService(*dbus, ipmi::boot::bootEnableIntf, bootObjPath);
270
271 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootEnableIntf,
272 ipmi::boot::bootEnableProp,
273 (mode & BOOT_MODE_BOOT_FLAG) ? true : false);
274
275 nlohmann::json bootMode;
276
277 bootMode["UEFI"] = (mode & BOOT_MODE_UEFI) ? true : false;
278 bootMode["CMOS_CLR"] = (mode & BOOT_MODE_CMOS_CLR) ? true : false;
279 bootMode["FORCE_BOOT"] = (mode & BOOT_MODE_FORCE_BOOT) ? true : false;
280 bootMode["BOOT_FLAG"] = (mode & BOOT_MODE_BOOT_FLAG) ? true : false;
281 oemData[bootOrderKey][KEY_BOOT_MODE] = bootMode;
282
283 /* Initialize boot sequence array */
284 oemData[bootOrderKey][KEY_BOOT_SEQ] = {};
285 for (size_t i = 1; i < SIZE_BOOT_ORDER; i++)
286 {
287 if (bootSeq.at(i) >= BOOT_SEQ_ARRAY_SIZE)
288 oemData[bootOrderKey][KEY_BOOT_SEQ][i - 1] = "NA";
289 else
290 oemData[bootOrderKey][KEY_BOOT_SEQ][i - 1] =
291 bootSeqDefine[bootSeq.at(i)];
292 }
293
294 flushOemData();
295}
296
297void getBootOrder(std::string bootObjPath, std::vector<uint8_t>& bootSeq,
298 std::string hostName)
299{
300 if (oemData.find(hostName) == oemData.end())
301 {
302 /* Return default boot order 0100090203ff */
303 bootSeq.push_back(BOOT_MODE_UEFI);
304 bootSeq.push_back(static_cast<uint8_t>(bootMap["USB_DEV"]));
305 bootSeq.push_back(static_cast<uint8_t>(bootMap["NET_IPV6"]));
306 bootSeq.push_back(static_cast<uint8_t>(bootMap["SATA_HDD"]));
307 bootSeq.push_back(static_cast<uint8_t>(bootMap["SATA_CD"]));
308 bootSeq.push_back(0xff);
309
310 phosphor::logging::log<phosphor::logging::level::INFO>(
311 "Set default boot order");
312 setBootOrder(bootObjPath, bootSeq, hostName);
313 return;
314 }
315
316 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
317
318 // GETTING PROPERTY OF MODE INTERFACE
319
Patrick Williams010dee02024-08-16 15:19:44 -0400320 std::string service =
321 getService(*dbus, ipmi::boot::bootModeIntf, bootObjPath);
322 Value variant =
323 getDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootModeIntf,
324 ipmi::boot::bootModeProp);
Delphine CC Chiu7bb45922023-04-10 13:34:04 +0800325
326 auto bootMode = sdbusplus::message::convert_from_string<boot::BootMode>(
327 std::get<std::string>(variant));
328
329 uint8_t bootOption = ipmi::boot::modeDbusToIpmi.at(bootMode);
330
331 // GETTING PROPERTY OF TYPE INTERFACE
332
333 service = getService(*dbus, ipmi::boot::bootTypeIntf, bootObjPath);
Patrick Williams010dee02024-08-16 15:19:44 -0400334 variant =
335 getDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootTypeIntf,
336 ipmi::boot::bootTypeProp);
Delphine CC Chiu7bb45922023-04-10 13:34:04 +0800337
338 auto bootType = sdbusplus::message::convert_from_string<boot::BootType>(
339 std::get<std::string>(variant));
340
341 // Get the valid bit to boot enabled property
342 service = getService(*dbus, ipmi::boot::bootEnableIntf, bootObjPath);
Patrick Williams010dee02024-08-16 15:19:44 -0400343 variant =
344 getDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootEnableIntf,
345 ipmi::boot::bootEnableProp);
Delphine CC Chiu7bb45922023-04-10 13:34:04 +0800346
347 bool validFlag = std::get<bool>(variant);
348
349 uint8_t bootTypeVal = ipmi::boot::typeDbusToIpmi.at(bootType);
350
351 bootSeq.push_back(bootOption | bootTypeVal);
352
353 if (validFlag)
354 {
355 bootSeq.front() |= BOOT_MODE_BOOT_FLAG;
356 }
357
358 nlohmann::json bootModeJson = oemData[hostName][KEY_BOOT_MODE];
359 if (bootModeJson["CMOS_CLR"])
360 bootSeq.front() |= BOOT_MODE_CMOS_CLR;
361
362 for (int i = 1; i < SIZE_BOOT_ORDER; i++)
363 {
364 std::string seqStr = oemData[hostName][KEY_BOOT_SEQ][i - 1];
365 if (bootMap.find(seqStr) != bootMap.end())
366 bootSeq.push_back(bootMap[seqStr]);
367 else
368 bootSeq.push_back(0xff);
369 }
370}
371
Jayashree-Df0cf6652020-11-30 11:03:30 +0530372} // namespace boot
373
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700374//----------------------------------------------------------------------
375// Helper functions for storing oem data
376//----------------------------------------------------------------------
377
378void flushOemData()
379{
380 std::ofstream file(JSON_OEM_DATA_FILE);
381 file << oemData;
Vijay Khemkafeaa9812019-08-27 15:08:08 -0700382 file.close();
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700383 return;
384}
385
Vijay Khemka63c99be2020-05-27 19:14:35 -0700386std::string bytesToStr(uint8_t* byte, int len)
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700387{
388 std::stringstream ss;
389 int i;
390
391 ss << std::hex;
392 for (i = 0; i < len; i++)
393 {
394 ss << std::setw(2) << std::setfill('0') << (int)byte[i];
395 }
396
397 return ss.str();
398}
399
Vijay Khemka63c99be2020-05-27 19:14:35 -0700400int strToBytes(std::string& str, uint8_t* data)
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700401{
402 std::string sstr;
Willy Tue39f9392022-06-15 13:24:20 -0700403 size_t i;
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700404
405 for (i = 0; i < (str.length()) / 2; i++)
406 {
407 sstr = str.substr(i * 2, 2);
408 data[i] = (uint8_t)std::strtol(sstr.c_str(), NULL, 16);
409 }
410 return i;
411}
412
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +0530413int readDimmType(std::string& data, uint8_t param)
414{
415 nlohmann::json dimmObj;
416 /* Get dimm type names stored in json file */
417 std::ifstream file(JSON_DIMM_TYPE_FILE);
418 if (file)
419 {
420 file >> dimmObj;
421 file.close();
422 }
423 else
424 {
425 phosphor::logging::log<phosphor::logging::level::ERR>(
426 "DIMM type names file not found",
427 phosphor::logging::entry("DIMM_TYPE_FILE=%s", JSON_DIMM_TYPE_FILE));
428 return -1;
429 }
430
431 std::string dimmKey = "dimm_type" + std::to_string(param);
432 auto obj = dimmObj[dimmKey]["short_name"];
433 data = obj;
434 return 0;
435}
436
Liora Guo4006fe72025-08-19 15:21:24 +0800437static std::optional<std::string> findIpAddress(
438 sdbusplus::bus_t& bus, const std::string& protocol,
439 const std::vector<std::string>& ifaces)
440{
441 for (auto& dev : ifaces)
442 {
443 try
444 {
445 auto ipObjectInfo =
446 ipmi::network::getIPObject(bus, ipmi::network::IP_INTERFACE,
447 ipmi::network::ROOT, protocol, dev);
448
449 auto props = ipmi::getAllDbusProperties(
450 bus, ipObjectInfo.second, ipObjectInfo.first,
451 ipmi::network::IP_INTERFACE);
452
453 auto addr = std::get<std::string>(props.at("Address"));
454 if (!addr.empty())
455 return addr;
456 }
457 catch (const sdbusplus::exception::SdBusError&)
458 {}
459 }
460 return std::nullopt;
461}
462static std::optional<std::string> findMacAddress(
463 sdbusplus::bus_t& bus, const std::vector<std::string>& ifaces)
464{
465 for (auto& dev : ifaces)
466 {
467 try
468 {
469 auto [path, obj] = ipmi::getDbusObject(
470 bus, ipmi::network::MAC_INTERFACE, ipmi::network::ROOT, dev);
471
472 auto var = ipmi::getDbusProperty(
473 bus, obj, path, ipmi::network::MAC_INTERFACE, "MACAddress");
474
475 auto mac = std::get<std::string>(var);
476 if (!mac.empty())
477 return mac;
478 }
479 catch (const sdbusplus::exception::SdBusError&)
480 {}
481 }
482 return std::nullopt;
483}
484
Vijay Khemka63c99be2020-05-27 19:14:35 -0700485ipmi_ret_t getNetworkData(uint8_t lan_param, char* data)
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700486{
Liora Guo4006fe72025-08-19 15:21:24 +0800487 static const std::vector<std::string> ifaces{"eth0", "eth1"};
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700488
Liora Guo4006fe72025-08-19 15:21:24 +0800489 sdbusplus::bus_t bus(ipmid_get_sd_bus_connection());
490 ipmi_ret_t rc = IPMI_CC_OK;
491 std::optional<std::string> result;
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700492
493 switch (static_cast<LanParam>(lan_param))
494 {
Vijay Khemkad1194022020-05-27 18:58:33 -0700495 case LanParam::IP:
Liora Guo4006fe72025-08-19 15:21:24 +0800496 result = findIpAddress(bus, ipmi::network::IPV4_PROTOCOL, ifaces);
497 lg2::info("Found IP Address: {ADDR}", "ADDR",
498 result.value_or("Not Found"));
499 break;
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700500
Vijay Khemkad1194022020-05-27 18:58:33 -0700501 case LanParam::IPV6:
Liora Guo4006fe72025-08-19 15:21:24 +0800502 result = findIpAddress(bus, ipmi::network::IPV6_PROTOCOL, ifaces);
503 lg2::info("Found IPv6 Address: {ADDR}", "ADDR",
504 result.value_or("Not Found"));
505 break;
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700506
Vijay Khemkad1194022020-05-27 18:58:33 -0700507 case LanParam::MAC:
Liora Guo4006fe72025-08-19 15:21:24 +0800508 result = findMacAddress(bus, ifaces);
509 lg2::info("Found MAC Address: {ADDR}", "ADDR",
510 result.value_or("Not Found"));
511 break;
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700512
513 default:
Liora Guo4006fe72025-08-19 15:21:24 +0800514 return IPMI_CC_PARM_OUT_OF_RANGE;
515 }
516
517 if (!result.has_value())
518 {
519 rc = IPMI_CC_UNSPECIFIED_ERROR;
520 data[0] = '\0';
521 }
522 else
523 {
524 std::strcpy(data, result->c_str());
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700525 }
526 return rc;
527}
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800528
Karthikeyan Pasupathi39836ff2022-01-17 12:20:06 +0530529bool isMultiHostPlatform()
530{
531 bool platform;
Jayashree Dhanapal4ec80562022-06-28 15:41:47 +0530532 if (hostInstances == "0")
Karthikeyan Pasupathi39836ff2022-01-17 12:20:06 +0530533 {
534 platform = false;
535 }
536 else
537 {
538 platform = true;
539 }
540 return platform;
541}
Liora Guo4006fe72025-08-19 15:21:24 +0800542static std::optional<std::string> findFruPathByInterface(
543 sdbusplus::bus_t& dbus, const std::string& interfaceName,
544 std::function<bool(const std::string&)> predicate)
Daniel Hsud8d95a32024-05-27 16:05:25 +0800545{
Liora Guo4006fe72025-08-19 15:21:24 +0800546 const int depth = 0;
Daniel Hsud8d95a32024-05-27 16:05:25 +0800547 std::vector<std::string> paths;
Daniel Hsud8d95a32024-05-27 16:05:25 +0800548
549 auto mapperCall = dbus.new_method_call(
550 "xyz.openbmc_project.ObjectMapper",
551 "/xyz/openbmc_project/object_mapper",
552 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths");
Liora Guo4006fe72025-08-19 15:21:24 +0800553 mapperCall.append("/xyz/openbmc_project/inventory/", depth,
554 std::array<const char*, 1>{interfaceName.c_str()});
Daniel Hsud8d95a32024-05-27 16:05:25 +0800555
Daniel Hsud8d95a32024-05-27 16:05:25 +0800556 try
557 {
558 auto reply = dbus.call(mapperCall);
559 reply.read(paths);
560 }
Liora Guo4006fe72025-08-19 15:21:24 +0800561 catch (const sdbusplus::exception_t& e)
Daniel Hsud8d95a32024-05-27 16:05:25 +0800562 {
563 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Liora Guo4006fe72025-08-19 15:21:24 +0800564 return std::nullopt;
Daniel Hsud8d95a32024-05-27 16:05:25 +0800565 }
566
567 for (const auto& path : paths)
568 {
Liora Guo4006fe72025-08-19 15:21:24 +0800569 if (predicate(path))
570 {
571 return path;
572 }
573 }
574 return std::nullopt;
575}
576
577// return "" equals failed
578std::string getMotherBoardFruPath()
579{
580 sdbusplus::bus_t dbus(ipmid_get_sd_bus_connection());
581
582 bool platform = isMultiHostPlatform();
583 size_t hostPosition;
584 if (platform)
585 getSelectorPosition(hostPosition);
586
587 if (hostPosition == 0)
588 {
589 if (auto path = findFruPathByInterface(
590 dbus, "xyz.openbmc_project.Inventory.Item.Bmc",
591 [](const std::string&) { return true; }))
592 {
593 lg2::info("[1] Found Motherboard: {PATH}", "PATH", *path);
594 return *path;
595 }
Daniel Hsud8d95a32024-05-27 16:05:25 +0800596 }
597
Liora Guo4006fe72025-08-19 15:21:24 +0800598 size_t targetIndex = (hostPosition > 0 ? hostPosition - 1 : 0);
599 auto predNth = [targetIndex,
600 counter = size_t{0}](const std::string& /*path*/) mutable {
601 return (counter++ == targetIndex);
602 };
603
604 if (auto path = findFruPathByInterface(
605 dbus, "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
606 predNth))
607 {
608 lg2::info("[2] Found Motherboard: {PATH}", "PATH", *path);
609 return *path;
610 }
611
612 phosphor::logging::log<phosphor::logging::level::ERR>(
613 "getMotherBoardFruPath: no valid FRU path found");
Daniel Hsud8d95a32024-05-27 16:05:25 +0800614 return "";
615}
616
617// return "" equals failed
618std::string getMotherBoardFruName()
619{
620 std::string path = getMotherBoardFruPath();
621 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
622 std::string service = "xyz.openbmc_project.EntityManager";
623
624 try
625 {
626 auto value = ipmi::getDbusProperty(
627 *dbus, service, path, "xyz.openbmc_project.Inventory.Item.Board",
628 "Name");
629 return std::get<std::string>(value);
630 }
631 catch (sdbusplus::exception_t& e)
632 {
633 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
634 return "";
635 }
636}
637
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800638// return code: 0 successful
Vijay Khemka63c99be2020-05-27 19:14:35 -0700639int8_t getFruData(std::string& data, std::string& name)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800640{
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530641 size_t pos;
642 static constexpr const auto depth = 0;
643 std::vector<std::string> paths;
644 std::string machinePath;
Daniel Hsud8d95a32024-05-27 16:05:25 +0800645 std::string baseBoard = getMotherBoardFruPath();
646 baseBoard = baseBoard.empty() ? "Baseboard" : baseBoard;
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530647
648 bool platform = isMultiHostPlatform();
649 if (platform == true)
650 {
Karthikeyan Pasupathie1ff81f2022-11-21 17:54:46 +0530651 getSelectorPosition(pos);
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530652 }
653
654 sd_bus* bus = NULL;
655 int ret = sd_bus_default_system(&bus);
656 if (ret < 0)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800657 {
658 phosphor::logging::log<phosphor::logging::level::ERR>(
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530659 "Failed to connect to system bus",
660 phosphor::logging::entry("ERRNO=0x%X", -ret));
661 sd_bus_unref(bus);
662 return -1;
663 }
Patrick Williamscd315e02022-07-22 19:26:52 -0500664 sdbusplus::bus_t dbus(bus);
Patrick Williams010dee02024-08-16 15:19:44 -0400665 auto mapperCall = dbus.new_method_call(
666 "xyz.openbmc_project.ObjectMapper",
667 "/xyz/openbmc_project/object_mapper",
668 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths");
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530669 static constexpr std::array<const char*, 1> interface = {
670 "xyz.openbmc_project.Inventory.Decorator.Asset"};
671 mapperCall.append("/xyz/openbmc_project/inventory/", depth, interface);
672
673 try
674 {
675 auto reply = dbus.call(mapperCall);
676 reply.read(paths);
677 }
678 catch (sdbusplus::exception_t& e)
679 {
680 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800681 return -1;
682 }
683
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530684 for (const auto& path : paths)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800685 {
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530686 if (platform == true)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800687 {
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530688 if (pos == BMC_POS)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800689 {
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530690 machinePath = baseBoard;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800691 }
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530692 else
693 {
694 machinePath = "_" + std::to_string(pos);
695 }
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800696 }
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530697 else
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800698 {
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530699 machinePath = baseBoard;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800700 }
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530701
702 auto found = path.find(machinePath);
Patrick Williams123cbcc2022-06-24 06:13:59 -0500703 if (found == std::string::npos)
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530704 {
705 continue;
706 }
707
708 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
709 std::string service = getService(
710 *dbus, "xyz.openbmc_project.Inventory.Decorator.Asset", path);
711
712 auto Value = ipmi::getDbusProperty(
713 *dbus, service, path,
714 "xyz.openbmc_project.Inventory.Decorator.Asset", name);
715
716 data = std::get<std::string>(Value);
717 return 0;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800718 }
719 return -1;
720}
721
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +0530722int8_t sysConfig(std::vector<std::string>& data, size_t pos)
723{
724 nlohmann::json sysObj;
725 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(pos);
726 std::string result, typeName;
727 uint8_t res[MAX_BUF];
728
729 /* Get sysConfig data stored in json file */
730 std::ifstream file(JSON_OEM_DATA_FILE);
731 if (file)
732 {
733 file >> sysObj;
734 file.close();
735 }
736 else
737 {
738 phosphor::logging::log<phosphor::logging::level::ERR>(
739 "oemData file not found",
740 phosphor::logging::entry("OEM_DATA_FILE=%s", JSON_OEM_DATA_FILE));
741 return -1;
742 }
743
744 if (sysObj.find(dimmInfo) == sysObj.end())
745 {
746 phosphor::logging::log<phosphor::logging::level::ERR>(
747 "sysconfig key not available",
748 phosphor::logging::entry("SYS_JSON_KEY=%s", dimmInfo.c_str()));
749 return -1;
750 }
751 /* Get dimm type names stored in json file */
752 nlohmann::json dimmObj;
753 std::ifstream dimmFile(JSON_DIMM_TYPE_FILE);
754 if (file)
755 {
756 dimmFile >> dimmObj;
757 dimmFile.close();
758 }
759 else
760 {
761 phosphor::logging::log<phosphor::logging::level::ERR>(
762 "DIMM type names file not found",
763 phosphor::logging::entry("DIMM_TYPE_FILE=%s", JSON_DIMM_TYPE_FILE));
764 return -1;
765 }
766 std::vector<std::string> a;
767 for (auto& j : dimmObj.items())
768 {
769 std::string name = j.key();
770 a.push_back(name);
771 }
772
773 uint8_t len = a.size();
774 for (uint8_t ii = 0; ii < len; ii++)
775 {
776 std::string indKey = std::to_string(ii);
777 std::string speedSize = sysObj[dimmInfo][indKey][DIMM_SPEED];
778 strToBytes(speedSize, res);
779 auto speed = (res[1] << 8 | res[0]);
780 size_t dimmSize = ((res[3] << 8 | res[2]) / 1000);
781
782 if (dimmSize == 0)
783 {
784 std::cerr << "Dimm information not available for slot_" +
785 std::to_string(ii)
786 << std::endl;
787 continue;
788 }
789 std::string type = sysObj[dimmInfo][indKey][DIMM_TYPE];
790 std::string dualInlineMem = sysObj[dimmInfo][indKey][KEY_DIMM_TYPE];
791 strToBytes(type, res);
792 size_t dimmType = res[0];
793 if (dimmVenMap.find(dimmType) == dimmVenMap.end())
794 {
795 typeName = "unknown";
796 }
797 else
798 {
799 typeName = dimmVenMap[dimmType];
800 }
801 result = dualInlineMem + "/" + typeName + "/" + std::to_string(speed) +
802 "MHz" + "/" + std::to_string(dimmSize) + "GB";
803 data.push_back(result);
804 }
805 return 0;
806}
807
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +0530808int8_t procInfo(std::string& result, size_t pos)
809{
810 std::vector<char> data;
811 uint8_t res[MAX_BUF];
812 std::string procIndex = "00";
813 nlohmann::json proObj;
814 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(pos);
815 /* Get processor data stored in json file */
816 std::ifstream file(JSON_OEM_DATA_FILE);
817 if (file)
818 {
819 file >> proObj;
820 file.close();
821 }
822 else
823 {
824 phosphor::logging::log<phosphor::logging::level::ERR>(
825 "oemData file not found",
826 phosphor::logging::entry("OEM_DATA_FILE=%s", JSON_OEM_DATA_FILE));
827 return -1;
828 }
829 if (proObj.find(procInfo) == proObj.end())
830 {
831 phosphor::logging::log<phosphor::logging::level::ERR>(
832 "processor info key not available",
833 phosphor::logging::entry("PROC_JSON_KEY=%s", procInfo.c_str()));
834 return -1;
835 }
836 std::string procName = proObj[procInfo][procIndex][KEY_PROC_NAME];
837 std::string basicInfo = proObj[procInfo][procIndex][KEY_BASIC_INFO];
838 // Processor Product Name
839 strToBytes(procName, res);
840 data.assign(reinterpret_cast<char*>(&res),
841 reinterpret_cast<char*>(&res) + sizeof(res));
842
843 std::string s(data.begin(), data.end());
844 std::regex regex(" ");
845 std::vector<std::string> productName(
846 std::sregex_token_iterator(s.begin(), s.end(), regex, -1),
847 std::sregex_token_iterator());
848
849 // Processor core and frequency
850 strToBytes(basicInfo, res);
851 uint16_t coreNum = res[0];
852 double procFrequency = (float)(res[4] << 8 | res[3]) / 1000;
853 result = "CPU:" + productName[2] + "/" + std::to_string(procFrequency) +
854 "GHz" + "/" + std::to_string(coreNum) + "c";
855 return 0;
856}
857
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800858typedef struct
859{
860 uint8_t cur_power_state;
861 uint8_t last_power_event;
862 uint8_t misc_power_state;
863 uint8_t front_panel_button_cap_status;
864} ipmi_get_chassis_status_t;
865
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800866//----------------------------------------------------------------------
867// Get Debug Frame Info
868//----------------------------------------------------------------------
Patrick Williams010dee02024-08-16 15:19:44 -0400869ipmi_ret_t ipmiOemDbgGetFrameInfo(
870 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
871 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800872{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700873 uint8_t* req = reinterpret_cast<uint8_t*>(request);
874 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Peter Yinb340aa22024-07-08 16:07:55 +0800875 uint8_t num_frames = debugCardFrameSize;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800876
877 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
878 res[SIZE_IANA_ID] = num_frames;
879 *data_len = SIZE_IANA_ID + 1;
880
George Liu2f454992025-07-02 16:43:57 +0800881 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800882}
883
884//----------------------------------------------------------------------
885// Get Debug Updated Frames
886//----------------------------------------------------------------------
Patrick Williams010dee02024-08-16 15:19:44 -0400887ipmi_ret_t ipmiOemDbgGetUpdFrames(
888 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
889 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800890{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700891 uint8_t* req = reinterpret_cast<uint8_t*>(request);
892 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800893 uint8_t num_updates = 3;
894 *data_len = 4;
895
896 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
897 res[SIZE_IANA_ID] = num_updates;
898 *data_len = SIZE_IANA_ID + num_updates + 1;
899 res[SIZE_IANA_ID + 1] = 1; // info page update
900 res[SIZE_IANA_ID + 2] = 2; // cri sel update
901 res[SIZE_IANA_ID + 3] = 3; // cri sensor update
902
George Liu2f454992025-07-02 16:43:57 +0800903 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800904}
905
906//----------------------------------------------------------------------
907// Get Debug POST Description
908//----------------------------------------------------------------------
Patrick Williams010dee02024-08-16 15:19:44 -0400909ipmi_ret_t ipmiOemDbgGetPostDesc(
910 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
911 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800912{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700913 uint8_t* req = reinterpret_cast<uint8_t*>(request);
914 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800915 uint8_t index = 0;
916 uint8_t next = 0;
917 uint8_t end = 0;
918 uint8_t phase = 0;
Vijay Khemkacc0d6d92019-08-27 14:51:17 -0700919 uint8_t descLen = 0;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800920 int ret;
921
922 index = req[3];
923 phase = req[4];
924
Vijay Khemkacc0d6d92019-08-27 14:51:17 -0700925 ret = plat_udbg_get_post_desc(index, &next, phase, &end, &descLen, &res[8]);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800926 if (ret)
927 {
928 memcpy(res, req, SIZE_IANA_ID); // IANA ID
929 *data_len = SIZE_IANA_ID;
George Liu2f454992025-07-02 16:43:57 +0800930 return ipmi::ccUnspecifiedError;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800931 }
932
933 memcpy(res, req, SIZE_IANA_ID); // IANA ID
934 res[3] = index;
935 res[4] = next;
936 res[5] = phase;
937 res[6] = end;
Vijay Khemkacc0d6d92019-08-27 14:51:17 -0700938 res[7] = descLen;
939 *data_len = SIZE_IANA_ID + 5 + descLen;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800940
George Liu2f454992025-07-02 16:43:57 +0800941 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800942}
943
944//----------------------------------------------------------------------
945// Get Debug GPIO Description
946//----------------------------------------------------------------------
Patrick Williams010dee02024-08-16 15:19:44 -0400947ipmi_ret_t ipmiOemDbgGetGpioDesc(
948 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
949 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800950{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700951 uint8_t* req = reinterpret_cast<uint8_t*>(request);
952 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800953
Vijay Khemka38183d62019-08-28 16:19:33 -0700954 uint8_t index = 0;
955 uint8_t next = 0;
956 uint8_t level = 0;
957 uint8_t pinDef = 0;
958 uint8_t descLen = 0;
959 int ret;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800960
Vijay Khemka38183d62019-08-28 16:19:33 -0700961 index = req[3];
962
963 ret = plat_udbg_get_gpio_desc(index, &next, &level, &pinDef, &descLen,
964 &res[8]);
965 if (ret)
966 {
967 memcpy(res, req, SIZE_IANA_ID); // IANA ID
968 *data_len = SIZE_IANA_ID;
George Liu2f454992025-07-02 16:43:57 +0800969 return ipmi::ccUnspecifiedError;
Vijay Khemka38183d62019-08-28 16:19:33 -0700970 }
971
972 memcpy(res, req, SIZE_IANA_ID); // IANA ID
973 res[3] = index;
974 res[4] = next;
975 res[5] = level;
976 res[6] = pinDef;
977 res[7] = descLen;
978 *data_len = SIZE_IANA_ID + 5 + descLen;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800979
George Liu2f454992025-07-02 16:43:57 +0800980 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800981}
982
983//----------------------------------------------------------------------
984// Get Debug Frame Data
985//----------------------------------------------------------------------
Patrick Williams010dee02024-08-16 15:19:44 -0400986ipmi_ret_t ipmiOemDbgGetFrameData(
987 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
988 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800989{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700990 uint8_t* req = reinterpret_cast<uint8_t*>(request);
991 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800992 uint8_t frame;
993 uint8_t page;
994 uint8_t next;
995 uint8_t count;
996 int ret;
997
998 frame = req[3];
999 page = req[4];
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001000
1001 ret = plat_udbg_get_frame_data(frame, page, &next, &count, &res[7]);
1002 if (ret)
1003 {
1004 memcpy(res, req, SIZE_IANA_ID); // IANA ID
1005 *data_len = SIZE_IANA_ID;
George Liu2f454992025-07-02 16:43:57 +08001006 return ipmi::ccUnspecifiedError;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001007 }
1008
1009 memcpy(res, req, SIZE_IANA_ID); // IANA ID
1010 res[3] = frame;
1011 res[4] = page;
1012 res[5] = next;
1013 res[6] = count;
1014 *data_len = SIZE_IANA_ID + 4 + count;
1015
George Liu2f454992025-07-02 16:43:57 +08001016 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001017}
1018
1019//----------------------------------------------------------------------
1020// Get Debug Control Panel
1021//----------------------------------------------------------------------
Patrick Williams010dee02024-08-16 15:19:44 -04001022ipmi_ret_t ipmiOemDbgGetCtrlPanel(
1023 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
1024 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001025{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001026 uint8_t* req = reinterpret_cast<uint8_t*>(request);
1027 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001028
1029 uint8_t panel;
1030 uint8_t operation;
1031 uint8_t item;
1032 uint8_t count;
1033 ipmi_ret_t ret;
1034
1035 panel = req[3];
1036 operation = req[4];
1037 item = req[5];
1038
1039 ret = plat_udbg_control_panel(panel, operation, item, &count, &res[3]);
1040
1041 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
1042 *data_len = SIZE_IANA_ID + count;
1043
1044 return ret;
1045}
1046
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001047//----------------------------------------------------------------------
1048// Set Dimm Info (CMD_OEM_SET_DIMM_INFO)
1049//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001050ipmi_ret_t ipmiOemSetDimmInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1051 ipmi_response_t, ipmi_data_len_t data_len,
1052 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001053{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001054 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001055
1056 uint8_t index = req[0];
1057 uint8_t type = req[1];
1058 uint16_t speed;
1059 uint32_t size;
1060
1061 memcpy(&speed, &req[2], 2);
1062 memcpy(&size, &req[4], 4);
1063
1064 std::stringstream ss;
1065 ss << std::hex;
1066 ss << std::setw(2) << std::setfill('0') << (int)index;
1067
1068 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_INDEX] = index;
1069 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_TYPE] = type;
1070 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_SPEED] = speed;
1071 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_SIZE] = size;
1072
1073 flushOemData();
1074
1075 *data_len = 0;
1076
George Liu2f454992025-07-02 16:43:57 +08001077 return ipmi::ccSuccess;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001078}
1079
1080//----------------------------------------------------------------------
1081// Get Board ID (CMD_OEM_GET_BOARD_ID)
1082//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001083ipmi_ret_t ipmiOemGetBoardID(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1084 ipmi_response_t, ipmi_data_len_t data_len,
1085 ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001086{
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001087 /* TODO: Needs to implement this after GPIO implementation */
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001088 *data_len = 0;
1089
George Liu2f454992025-07-02 16:43:57 +08001090 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001091}
1092
Bonnie Lo4ae63e72023-02-09 15:27:54 +08001093//----------------------------------------------------------------------
1094// Get port 80 record (CMD_OEM_GET_80PORT_RECORD)
1095//----------------------------------------------------------------------
Patrick Williams1caf0482025-02-01 08:21:34 -05001096ipmi::RspType<std::vector<uint8_t>> ipmiOemGet80PortRecord(
1097 ipmi::Context::ptr ctx)
Bonnie Lo4ae63e72023-02-09 15:27:54 +08001098{
1099 auto postCodeService = "xyz.openbmc_project.State.Boot.PostCode" +
1100 std::to_string(ctx->hostIdx + 1);
1101 auto postCodeObjPath = "/xyz/openbmc_project/State/Boot/PostCode" +
1102 std::to_string(ctx->hostIdx + 1);
1103 constexpr auto postCodeInterface =
1104 "xyz.openbmc_project.State.Boot.PostCode";
1105 const static uint16_t lastestPostCodeIndex = 1;
1106 constexpr const auto maxPostCodeLen =
1107 224; // The length must be lower than IPMB limitation
1108 size_t startIndex = 0;
1109
1110 std::vector<std::tuple<uint64_t, std::vector<uint8_t>>> postCodes;
1111 std::vector<uint8_t> resData;
1112
1113 auto conn = getSdBus();
1114 /* Get the post codes by calling GetPostCodes method */
Patrick Williams010dee02024-08-16 15:19:44 -04001115 auto msg =
1116 conn->new_method_call(postCodeService.c_str(), postCodeObjPath.c_str(),
1117 postCodeInterface, "GetPostCodes");
Bonnie Lo4ae63e72023-02-09 15:27:54 +08001118 msg.append(lastestPostCodeIndex);
1119
1120 try
1121 {
1122 auto reply = conn->call(msg);
1123 reply.read(postCodes);
1124 }
1125 catch (const sdbusplus::exception::SdBusError& e)
1126 {
1127 phosphor::logging::log<phosphor::logging::level::ERR>(
1128 "IPMI Get80PortRecord Failed in call method",
1129 phosphor::logging::entry("ERROR=%s", e.what()));
1130 return ipmi::responseUnspecifiedError();
1131 }
1132
1133 /* Get post code data */
1134 for (size_t i = 0; i < postCodes.size(); ++i)
1135 {
1136 uint64_t primaryPostCode = std::get<uint64_t>(postCodes[i]);
1137 for (int j = postCodeSize - 1; j >= 0; --j)
1138 {
1139 uint8_t postCode =
1140 ((primaryPostCode >> (sizeof(uint64_t) * j)) & 0xFF);
1141 resData.emplace_back(postCode);
1142 }
1143 }
1144
1145 std::vector<uint8_t> response;
1146 if (resData.size() > maxPostCodeLen)
1147 {
1148 startIndex = resData.size() - maxPostCodeLen;
1149 }
1150
1151 response.assign(resData.begin() + startIndex, resData.end());
1152
1153 return ipmi::responseSuccess(response);
1154}
1155
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001156//----------------------------------------------------------------------
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001157// Set Boot Order (CMD_OEM_SET_BOOT_ORDER)
1158//----------------------------------------------------------------------
Patrick Williams1caf0482025-02-01 08:21:34 -05001159ipmi::RspType<std::vector<uint8_t>> ipmiOemSetBootOrder(
1160 ipmi::Context::ptr ctx, std::vector<uint8_t> bootSeq)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001161{
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001162 size_t len = bootSeq.size();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001163
1164 if (len != SIZE_BOOT_ORDER)
1165 {
1166 phosphor::logging::log<phosphor::logging::level::ERR>(
1167 "Invalid Boot order length received");
Jayashree-Df0cf6652020-11-30 11:03:30 +05301168 return ipmi::responseReqDataLenInvalid();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001169 }
1170
Jayashree Dhanapal4ec80562022-06-28 15:41:47 +05301171 std::optional<size_t> hostId = findHost(ctx->hostIdx);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001172
Jayashree-Df0cf6652020-11-30 11:03:30 +05301173 if (!hostId)
1174 {
1175 phosphor::logging::log<phosphor::logging::level::ERR>(
1176 "Invalid Host Id received");
1177 return ipmi::responseInvalidCommand();
1178 }
1179 auto [bootObjPath, hostName] = ipmi::boot::objPath(*hostId);
1180
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001181 ipmi::boot::setBootOrder(bootObjPath, bootSeq, hostName);
Jayashree-Df0cf6652020-11-30 11:03:30 +05301182
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001183 return ipmi::responseSuccess(bootSeq);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001184}
1185
1186//----------------------------------------------------------------------
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001187// Get Boot Order (CMD_OEM_GET_BOOT_ORDER)
1188//----------------------------------------------------------------------
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001189ipmi::RspType<std::vector<uint8_t>> ipmiOemGetBootOrder(ipmi::Context::ptr ctx)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001190{
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001191 std::vector<uint8_t> bootSeq;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001192
Jayashree Dhanapal4ec80562022-06-28 15:41:47 +05301193 std::optional<size_t> hostId = findHost(ctx->hostIdx);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001194
Jayashree-Df0cf6652020-11-30 11:03:30 +05301195 if (!hostId)
1196 {
1197 phosphor::logging::log<phosphor::logging::level::ERR>(
1198 "Invalid Host Id received");
1199 return ipmi::responseInvalidCommand();
1200 }
1201 auto [bootObjPath, hostName] = ipmi::boot::objPath(*hostId);
1202
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001203 ipmi::boot::getBootOrder(bootObjPath, bootSeq, hostName);
Jayashree-Df0cf6652020-11-30 11:03:30 +05301204
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001205 return ipmi::responseSuccess(bootSeq);
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001206}
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001207// Set Machine Config Info (CMD_OEM_SET_MACHINE_CONFIG_INFO)
1208//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001209ipmi_ret_t ipmiOemSetMachineCfgInfo(ipmi_netfn_t, ipmi_cmd_t,
1210 ipmi_request_t request, ipmi_response_t,
1211 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001212{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001213 machineConfigInfo_t* req = reinterpret_cast<machineConfigInfo_t*>(request);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001214 uint8_t len = *data_len;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001215
1216 *data_len = 0;
1217
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001218 if (len < sizeof(machineConfigInfo_t))
1219 {
1220 phosphor::logging::log<phosphor::logging::level::ERR>(
1221 "Invalid machine configuration length received");
George Liu2f454992025-07-02 16:43:57 +08001222 return ipmi::ccReqDataLenInvalid;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001223 }
1224
Vijay Khemka63c99be2020-05-27 19:14:35 -07001225 if (req->chassis_type >= sizeof(chassisType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001226 oemData[KEY_MC_CONFIG][KEY_MC_CHAS_TYPE] = "UNKNOWN";
1227 else
1228 oemData[KEY_MC_CONFIG][KEY_MC_CHAS_TYPE] =
1229 chassisType[req->chassis_type];
1230
Vijay Khemka63c99be2020-05-27 19:14:35 -07001231 if (req->mb_type >= sizeof(mbType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001232 oemData[KEY_MC_CONFIG][KEY_MC_MB_TYPE] = "UNKNOWN";
1233 else
1234 oemData[KEY_MC_CONFIG][KEY_MC_MB_TYPE] = mbType[req->mb_type];
1235
1236 oemData[KEY_MC_CONFIG][KEY_MC_PROC_CNT] = req->proc_cnt;
1237 oemData[KEY_MC_CONFIG][KEY_MC_MEM_CNT] = req->mem_cnt;
1238 oemData[KEY_MC_CONFIG][KEY_MC_HDD35_CNT] = req->hdd35_cnt;
1239 oemData[KEY_MC_CONFIG][KEY_MC_HDD25_CNT] = req->hdd25_cnt;
1240
Vijay Khemka63c99be2020-05-27 19:14:35 -07001241 if (req->riser_type >= sizeof(riserType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001242 oemData[KEY_MC_CONFIG][KEY_MC_RSR_TYPE] = "UNKNOWN";
1243 else
1244 oemData[KEY_MC_CONFIG][KEY_MC_RSR_TYPE] = riserType[req->riser_type];
1245
1246 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC] = {};
1247 int i = 0;
1248 if (req->pcie_card_loc & BIT_0)
1249 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT1";
1250 if (req->pcie_card_loc & BIT_1)
1251 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT2";
1252 if (req->pcie_card_loc & BIT_2)
1253 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT3";
1254 if (req->pcie_card_loc & BIT_3)
1255 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT4";
1256
Vijay Khemka63c99be2020-05-27 19:14:35 -07001257 if (req->slot1_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001258 oemData[KEY_MC_CONFIG][KEY_MC_SLOT1_TYPE] = "UNKNOWN";
1259 else
1260 oemData[KEY_MC_CONFIG][KEY_MC_SLOT1_TYPE] =
1261 pcieType[req->slot1_pcie_type];
1262
Vijay Khemka63c99be2020-05-27 19:14:35 -07001263 if (req->slot2_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001264 oemData[KEY_MC_CONFIG][KEY_MC_SLOT2_TYPE] = "UNKNOWN";
1265 else
1266 oemData[KEY_MC_CONFIG][KEY_MC_SLOT2_TYPE] =
1267 pcieType[req->slot2_pcie_type];
1268
Vijay Khemka63c99be2020-05-27 19:14:35 -07001269 if (req->slot3_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001270 oemData[KEY_MC_CONFIG][KEY_MC_SLOT3_TYPE] = "UNKNOWN";
1271 else
1272 oemData[KEY_MC_CONFIG][KEY_MC_SLOT3_TYPE] =
1273 pcieType[req->slot3_pcie_type];
1274
Vijay Khemka63c99be2020-05-27 19:14:35 -07001275 if (req->slot4_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001276 oemData[KEY_MC_CONFIG][KEY_MC_SLOT4_TYPE] = "UNKNOWN";
1277 else
1278 oemData[KEY_MC_CONFIG][KEY_MC_SLOT4_TYPE] =
1279 pcieType[req->slot4_pcie_type];
1280
1281 oemData[KEY_MC_CONFIG][KEY_MC_AEP_CNT] = req->aep_mem_cnt;
1282
1283 flushOemData();
1284
George Liu2f454992025-07-02 16:43:57 +08001285 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001286}
1287
1288//----------------------------------------------------------------------
1289// Set POST start (CMD_OEM_SET_POST_START)
1290//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001291ipmi_ret_t ipmiOemSetPostStart(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1292 ipmi_response_t, ipmi_data_len_t data_len,
1293 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001294{
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001295 phosphor::logging::log<phosphor::logging::level::INFO>("POST Start Event");
1296
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001297 /* Do nothing, return success */
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001298 *data_len = 0;
George Liu2f454992025-07-02 16:43:57 +08001299 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001300}
1301
1302//----------------------------------------------------------------------
1303// Set POST End (CMD_OEM_SET_POST_END)
1304//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001305ipmi_ret_t ipmiOemSetPostEnd(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1306 ipmi_response_t, ipmi_data_len_t data_len,
1307 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001308{
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001309 struct timespec ts;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001310
1311 phosphor::logging::log<phosphor::logging::level::INFO>("POST End Event");
1312
1313 *data_len = 0;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001314
1315 // Timestamp post end time.
1316 clock_gettime(CLOCK_REALTIME, &ts);
1317 oemData[KEY_TS_SLED] = ts.tv_sec;
1318 flushOemData();
1319
1320 // Sync time with system
1321 // TODO: Add code for syncing time
1322
George Liu2f454992025-07-02 16:43:57 +08001323 return ipmi::ccSuccess;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001324}
1325
1326//----------------------------------------------------------------------
1327// Set PPIN Info (CMD_OEM_SET_PPIN_INFO)
1328//----------------------------------------------------------------------
1329// Inform BMC about PPIN data of 8 bytes for each CPU
1330//
1331// Request:
1332// Byte 1:8 – CPU0 PPIN data
1333// Optional:
1334// Byte 9:16 – CPU1 PPIN data
1335//
1336// Response:
1337// Byte 1 – Completion Code
Willy Tue39f9392022-06-15 13:24:20 -07001338ipmi_ret_t ipmiOemSetPPINInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1339 ipmi_response_t, ipmi_data_len_t data_len,
1340 ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001341{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001342 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001343 std::string ppinStr;
1344 int len;
1345
1346 if (*data_len > SIZE_CPU_PPIN * 2)
1347 len = SIZE_CPU_PPIN * 2;
1348 else
1349 len = *data_len;
1350 *data_len = 0;
1351
1352 ppinStr = bytesToStr(req, len);
1353 oemData[KEY_PPIN_INFO] = ppinStr.c_str();
1354 flushOemData();
1355
George Liu2f454992025-07-02 16:43:57 +08001356 return ipmi::ccSuccess;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001357}
1358
1359//----------------------------------------------------------------------
1360// Set ADR Trigger (CMD_OEM_SET_ADR_TRIGGER)
1361//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001362ipmi_ret_t ipmiOemSetAdrTrigger(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1363 ipmi_response_t, ipmi_data_len_t data_len,
1364 ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001365{
1366 /* Do nothing, return success */
1367 *data_len = 0;
George Liu2f454992025-07-02 16:43:57 +08001368 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001369}
1370
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001371// Helper function to set guid at offset in EEPROM
Willy Tue39f9392022-06-15 13:24:20 -07001372[[maybe_unused]] static int setGUID(off_t offset, uint8_t* guid)
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001373{
1374 int fd = -1;
1375 ssize_t len;
1376 int ret = 0;
cchouxb2ae88b2023-09-13 00:35:36 +08001377 std::string eepromPath = FRU_EEPROM;
1378
1379 // find the eeprom path of MB FRU
1380 auto device = getMbFruDevice();
1381 if (device)
1382 {
1383 auto [bus, address] = *device;
1384 std::stringstream ss;
1385 ss << "/sys/bus/i2c/devices/" << static_cast<int>(bus) << "-"
1386 << std::setw(4) << std::setfill('0') << std::hex
1387 << static_cast<int>(address) << "/eeprom";
1388 eepromPath = ss.str();
1389 }
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001390
1391 errno = 0;
1392
1393 // Check if file is present
cchouxb2ae88b2023-09-13 00:35:36 +08001394 if (access(eepromPath.c_str(), F_OK) == -1)
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001395 {
cchouxb2ae88b2023-09-13 00:35:36 +08001396 std::cerr << "Unable to access: " << eepromPath << std::endl;
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001397 return errno;
1398 }
1399
1400 // Open the file
cchouxb2ae88b2023-09-13 00:35:36 +08001401 fd = open(eepromPath.c_str(), O_WRONLY);
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001402 if (fd == -1)
1403 {
cchouxb2ae88b2023-09-13 00:35:36 +08001404 std::cerr << "Unable to open: " << eepromPath << std::endl;
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001405 return errno;
1406 }
1407
1408 // seek to the offset
1409 lseek(fd, offset, SEEK_SET);
1410
1411 // Write bytes to location
1412 len = write(fd, guid, GUID_SIZE);
1413 if (len != GUID_SIZE)
1414 {
1415 phosphor::logging::log<phosphor::logging::level::ERR>(
1416 "GUID write data to EEPROM failed");
1417 ret = errno;
1418 }
1419
1420 close(fd);
1421 return ret;
1422}
1423
1424//----------------------------------------------------------------------
1425// Set System GUID (CMD_OEM_SET_SYSTEM_GUID)
1426//----------------------------------------------------------------------
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05301427#if BIC_ENABLED
Bonnie Lo3f671272022-10-12 15:46:45 +08001428ipmi::RspType<> ipmiOemSetSystemGuid(ipmi::Context::ptr ctx,
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05301429 std::vector<uint8_t> reqData)
1430{
1431 std::vector<uint8_t> respData;
1432
1433 if (reqData.size() != GUID_SIZE) // 16bytes
1434 {
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05301435 return ipmi::responseReqDataLenInvalid();
1436 }
1437
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05301438 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
1439
1440 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, reqData, respData))
1441 return ipmi::responseUnspecifiedError();
1442
1443 return ipmi::responseSuccess();
1444}
1445
1446#else
Potin Laid5353ca2022-08-11 04:52:11 +00001447ipmi_ret_t ipmiOemSetSystemGuid(ipmi_netfn_t, ipmi_cmd_t,
1448 ipmi_request_t request, ipmi_response_t,
1449 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001450{
1451 uint8_t* req = reinterpret_cast<uint8_t*>(request);
1452
1453 if (*data_len != GUID_SIZE) // 16bytes
1454 {
1455 *data_len = 0;
George Liu2f454992025-07-02 16:43:57 +08001456 return ipmi::ccReqDataLenInvalid;
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001457 }
1458
1459 *data_len = 0;
1460
1461 if (setGUID(OFFSET_SYS_GUID, req))
1462 {
George Liu2f454992025-07-02 16:43:57 +08001463 return ipmi::ccUnspecifiedError;
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001464 }
George Liu2f454992025-07-02 16:43:57 +08001465 return ipmi::ccSuccess;
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001466}
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05301467#endif
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001468
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001469//----------------------------------------------------------------------
1470// Set Bios Flash Info (CMD_OEM_SET_BIOS_FLASH_INFO)
1471//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001472ipmi_ret_t ipmiOemSetBiosFlashInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1473 ipmi_response_t, ipmi_data_len_t data_len,
1474 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001475{
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001476 /* Do nothing, return success */
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001477 *data_len = 0;
George Liu2f454992025-07-02 16:43:57 +08001478 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001479}
1480
1481//----------------------------------------------------------------------
1482// Set PPR (CMD_OEM_SET_PPR)
1483//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001484ipmi_ret_t ipmiOemSetPpr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1485 ipmi_response_t, ipmi_data_len_t data_len,
1486 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001487{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001488 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001489 uint8_t pprCnt, pprAct, pprIndex;
1490 uint8_t selParam = req[0];
1491 uint8_t len = *data_len;
1492 std::stringstream ss;
1493 std::string str;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001494
1495 *data_len = 0;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001496
1497 switch (selParam)
1498 {
1499 case PPR_ACTION:
1500 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) ==
1501 oemData[KEY_PPR].end())
1502 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1503
1504 pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1505 if (pprCnt == 0)
1506 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1507
1508 pprAct = req[1];
1509 /* Check if ppr is enabled or disabled */
1510 if (!(pprAct & 0x80))
1511 pprAct = 0;
1512
1513 oemData[KEY_PPR][KEY_PPR_ACTION] = pprAct;
1514 break;
1515 case PPR_ROW_COUNT:
1516 if (req[1] > 100)
George Liu2f454992025-07-02 16:43:57 +08001517 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001518
1519 oemData[KEY_PPR][KEY_PPR_ROW_COUNT] = req[1];
1520 break;
1521 case PPR_ROW_ADDR:
1522 pprIndex = req[1];
1523 if (pprIndex > 100)
George Liu2f454992025-07-02 16:43:57 +08001524 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001525
1526 if (len < PPR_ROW_ADDR_LEN + 1)
1527 {
1528 phosphor::logging::log<phosphor::logging::level::ERR>(
1529 "Invalid PPR Row Address length received");
George Liu2f454992025-07-02 16:43:57 +08001530 return ipmi::ccReqDataLenInvalid;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001531 }
1532
1533 ss << std::hex;
1534 ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1535
1536 oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex;
1537
1538 str = bytesToStr(&req[1], PPR_ROW_ADDR_LEN);
1539 oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR] = str.c_str();
1540 break;
1541 case PPR_HISTORY_DATA:
1542 pprIndex = req[1];
1543 if (pprIndex > 100)
George Liu2f454992025-07-02 16:43:57 +08001544 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001545
1546 if (len < PPR_HST_DATA_LEN + 1)
1547 {
1548 phosphor::logging::log<phosphor::logging::level::ERR>(
1549 "Invalid PPR history data length received");
George Liu2f454992025-07-02 16:43:57 +08001550 return ipmi::ccReqDataLenInvalid;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001551 }
1552
1553 ss << std::hex;
1554 ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1555
1556 oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex;
1557
1558 str = bytesToStr(&req[1], PPR_HST_DATA_LEN);
1559 oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA] = str.c_str();
1560 break;
1561 default:
George Liu2f454992025-07-02 16:43:57 +08001562 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001563 break;
1564 }
1565
1566 flushOemData();
1567
George Liu2f454992025-07-02 16:43:57 +08001568 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001569}
1570
1571//----------------------------------------------------------------------
1572// Get PPR (CMD_OEM_GET_PPR)
1573//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001574ipmi_ret_t ipmiOemGetPpr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1575 ipmi_response_t response, ipmi_data_len_t data_len,
1576 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001577{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001578 uint8_t* req = reinterpret_cast<uint8_t*>(request);
1579 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001580 uint8_t pprCnt, pprIndex;
1581 uint8_t selParam = req[0];
1582 std::stringstream ss;
1583 std::string str;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001584
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001585 /* Any failure will return zero length data */
1586 *data_len = 0;
1587
1588 switch (selParam)
1589 {
1590 case PPR_ACTION:
1591 res[0] = 0;
1592 *data_len = 1;
1593
1594 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) !=
1595 oemData[KEY_PPR].end())
1596 {
1597 pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1598 if (pprCnt != 0)
1599 {
1600 if (oemData[KEY_PPR].find(KEY_PPR_ACTION) !=
1601 oemData[KEY_PPR].end())
1602 {
1603 res[0] = oemData[KEY_PPR][KEY_PPR_ACTION];
1604 }
1605 }
1606 }
1607 break;
1608 case PPR_ROW_COUNT:
1609 res[0] = 0;
1610 *data_len = 1;
1611 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) !=
1612 oemData[KEY_PPR].end())
1613 res[0] = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1614 break;
1615 case PPR_ROW_ADDR:
1616 pprIndex = req[1];
1617 if (pprIndex > 100)
George Liu2f454992025-07-02 16:43:57 +08001618 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001619
1620 ss << std::hex;
1621 ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1622
1623 if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end())
George Liu2f454992025-07-02 16:43:57 +08001624 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001625
1626 if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_ROW_ADDR) ==
1627 oemData[KEY_PPR][ss.str()].end())
George Liu2f454992025-07-02 16:43:57 +08001628 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001629
1630 str = oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR];
1631 *data_len = strToBytes(str, res);
1632 break;
1633 case PPR_HISTORY_DATA:
1634 pprIndex = req[1];
1635 if (pprIndex > 100)
George Liu2f454992025-07-02 16:43:57 +08001636 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001637
1638 ss << std::hex;
1639 ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1640
1641 if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end())
George Liu2f454992025-07-02 16:43:57 +08001642 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001643
1644 if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_HST_DATA) ==
1645 oemData[KEY_PPR][ss.str()].end())
George Liu2f454992025-07-02 16:43:57 +08001646 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001647
1648 str = oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA];
1649 *data_len = strToBytes(str, res);
1650 break;
1651 default:
George Liu2f454992025-07-02 16:43:57 +08001652 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001653 break;
1654 }
1655
George Liu2f454992025-07-02 16:43:57 +08001656 return ipmi::ccSuccess;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001657}
1658
1659/* FB OEM QC Commands */
1660
1661//----------------------------------------------------------------------
1662// Set Proc Info (CMD_OEM_Q_SET_PROC_INFO)
1663//----------------------------------------------------------------------
1664//"Request:
1665// Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first
1666// Byte 4 – Processor Index, 0 base
1667// Byte 5 – Parameter Selector
1668// Byte 6..N – Configuration parameter data (see below for Parameters
1669// of Processor Information)
1670// Response:
1671// Byte 1 – Completion code
1672//
1673// Parameter#1: (Processor Product Name)
1674//
1675// Byte 1..48 –Product name(ASCII code)
1676// Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz
1677//
1678// Param#2: Processor Basic Information
1679// Byte 1 – Core Number
1680// Byte 2 – Thread Number (LSB)
1681// Byte 3 – Thread Number (MSB)
1682// Byte 4 – Processor frequency in MHz (LSB)
1683// Byte 5 – Processor frequency in MHz (MSB)
1684// Byte 6..7 – Revision
1685//
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301686
Patrick Williams010dee02024-08-16 15:19:44 -04001687ipmi::RspType<> ipmiOemQSetProcInfo(
1688 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t procIndex,
1689 uint8_t paramSel, std::vector<uint8_t> request)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001690{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001691 uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001692 std::stringstream ss;
1693 std::string str;
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301694 uint8_t len = request.size();
1695 auto hostId = findHost(ctx->hostIdx);
1696 if (!hostId)
1697 {
1698 phosphor::logging::log<phosphor::logging::level::ERR>(
1699 "Invalid Host Id received");
1700 return ipmi::responseInvalidCommand();
1701 }
1702 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(*hostId);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001703 /* check for requested data params */
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301704 if (len < 5 || paramSel < 1 || paramSel >= numParam)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001705 {
1706 phosphor::logging::log<phosphor::logging::level::ERR>(
1707 "Invalid parameter received");
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301708 return ipmi::responseParmOutOfRange();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001709 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001710 ss << std::hex;
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301711 ss << std::setw(2) << std::setfill('0') << (int)procIndex;
1712 oemData[procInfo][ss.str()][KEY_PROC_INDEX] = procIndex;
1713 str = bytesToStr(request.data(), len);
1714 oemData[procInfo][ss.str()][cpuInfoKey[paramSel]] = str.c_str();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001715 flushOemData();
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301716 return ipmi::responseSuccess();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001717}
1718
1719//----------------------------------------------------------------------
1720// Get Proc Info (CMD_OEM_Q_GET_PROC_INFO)
1721//----------------------------------------------------------------------
1722// Request:
1723// Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first
1724// Byte 4 – Processor Index, 0 base
1725// Byte 5 – Parameter Selector
1726// Response:
1727// Byte 1 – Completion code
1728// Byte 2..N – Configuration Parameter Data (see below for Parameters
1729// of Processor Information)
1730//
1731// Parameter#1: (Processor Product Name)
1732//
1733// Byte 1..48 –Product name(ASCII code)
1734// Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz
1735//
1736// Param#2: Processor Basic Information
1737// Byte 1 – Core Number
1738// Byte 2 – Thread Number (LSB)
1739// Byte 3 – Thread Number (MSB)
1740// Byte 4 – Processor frequency in MHz (LSB)
1741// Byte 5 – Processor frequency in MHz (MSB)
1742// Byte 6..7 – Revision
1743//
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301744
Patrick Williams1caf0482025-02-01 08:21:34 -05001745ipmi::RspType<std::vector<uint8_t>> ipmiOemQGetProcInfo(
1746 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t procIndex,
1747 uint8_t paramSel)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001748{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001749 uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001750 std::stringstream ss;
1751 std::string str;
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301752 uint8_t res[MAX_BUF];
1753 auto hostId = findHost(ctx->hostIdx);
1754 if (!hostId)
1755 {
1756 phosphor::logging::log<phosphor::logging::level::ERR>(
1757 "Invalid Host Id received");
1758 return ipmi::responseInvalidCommand();
1759 }
1760 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(*hostId);
1761 if (paramSel < 1 || paramSel >= numParam)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001762 {
1763 phosphor::logging::log<phosphor::logging::level::ERR>(
1764 "Invalid parameter received");
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301765 return ipmi::responseParmOutOfRange();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001766 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001767 ss << std::hex;
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301768 ss << std::setw(2) << std::setfill('0') << (int)procIndex;
1769 if (oemData[procInfo].find(ss.str()) == oemData[procInfo].end())
1770 return ipmi::responseCommandNotAvailable();
1771 if (oemData[procInfo][ss.str()].find(cpuInfoKey[paramSel]) ==
1772 oemData[procInfo][ss.str()].end())
1773 return ipmi::responseCommandNotAvailable();
1774 str = oemData[procInfo][ss.str()][cpuInfoKey[paramSel]];
1775 int dataLen = strToBytes(str, res);
1776 std::vector<uint8_t> response(&res[0], &res[dataLen]);
1777 return ipmi::responseSuccess(response);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001778}
1779
1780//----------------------------------------------------------------------
1781// Set Dimm Info (CMD_OEM_Q_SET_DIMM_INFO)
1782//----------------------------------------------------------------------
1783// Request:
1784// Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first
1785// Byte 4 – DIMM Index, 0 base
1786// Byte 5 – Parameter Selector
1787// Byte 6..N – Configuration parameter data (see below for Parameters
1788// of DIMM Information)
1789// Response:
1790// Byte 1 – Completion code
1791//
1792// Param#1 (DIMM Location):
1793// Byte 1 – DIMM Present
1794// Byte 1 – DIMM Present
1795// 01h – Present
1796// FFh – Not Present
1797// Byte 2 – Node Number, 0 base
1798// Byte 3 – Channel Number , 0 base
1799// Byte 4 – DIMM Number , 0 base
1800//
1801// Param#2 (DIMM Type):
1802// Byte 1 – DIMM Type
1803// Bit [7:6]
1804// For DDR3
1805// 00 – Normal Voltage (1.5V)
1806// 01 – Ultra Low Voltage (1.25V)
1807// 10 – Low Voltage (1.35V)
1808// 11 – Reserved
1809// For DDR4
1810// 00 – Reserved
1811// 01 – Reserved
1812// 10 – Reserved
1813// 11 – Normal Voltage (1.2V)
1814// Bit [5:0]
1815// 0x00 – SDRAM
1816// 0x01 – DDR-1 RAM
1817// 0x02 – Rambus
1818// 0x03 – DDR-2 RAM
1819// 0x04 – FBDIMM
1820// 0x05 – DDR-3 RAM
1821// 0x06 – DDR-4 RAM
1822//
1823// Param#3 (DIMM Speed):
1824// Byte 1..2 – DIMM speed in MHz, LSB
1825// Byte 3..6 – DIMM size in Mbytes, LSB
1826//
1827// Param#4 (Module Part Number):
1828// Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C)
1829//
1830// Param#5 (Module Serial Number):
1831// Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C)
1832//
1833// Param#6 (Module Manufacturer ID):
1834// Byte 1 - Module Manufacturer ID, LSB
1835// Byte 2 - Module Manufacturer ID, MSB
1836//
Patrick Williams010dee02024-08-16 15:19:44 -04001837ipmi::RspType<> ipmiOemQSetDimmInfo(
1838 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t dimmIndex,
1839 uint8_t paramSel, std::vector<uint8_t> request)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001840{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001841 uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001842 std::stringstream ss;
1843 std::string str;
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301844 uint8_t len = request.size();
1845 std::string dimmType;
1846 readDimmType(dimmType, dimmIndex);
Patrick Williams6d9e9a72022-07-18 10:30:50 -05001847 auto hostId = findHost(ctx->hostIdx);
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301848 if (!hostId)
1849 {
1850 phosphor::logging::log<phosphor::logging::level::ERR>(
1851 "Invalid Host Id received");
1852 return ipmi::responseInvalidCommand();
1853 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001854
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301855 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(*hostId);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001856
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301857 if (len < 3 || paramSel < 1 || paramSel >= numParam)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001858 {
1859 phosphor::logging::log<phosphor::logging::level::ERR>(
1860 "Invalid parameter received");
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301861 return ipmi::responseParmOutOfRange();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001862 }
1863
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001864 ss << std::hex;
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301865 ss << (int)dimmIndex;
1866 oemData[dimmInfo][ss.str()][KEY_DIMM_INDEX] = dimmIndex;
1867 oemData[dimmInfo][ss.str()][KEY_DIMM_TYPE] = dimmType;
1868 str = bytesToStr(request.data(), len);
1869 oemData[dimmInfo][ss.str()][dimmInfoKey[paramSel]] = str.c_str();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001870 flushOemData();
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301871 return ipmi::responseSuccess();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001872}
1873
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001874// Get Dimm Info (CMD_OEM_Q_GET_DIMM_INFO)
1875//----------------------------------------------------------------------
1876// Request:
1877// Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first
1878// Byte 4 – DIMM Index, 0 base
1879// Byte 5 – Parameter Selector
1880// Byte 6..N – Configuration parameter data (see below for Parameters
1881// of DIMM Information)
1882// Response:
1883// Byte 1 – Completion code
1884// Byte 2..N – Configuration Parameter Data (see Table_1213h Parameters
1885// of DIMM Information)
1886//
1887// Param#1 (DIMM Location):
1888// Byte 1 – DIMM Present
1889// Byte 1 – DIMM Present
1890// 01h – Present
1891// FFh – Not Present
1892// Byte 2 – Node Number, 0 base
1893// Byte 3 – Channel Number , 0 base
1894// Byte 4 – DIMM Number , 0 base
1895//
1896// Param#2 (DIMM Type):
1897// Byte 1 – DIMM Type
1898// Bit [7:6]
1899// For DDR3
1900// 00 – Normal Voltage (1.5V)
1901// 01 – Ultra Low Voltage (1.25V)
1902// 10 – Low Voltage (1.35V)
1903// 11 – Reserved
1904// For DDR4
1905// 00 – Reserved
1906// 01 – Reserved
1907// 10 – Reserved
1908// 11 – Normal Voltage (1.2V)
1909// Bit [5:0]
1910// 0x00 – SDRAM
1911// 0x01 – DDR-1 RAM
1912// 0x02 – Rambus
1913// 0x03 – DDR-2 RAM
1914// 0x04 – FBDIMM
1915// 0x05 – DDR-3 RAM
1916// 0x06 – DDR-4 RAM
1917//
1918// Param#3 (DIMM Speed):
1919// Byte 1..2 – DIMM speed in MHz, LSB
1920// Byte 3..6 – DIMM size in Mbytes, LSB
1921//
1922// Param#4 (Module Part Number):
1923// Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C)
1924//
1925// Param#5 (Module Serial Number):
1926// Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C)
1927//
1928// Param#6 (Module Manufacturer ID):
1929// Byte 1 - Module Manufacturer ID, LSB
1930// Byte 2 - Module Manufacturer ID, MSB
1931//
Patrick Williams1caf0482025-02-01 08:21:34 -05001932ipmi::RspType<std::vector<uint8_t>> ipmiOemQGetDimmInfo(
1933 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t dimmIndex,
1934 uint8_t paramSel)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001935{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001936 uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*);
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301937 uint8_t res[MAX_BUF];
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001938 std::stringstream ss;
1939 std::string str;
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301940 std::string dimmType;
1941 readDimmType(dimmType, dimmIndex);
Patrick Williams6d9e9a72022-07-18 10:30:50 -05001942 auto hostId = findHost(ctx->hostIdx);
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301943 if (!hostId)
1944 {
1945 phosphor::logging::log<phosphor::logging::level::ERR>(
1946 "Invalid Host Id received");
1947 return ipmi::responseInvalidCommand();
1948 }
1949 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(*hostId);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001950
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301951 if (paramSel < 1 || paramSel >= numParam)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001952 {
1953 phosphor::logging::log<phosphor::logging::level::ERR>(
1954 "Invalid parameter received");
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301955 return ipmi::responseParmOutOfRange();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001956 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001957 ss << std::hex;
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301958 ss << (int)dimmIndex;
1959 oemData[dimmInfo][ss.str()][KEY_DIMM_TYPE] = dimmType;
1960 if (oemData[dimmInfo].find(ss.str()) == oemData[dimmInfo].end())
1961 return ipmi::responseCommandNotAvailable();
1962 if (oemData[dimmInfo][ss.str()].find(dimmInfoKey[paramSel]) ==
1963 oemData[dimmInfo][ss.str()].end())
1964 return ipmi::responseCommandNotAvailable();
1965 str = oemData[dimmInfo][ss.str()][dimmInfoKey[paramSel]];
1966 int data_length = strToBytes(str, res);
1967 std::vector<uint8_t> response(&res[0], &res[data_length]);
1968 return ipmi::responseSuccess(response);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001969}
1970
1971//----------------------------------------------------------------------
1972// Set Drive Info (CMD_OEM_Q_SET_DRIVE_INFO)
1973//----------------------------------------------------------------------
1974// BIOS issue this command to provide HDD information to BMC.
1975//
1976// BIOS just can get information by standard ATA / SMART command for
1977// OB SATA controller.
1978// BIOS can get
1979// 1. Serial Number
1980// 2. Model Name
1981// 3. HDD FW Version
1982// 4. HDD Capacity
1983// 5. HDD WWN
1984//
1985// Use Get HDD info Param #5 to know the MAX HDD info index.
1986//
1987// Request:
1988// Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first
1989// Byte 4 –
1990// [7:4] Reserved
1991// [3:0] HDD Controller Type
1992// 0x00 – BIOS
1993// 0x01 – Expander
1994// 0x02 – LSI
1995// Byte 5 – HDD Info Index, 0 base
1996// Byte 6 – Parameter Selector
1997// Byte 7..N – Configuration parameter data (see Table_1415h Parameters of HDD
1998// Information)
1999//
2000// Response:
2001// Byte 1 – Completion Code
2002//
2003// Param#0 (HDD Location):
2004// Byte 1 – Controller
2005// [7:3] Device Number
2006// [2:0] Function Number
2007// For Intel C610 series (Wellsburg)
2008// D31:F2 (0xFA) – SATA control 1
2009// D31:F5 (0xFD) – SATA control 2
2010// D17:F4 (0x8C) – sSata control
2011// Byte 2 – Port Number
2012// Byte 3 – Location (0xFF: No HDD Present)
2013// BIOS default set Byte 3 to 0xFF, if No HDD Present. And then skip send param
2014// #1~4, #6, #7 to BMC (still send param #5) BIOS default set Byte 3 to 0, if
2015// the HDD present. BMC or other people who know the HDD location has
2016// responsibility for update Location info
2017//
2018// Param#1 (Serial Number):
2019// Bytes 1..33: HDD Serial Number
2020//
2021// Param#2 (Model Name):
2022// Byte 1..33 – HDD Model Name
2023//
2024// Param#3 (HDD FW Version):
2025// Byte 1..17 –HDD FW version
2026//
2027// Param#4 (Capacity):
2028// Byte 1..4 –HDD Block Size, LSB
2029// Byte 5..12 - HDD Block Number, LSB
2030// HDD Capacity = HDD Block size * HDD BLock number (Unit Byte)
2031//
2032// Param#5 (Max HDD Quantity):
2033// Byte 1 - Max HDD Quantity
2034// Max supported port numbers in this PCH
2035//
2036// Param#6 (HDD Type)
2037// Byte 1 – HDD Type
2038// 0h – Reserved
2039// 1h – SAS
2040// 2h – SATA
2041// 3h – PCIE SSD (NVME)
2042//
2043// Param#7 (HDD WWN)
2044// Data 1...8: HDD World Wide Name, LSB
2045//
Willy Tue39f9392022-06-15 13:24:20 -07002046ipmi_ret_t ipmiOemQSetDriveInfo(ipmi_netfn_t, ipmi_cmd_t,
2047 ipmi_request_t request, ipmi_response_t,
2048 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002049{
Vijay Khemka63c99be2020-05-27 19:14:35 -07002050 qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request);
2051 uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002052 uint8_t ctrlType = req->hddCtrlType & 0x0f;
2053 std::stringstream ss;
2054 std::string str;
2055 uint8_t len = *data_len;
2056
2057 *data_len = 0;
2058
2059 /* check for requested data params */
Bruce Hungb445feb2025-07-17 17:36:25 +08002060 if (len < 6 || req->paramSel >= numParam || ctrlType > 2)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002061 {
2062 phosphor::logging::log<phosphor::logging::level::ERR>(
2063 "Invalid parameter received");
George Liu2f454992025-07-02 16:43:57 +08002064 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002065 }
2066
2067 len = len - 6; // Get Actual data length
2068
2069 ss << std::hex;
2070 ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex;
2071 oemData[KEY_Q_DRIVE_INFO][KEY_HDD_CTRL_TYPE] = req->hddCtrlType;
2072 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()][KEY_HDD_INDEX] =
2073 req->hddIndex;
2074
2075 str = bytesToStr(req->data, len);
2076 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()]
2077 [driveInfoKey[req->paramSel]] = str.c_str();
2078 flushOemData();
2079
George Liu2f454992025-07-02 16:43:57 +08002080 return ipmi::ccSuccess;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002081}
2082
2083//----------------------------------------------------------------------
2084// Get Drive Info (CMD_OEM_Q_GET_DRIVE_INFO)
2085//----------------------------------------------------------------------
2086// BMC needs to check HDD presented or not first. If NOT presented, return
2087// completion code 0xD5.
2088//
2089// Request:
2090// Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first
2091// Byte 4 –
2092//[7:4] Reserved
2093//[3:0] HDD Controller Type
2094// 0x00 – BIOS
2095// 0x01 – Expander
2096// 0x02 – LSI
2097// Byte 5 – HDD Index, 0 base
2098// Byte 6 – Parameter Selector (See Above Set HDD Information)
2099// Response:
2100// Byte 1 – Completion Code
2101// 0xD5 – Not support in current status (HDD Not Present)
2102// Byte 2..N – Configuration parameter data (see Table_1415h Parameters of HDD
2103// Information)
2104//
Patrick Williams010dee02024-08-16 15:19:44 -04002105ipmi_ret_t ipmiOemQGetDriveInfo(
2106 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
2107 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002108{
Vijay Khemka63c99be2020-05-27 19:14:35 -07002109 qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request);
2110 uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*);
2111 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002112 uint8_t ctrlType = req->hddCtrlType & 0x0f;
2113 std::stringstream ss;
2114 std::string str;
2115
2116 *data_len = 0;
2117
2118 /* check for requested data params */
Bruce Hungb445feb2025-07-17 17:36:25 +08002119 if (req->paramSel >= numParam || ctrlType > 2)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002120 {
2121 phosphor::logging::log<phosphor::logging::level::ERR>(
2122 "Invalid parameter received");
George Liu2f454992025-07-02 16:43:57 +08002123 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002124 }
2125
2126 if (oemData[KEY_Q_DRIVE_INFO].find(ctrlTypeKey[ctrlType]) ==
2127 oemData[KEY_Q_DRIVE_INFO].end())
2128 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2129
2130 ss << std::hex;
2131 ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex;
2132
2133 if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]].find(ss.str()) ==
Bruce Hungb445feb2025-07-17 17:36:25 +08002134 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]].end())
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002135 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2136
2137 if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()].find(
Bruce Hungb445feb2025-07-17 17:36:25 +08002138 driveInfoKey[req->paramSel]) ==
2139 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()].end())
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002140 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2141
2142 str = oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()]
Bruce Hungb445feb2025-07-17 17:36:25 +08002143 [driveInfoKey[req->paramSel]];
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002144 *data_len = strToBytes(str, res);
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002145
George Liu2f454992025-07-02 16:43:57 +08002146 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002147}
2148
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302149/* Helper function for sending DCMI commands to ME/BIC and
2150 * getting response back
2151 */
Patrick Williams1caf0482025-02-01 08:21:34 -05002152ipmi::RspType<std::vector<uint8_t>> sendDCMICmd(
2153 [[maybe_unused]] ipmi::Context::ptr ctx, [[maybe_unused]] uint8_t cmd,
2154 std::vector<uint8_t>& cmdData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002155{
2156 std::vector<uint8_t> respData;
2157
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302158#if BIC_ENABLED
2159
2160 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
2161
2162 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, cmdData, respData))
2163 {
2164 return ipmi::responseUnspecifiedError();
2165 }
2166
2167#else
2168
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002169 /* Add group id as first byte to request for ME command */
2170 cmdData.insert(cmdData.begin(), groupDCMI);
2171
2172 if (sendMeCmd(ipmi::netFnGroup, cmd, cmdData, respData))
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302173 {
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002174 return ipmi::responseUnspecifiedError();
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302175 }
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002176
2177 /* Remove group id as first byte as it will be added by IPMID */
2178 respData.erase(respData.begin());
2179
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302180#endif
2181
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002182 return ipmi::responseSuccess(std::move(respData));
2183}
2184
2185/* DCMI Command handellers. */
2186
Patrick Williams010dee02024-08-16 15:19:44 -04002187ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMIGetPowerReading(
2188 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002189{
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302190 return sendDCMICmd(ctx, ipmi::dcmi::cmdGetPowerReading, reqData);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002191}
2192
Patrick Williams010dee02024-08-16 15:19:44 -04002193ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMIGetPowerLimit(
2194 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002195{
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302196 return sendDCMICmd(ctx, ipmi::dcmi::cmdGetPowerLimit, reqData);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002197}
2198
Patrick Williams010dee02024-08-16 15:19:44 -04002199ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMISetPowerLimit(
2200 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002201{
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302202 return sendDCMICmd(ctx, ipmi::dcmi::cmdSetPowerLimit, reqData);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002203}
2204
Patrick Williams010dee02024-08-16 15:19:44 -04002205ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMIApplyPowerLimit(
2206 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002207{
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302208 return sendDCMICmd(ctx, ipmi::dcmi::cmdActDeactivatePwrLimit, reqData);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002209}
2210
Cosmo Chou99d42b62024-08-15 10:42:47 +08002211// Https Boot related functions
Patrick Williams010dee02024-08-16 15:19:44 -04002212ipmi::RspType<std::vector<uint8_t>> ipmiOemGetHttpsData(
2213 [[maybe_unused]] ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Cosmo Chou99d42b62024-08-15 10:42:47 +08002214{
2215 if (reqData.size() < sizeof(HttpsDataReq))
2216 return ipmi::responseReqDataLenInvalid();
2217
2218 const auto* pReq = reinterpret_cast<const HttpsDataReq*>(reqData.data());
2219 std::error_code ec;
2220 auto fileSize = std::filesystem::file_size(certPath, ec);
2221 if (ec)
2222 return ipmi::responseUnspecifiedError();
2223
2224 if (pReq->offset >= fileSize)
2225 return ipmi::responseInvalidFieldRequest();
2226
2227 std::ifstream file(certPath, std::ios::binary);
2228 if (!file)
2229 return ipmi::responseUnspecifiedError();
2230
2231 auto readLen = std::min<uint16_t>(pReq->length, fileSize - pReq->offset);
2232 std::vector<uint8_t> resData(readLen + 1);
2233 resData[0] = readLen;
2234 file.seekg(pReq->offset);
2235 file.read(reinterpret_cast<char*>(resData.data() + 1), readLen);
2236
2237 return ipmi::responseSuccess(resData);
2238}
2239
Patrick Williams010dee02024-08-16 15:19:44 -04002240ipmi::RspType<std::vector<uint8_t>> ipmiOemGetHttpsAttr(
2241 [[maybe_unused]] ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Cosmo Chou99d42b62024-08-15 10:42:47 +08002242{
2243 if (reqData.size() < sizeof(HttpsBootAttr))
2244 return ipmi::responseReqDataLenInvalid();
2245
2246 std::vector<uint8_t> resData;
2247
2248 switch (static_cast<HttpsBootAttr>(reqData[0]))
2249 {
2250 case HttpsBootAttr::certSize:
2251 {
2252 std::error_code ec;
2253 auto fileSize = std::filesystem::file_size(certPath, ec);
2254 if (ec || fileSize > std::numeric_limits<uint16_t>::max())
2255 return ipmi::responseUnspecifiedError();
2256
2257 uint16_t size = static_cast<uint16_t>(fileSize);
2258 resData.resize(sizeof(uint16_t));
2259 std::memcpy(resData.data(), &size, sizeof(uint16_t));
2260 break;
2261 }
2262 case HttpsBootAttr::certCrc:
2263 {
2264 std::ifstream file(certPath, std::ios::binary);
2265 if (!file)
2266 return ipmi::responseUnspecifiedError();
2267
2268 boost::crc_32_type result;
2269 char data[1024];
2270 while (file.read(data, sizeof(data)))
2271 result.process_bytes(data, file.gcount());
2272 if (file.gcount() > 0)
2273 result.process_bytes(data, file.gcount());
2274
2275 uint32_t crc = result.checksum();
2276 resData.resize(sizeof(uint32_t));
2277 std::memcpy(resData.data(), &crc, sizeof(uint32_t));
2278 break;
2279 }
2280 default:
2281 return ipmi::responseInvalidFieldRequest();
2282 }
2283
2284 return ipmi::responseSuccess(resData);
2285}
2286
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002287// OEM Crashdump related functions
2288static ipmi_ret_t setDumpState(CrdState& currState, CrdState newState)
2289{
2290 switch (newState)
2291 {
2292 case CrdState::waitData:
2293 if (currState == CrdState::packing)
2294 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2295 break;
2296 case CrdState::packing:
2297 if (currState != CrdState::waitData)
2298 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2299 break;
2300 case CrdState::free:
2301 break;
2302 default:
George Liu2f454992025-07-02 16:43:57 +08002303 return ipmi::ccUnspecifiedError;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002304 }
2305 currState = newState;
2306
George Liu2f454992025-07-02 16:43:57 +08002307 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002308}
2309
2310static ipmi_ret_t handleMcaBank(const CrashDumpHdr& hdr,
2311 std::span<const uint8_t> data,
2312 CrdState& currState, std::stringstream& ss)
2313{
2314 if (data.size() < sizeof(CrdMcaBank))
George Liu2f454992025-07-02 16:43:57 +08002315 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002316
2317 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2318 if (res)
2319 return res;
2320
2321 const auto* pBank = reinterpret_cast<const CrdMcaBank*>(data.data());
2322 ss << std::format(" Bank ID : 0x{:02X}, Core ID : 0x{:02X}\n",
2323 hdr.bankHdr.bankId, hdr.bankHdr.coreId);
2324 ss << std::format(" MCA_CTRL : 0x{:016X}\n", pBank->mcaCtrl);
2325 ss << std::format(" MCA_STATUS : 0x{:016X}\n", pBank->mcaSts);
2326 ss << std::format(" MCA_ADDR : 0x{:016X}\n", pBank->mcaAddr);
2327 ss << std::format(" MCA_MISC0 : 0x{:016X}\n", pBank->mcaMisc0);
2328 ss << std::format(" MCA_CTRL_MASK : 0x{:016X}\n", pBank->mcaCtrlMask);
2329 ss << std::format(" MCA_CONFIG : 0x{:016X}\n", pBank->mcaConfig);
2330 ss << std::format(" MCA_IPID : 0x{:016X}\n", pBank->mcaIpid);
2331 ss << std::format(" MCA_SYND : 0x{:016X}\n", pBank->mcaSynd);
2332 ss << std::format(" MCA_DESTAT : 0x{:016X}\n", pBank->mcaDestat);
2333 ss << std::format(" MCA_DEADDR : 0x{:016X}\n", pBank->mcaDeaddr);
2334 ss << std::format(" MCA_MISC1 : 0x{:016X}\n", pBank->mcaMisc1);
2335 ss << "\n";
2336
George Liu2f454992025-07-02 16:43:57 +08002337 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002338}
2339
2340template <typename T>
2341static ipmi_ret_t handleVirtualBank(std::span<const uint8_t> data,
2342 CrdState& currState, std::stringstream& ss)
2343{
2344 if (data.size() < sizeof(T))
George Liu2f454992025-07-02 16:43:57 +08002345 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002346
2347 const auto* pBank = reinterpret_cast<const T*>(data.data());
2348
2349 if (data.size() < sizeof(T) + sizeof(BankCorePair) * pBank->mcaCount)
George Liu2f454992025-07-02 16:43:57 +08002350 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002351
2352 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2353 if (res)
2354 return res;
2355
2356 ss << " Virtual Bank\n";
2357 ss << std::format(" S5_RESET_STATUS : 0x{:08X}\n", pBank->s5ResetSts);
2358 ss << std::format(" PM_BREAKEVENT : 0x{:08X}\n", pBank->breakevent);
2359 if constexpr (std::is_same_v<T, CrdVirtualBankV3>)
2360 {
2361 ss << std::format(" WARMCOLDRSTSTATUS : 0x{:08X}\n", pBank->rstSts);
2362 }
2363 ss << std::format(" PROCESSOR NUMBER : 0x{:04X}\n", pBank->procNum);
2364 ss << std::format(" APIC ID : 0x{:08X}\n", pBank->apicId);
2365 ss << std::format(" EAX : 0x{:08X}\n", pBank->eax);
2366 ss << std::format(" EBX : 0x{:08X}\n", pBank->ebx);
2367 ss << std::format(" ECX : 0x{:08X}\n", pBank->ecx);
2368 ss << std::format(" EDX : 0x{:08X}\n", pBank->edx);
2369 ss << " VALID LIST : ";
2370 for (size_t i = 0; i < pBank->mcaCount; i++)
2371 {
2372 ss << std::format("(0x{:02X},0x{:02X}) ", pBank->mcaList[i].bankId,
2373 pBank->mcaList[i].coreId);
2374 }
2375 ss << "\n\n";
2376
George Liu2f454992025-07-02 16:43:57 +08002377 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002378}
2379
2380static ipmi_ret_t handleCpuWdtBank(std::span<const uint8_t> data,
2381 CrdState& currState, std::stringstream& ss)
2382{
2383 if (data.size() < sizeof(CrdCpuWdtBank))
George Liu2f454992025-07-02 16:43:57 +08002384 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002385
2386 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2387 if (res)
2388 return res;
2389
2390 const auto* pBank = reinterpret_cast<const CrdCpuWdtBank*>(data.data());
2391 for (size_t i = 0; i < ccmNum; i++)
2392 {
2393 ss << std::format(" [CCM{}]\n", i);
2394 ss << std::format(" HwAssertStsHi : 0x{:08X}\n",
2395 pBank->hwAssertStsHi[i]);
2396 ss << std::format(" HwAssertStsLo : 0x{:08X}\n",
2397 pBank->hwAssertStsLo[i]);
2398 ss << std::format(" OrigWdtAddrLogHi : 0x{:08X}\n",
2399 pBank->origWdtAddrLogHi[i]);
2400 ss << std::format(" OrigWdtAddrLogLo : 0x{:08X}\n",
2401 pBank->origWdtAddrLogLo[i]);
2402 ss << std::format(" HwAssertMskHi : 0x{:08X}\n",
2403 pBank->hwAssertMskHi[i]);
2404 ss << std::format(" HwAssertMskLo : 0x{:08X}\n",
2405 pBank->hwAssertMskLo[i]);
2406 ss << std::format(" OrigWdtAddrLogStat : 0x{:08X}\n",
2407 pBank->origWdtAddrLogStat[i]);
2408 }
2409 ss << "\n";
2410
George Liu2f454992025-07-02 16:43:57 +08002411 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002412}
2413
2414template <size_t N>
Patrick Williams1caf0482025-02-01 08:21:34 -05002415static ipmi_ret_t handleHwAssertBank(const char* name,
2416 std::span<const uint8_t> data,
2417 CrdState& currState, std::stringstream& ss)
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002418{
2419 if (data.size() < sizeof(CrdHwAssertBank<N>))
George Liu2f454992025-07-02 16:43:57 +08002420 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002421
2422 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2423 if (res)
2424 return res;
2425
2426 const CrdHwAssertBank<N>* pBank =
2427 reinterpret_cast<const CrdHwAssertBank<N>*>(data.data());
2428
2429 for (size_t i = 0; i < N; i++)
2430 {
2431 ss << std::format(" [{}{}]\n", name, i);
2432 ss << std::format(" HwAssertStsHi : 0x{:08X}\n",
2433 pBank->hwAssertStsHi[i]);
2434 ss << std::format(" HwAssertStsLo : 0x{:08X}\n",
2435 pBank->hwAssertStsLo[i]);
2436 ss << std::format(" HwAssertMskHi : 0x{:08X}\n",
2437 pBank->hwAssertMskHi[i]);
2438 ss << std::format(" HwAssertMskLo : 0x{:08X}\n",
2439 pBank->hwAssertMskLo[i]);
2440 }
2441 ss << "\n";
2442
George Liu2f454992025-07-02 16:43:57 +08002443 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002444}
2445
2446static ipmi_ret_t handlePcieAerBank(std::span<const uint8_t> data,
2447 CrdState& currState, std::stringstream& ss)
2448{
2449 if (data.size() < sizeof(CrdPcieAerBank))
George Liu2f454992025-07-02 16:43:57 +08002450 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002451
2452 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2453 if (res)
2454 return res;
2455
2456 const auto* pBank = reinterpret_cast<const CrdPcieAerBank*>(data.data());
2457 ss << std::format(" [Bus{} Dev{} Fun{}]\n", pBank->bus, pBank->dev,
2458 pBank->fun);
2459 ss << std::format(" Command : 0x{:04X}\n",
2460 pBank->cmd);
2461 ss << std::format(" Status : 0x{:04X}\n",
2462 pBank->sts);
2463 ss << std::format(" Slot : 0x{:04X}\n",
2464 pBank->slot);
2465 ss << std::format(" Secondary Bus : 0x{:02X}\n",
2466 pBank->secondBus);
2467 ss << std::format(" Vendor ID : 0x{:04X}\n",
2468 pBank->vendorId);
2469 ss << std::format(" Device ID : 0x{:04X}\n",
2470 pBank->devId);
2471 ss << std::format(" Class Code : 0x{:02X}{:04X}\n",
2472 pBank->classCodeHi, pBank->classCodeLo);
2473 ss << std::format(" Bridge: Secondary Status : 0x{:04X}\n",
2474 pBank->secondSts);
2475 ss << std::format(" Bridge: Control : 0x{:04X}\n",
2476 pBank->ctrl);
2477 ss << std::format(" Uncorrectable Error Status : 0x{:08X}\n",
2478 pBank->uncorrErrSts);
2479 ss << std::format(" Uncorrectable Error Mask : 0x{:08X}\n",
2480 pBank->uncorrErrMsk);
2481 ss << std::format(" Uncorrectable Error Severity : 0x{:08X}\n",
2482 pBank->uncorrErrSeverity);
2483 ss << std::format(" Correctable Error Status : 0x{:08X}\n",
2484 pBank->corrErrSts);
2485 ss << std::format(" Correctable Error Mask : 0x{:08X}\n",
2486 pBank->corrErrMsk);
2487 ss << std::format(" Header Log DW0 : 0x{:08X}\n",
2488 pBank->hdrLogDw0);
2489 ss << std::format(" Header Log DW1 : 0x{:08X}\n",
2490 pBank->hdrLogDw1);
2491 ss << std::format(" Header Log DW2 : 0x{:08X}\n",
2492 pBank->hdrLogDw2);
2493 ss << std::format(" Header Log DW3 : 0x{:08X}\n",
2494 pBank->hdrLogDw3);
2495 ss << std::format(" Root Error Status : 0x{:08X}\n",
2496 pBank->rootErrSts);
2497 ss << std::format(" Correctable Error Source ID : 0x{:04X}\n",
2498 pBank->corrErrSrcId);
2499 ss << std::format(" Error Source ID : 0x{:04X}\n",
2500 pBank->errSrcId);
2501 ss << std::format(" Lane Error Status : 0x{:08X}\n",
2502 pBank->laneErrSts);
2503 ss << "\n";
2504
George Liu2f454992025-07-02 16:43:57 +08002505 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002506}
2507
2508static ipmi_ret_t handleWdtRegBank(std::span<const uint8_t> data,
2509 CrdState& currState, std::stringstream& ss)
2510{
2511 if (data.size() < sizeof(CrdWdtRegBank))
George Liu2f454992025-07-02 16:43:57 +08002512 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002513
2514 const auto* pBank = reinterpret_cast<const CrdWdtRegBank*>(data.data());
2515 if (data.size() < sizeof(CrdWdtRegBank) + sizeof(uint32_t) * pBank->count)
George Liu2f454992025-07-02 16:43:57 +08002516 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002517
2518 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2519 if (res)
2520 return res;
2521
2522 ss << std::format(" [NBIO{}] {}\n", pBank->nbio, pBank->name);
2523 ss << std::format(" Address: 0x{:08X}\n", pBank->addr);
2524 ss << std::format(" Data Count: {}\n", pBank->count);
2525 ss << " Data:\n";
2526 for (size_t i = 0; i < pBank->count; i++)
2527 {
2528 ss << std::format(" {}: 0x{:08X}\n", i, pBank->data[i]);
2529 }
2530 ss << "\n";
2531
George Liu2f454992025-07-02 16:43:57 +08002532 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002533}
2534
2535static ipmi_ret_t handleCrdHdrBank(std::span<const uint8_t> data,
2536 CrdState& currState, std::stringstream& ss)
2537{
2538 if (data.size() < sizeof(CrdHdrBank))
George Liu2f454992025-07-02 16:43:57 +08002539 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002540
2541 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2542 if (res)
2543 return res;
2544
2545 const auto* pBank = reinterpret_cast<const CrdHdrBank*>(data.data());
2546 ss << " Crashdump Header\n";
2547 ss << std::format(" CPU PPIN : 0x{:016X}\n", pBank->ppin);
2548 ss << std::format(" UCODE VERSION : 0x{:08X}\n", pBank->ucodeVer);
2549 ss << std::format(" PMIO 80h : 0x{:08X}\n", pBank->pmio);
2550 ss << std::format(
2551 " BIT0 - SMN Parity/SMN Timeouts PSP/SMU Parity and ECC/SMN On-Package Link Error : {}\n",
2552 pBank->pmio & 0x1);
2553 ss << std::format(" BIT2 - PSP Parity and ECC : {}\n",
2554 (pBank->pmio & 0x4) >> 2);
2555 ss << std::format(" BIT3 - SMN Timeouts SMU : {}\n",
2556 (pBank->pmio & 0x8) >> 3);
2557 ss << std::format(" BIT4 - SMN Off-Package Link Packet Error : {}\n",
2558 (pBank->pmio & 0x10) >> 4);
2559 ss << "\n";
2560
George Liu2f454992025-07-02 16:43:57 +08002561 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002562}
2563
2564static std::string getFilename(const std::filesystem::path& dir,
2565 const std::string& prefix)
2566{
2567 std::vector<int> indices;
2568 std::regex pattern(prefix + "(\\d+)\\.txt");
2569
2570 for (const auto& entry : std::filesystem::directory_iterator(dir))
2571 {
2572 std::string filename = entry.path().filename().string();
2573 std::smatch match;
2574 if (std::regex_match(filename, match, pattern))
2575 indices.push_back(std::stoi(match[1]));
2576 }
2577
2578 std::sort(indices.rbegin(), indices.rend());
2579 while (indices.size() > 2) // keep 3 files, so remove if more than 2
2580 {
2581 std::filesystem::remove(
2582 dir / (prefix + std::to_string(indices.back()) + ".txt"));
2583 indices.pop_back();
2584 }
2585
2586 int nextIndex = indices.empty() ? 1 : indices.front() + 1;
2587 return prefix + std::to_string(nextIndex) + ".txt";
2588}
2589
2590static ipmi_ret_t handleCtrlBank(std::span<const uint8_t> data,
2591 CrdState& currState, std::stringstream& ss)
2592{
2593 if (data.empty())
George Liu2f454992025-07-02 16:43:57 +08002594 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002595
2596 switch (static_cast<CrdCtrl>(data[0]))
2597 {
2598 case CrdCtrl::getState:
2599 break;
2600 case CrdCtrl::finish:
2601 {
2602 ipmi_ret_t res = setDumpState(currState, CrdState::packing);
2603 if (res)
2604 return res;
2605
2606 const std::filesystem::path dumpDir = "/var/lib/fb-ipmi-oem";
2607 std::string filename = getFilename(dumpDir, "crashdump_");
2608 std::ofstream outFile(dumpDir / filename);
2609 if (!outFile.is_open())
George Liu2f454992025-07-02 16:43:57 +08002610 return ipmi::ccUnspecifiedError;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002611
2612 auto now = std::chrono::system_clock::to_time_t(
2613 std::chrono::system_clock::now());
2614 outFile << "Crash Dump generated at: "
2615 << std::put_time(std::localtime(&now), "%Y-%m-%d %H:%M:%S")
2616 << "\n\n";
2617 outFile << ss.str();
2618 outFile.close();
2619 ss.str("");
2620 ss.clear();
2621 setDumpState(currState, CrdState::free);
2622 break;
2623 }
2624 default:
2625 return ccInvalidParam;
2626 }
2627
George Liu2f454992025-07-02 16:43:57 +08002628 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002629}
2630
Patrick Williams010dee02024-08-16 15:19:44 -04002631ipmi::RspType<std::vector<uint8_t>> ipmiOemCrashdump(
2632 [[maybe_unused]] ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002633{
2634 static CrdState dumpState = CrdState::free;
2635 static std::stringstream ss;
2636
2637 if (reqData.size() < sizeof(CrashDumpHdr))
2638 return ipmi::responseReqDataLenInvalid();
2639
2640 const auto* pHdr = reinterpret_cast<const CrashDumpHdr*>(reqData.data());
2641 std::span<const uint8_t> bData{reqData.data() + sizeof(CrashDumpHdr),
2642 reqData.size() - sizeof(CrashDumpHdr)};
2643 ipmi_ret_t res;
2644
2645 switch (pHdr->bankHdr.bankType)
2646 {
2647 case BankType::mca:
2648 res = handleMcaBank(*pHdr, bData, dumpState, ss);
2649 break;
2650 case BankType::virt:
2651 if (pHdr->bankHdr.version >= 3)
2652 {
2653 res = handleVirtualBank<CrdVirtualBankV3>(bData, dumpState, ss);
2654 break;
2655 }
2656 res = handleVirtualBank<CrdVirtualBankV2>(bData, dumpState, ss);
2657 break;
2658 case BankType::cpuWdt:
2659 res = handleCpuWdtBank(bData, dumpState, ss);
2660 break;
2661 case BankType::tcdx:
2662 res = handleHwAssertBank<tcdxNum>("TCDX", bData, dumpState, ss);
2663 break;
2664 case BankType::cake:
2665 res = handleHwAssertBank<cakeNum>("CAKE", bData, dumpState, ss);
2666 break;
2667 case BankType::pie0:
2668 res = handleHwAssertBank<pie0Num>("PIE", bData, dumpState, ss);
2669 break;
2670 case BankType::iom:
2671 res = handleHwAssertBank<iomNum>("IOM", bData, dumpState, ss);
2672 break;
2673 case BankType::ccix:
2674 res = handleHwAssertBank<ccixNum>("CCIX", bData, dumpState, ss);
2675 break;
2676 case BankType::cs:
2677 res = handleHwAssertBank<csNum>("CS", bData, dumpState, ss);
2678 break;
2679 case BankType::pcieAer:
2680 res = handlePcieAerBank(bData, dumpState, ss);
2681 break;
2682 case BankType::wdtReg:
2683 res = handleWdtRegBank(bData, dumpState, ss);
2684 break;
2685 case BankType::ctrl:
2686 res = handleCtrlBank(bData, dumpState, ss);
George Liu2f454992025-07-02 16:43:57 +08002687 if (res == ipmi::ccSuccess &&
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002688 static_cast<CrdCtrl>(bData[0]) == CrdCtrl::getState)
2689 {
2690 return ipmi::responseSuccess(
2691 std::vector<uint8_t>{static_cast<uint8_t>(dumpState)});
2692 }
2693 break;
2694 case BankType::crdHdr:
2695 res = handleCrdHdrBank(bData, dumpState, ss);
2696 break;
2697 default:
2698 return ipmi::responseInvalidFieldRequest();
2699 }
2700
2701 return ipmi::response(res);
2702}
2703
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002704static void registerOEMFunctions(void)
2705{
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002706 /* Get OEM data from json file */
2707 std::ifstream file(JSON_OEM_DATA_FILE);
2708 if (file)
Vijay Khemkafeaa9812019-08-27 15:08:08 -07002709 {
Peter Yinac597172024-11-05 16:15:50 +08002710 try
2711 {
2712 file >> oemData;
2713 }
2714 // If parsing fails, initialize oemData as an empty JSON and
2715 // overwrite the file
2716 catch (const nlohmann::json::parse_error& e)
2717 {
2718 lg2::error("Error parsing JSON file: {ERROR}", "ERROR", e);
2719 oemData = nlohmann::json::object();
2720 std::ofstream outFile(JSON_OEM_DATA_FILE, std::ofstream::trunc);
2721 outFile << oemData.dump(4); // Write empty JSON object to the file
2722 outFile.close();
2723 }
Vijay Khemkafeaa9812019-08-27 15:08:08 -07002724 file.close();
2725 }
Peter Yinac597172024-11-05 16:15:50 +08002726 else
2727 {
2728 lg2::info("Failed to open JSON file.");
2729 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002730
Peter Yinac597172024-11-05 16:15:50 +08002731 lg2::info("Registering OEM commands.");
Vijay Khemka7c0aea42020-03-05 13:31:53 -08002732
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002733 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_INFO,
2734 NULL, ipmiOemDbgGetFrameInfo,
2735 PRIVILEGE_USER); // get debug frame info
2736 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ,
2737 CMD_OEM_USB_DBG_GET_UPDATED_FRAMES, NULL,
2738 ipmiOemDbgGetUpdFrames,
2739 PRIVILEGE_USER); // get debug updated frames
2740 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_POST_DESC,
2741 NULL, ipmiOemDbgGetPostDesc,
2742 PRIVILEGE_USER); // get debug post description
2743 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_GPIO_DESC,
2744 NULL, ipmiOemDbgGetGpioDesc,
2745 PRIVILEGE_USER); // get debug gpio description
2746 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_DATA,
2747 NULL, ipmiOemDbgGetFrameData,
2748 PRIVILEGE_USER); // get debug frame data
2749 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_CTRL_PANEL,
2750 NULL, ipmiOemDbgGetCtrlPanel,
2751 PRIVILEGE_USER); // get debug control panel
George Liu0821a2e2025-04-03 10:12:10 +08002752 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_DIMM_INFO, NULL,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002753 ipmiOemSetDimmInfo,
2754 PRIVILEGE_USER); // Set Dimm Info
George Liu0821a2e2025-04-03 10:12:10 +08002755 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_GET_BOARD_ID, NULL,
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002756 ipmiOemGetBoardID,
2757 PRIVILEGE_USER); // Get Board ID
Bonnie Lo4ae63e72023-02-09 15:27:54 +08002758 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnOemOne,
2759 CMD_OEM_GET_80PORT_RECORD, ipmi::Privilege::User,
2760 ipmiOemGet80PortRecord); // Get 80 Port Record
George Liu0821a2e2025-04-03 10:12:10 +08002761 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_MACHINE_CONFIG_INFO,
2762 NULL, ipmiOemSetMachineCfgInfo,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002763 PRIVILEGE_USER); // Set Machine Config Info
George Liu0821a2e2025-04-03 10:12:10 +08002764 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_POST_START, NULL,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002765 ipmiOemSetPostStart,
2766 PRIVILEGE_USER); // Set POST start
George Liu0821a2e2025-04-03 10:12:10 +08002767 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_POST_END, NULL,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002768 ipmiOemSetPostEnd,
2769 PRIVILEGE_USER); // Set POST End
George Liu0821a2e2025-04-03 10:12:10 +08002770 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_PPIN_INFO, NULL,
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002771 ipmiOemSetPPINInfo,
2772 PRIVILEGE_USER); // Set PPIN Info
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05302773#if BIC_ENABLED
2774
2775 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2776 ipmi::cmdSetSystemGuid, ipmi::Privilege::User,
2777 ipmiOemSetSystemGuid);
2778#else
2779
George Liu0821a2e2025-04-03 10:12:10 +08002780 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_SYSTEM_GUID, NULL,
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07002781 ipmiOemSetSystemGuid,
2782 PRIVILEGE_USER); // Set System GUID
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05302783#endif
George Liu0821a2e2025-04-03 10:12:10 +08002784 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_ADR_TRIGGER, NULL,
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002785 ipmiOemSetAdrTrigger,
2786 PRIVILEGE_USER); // Set ADR Trigger
George Liu0821a2e2025-04-03 10:12:10 +08002787 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_BIOS_FLASH_INFO, NULL,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002788 ipmiOemSetBiosFlashInfo,
2789 PRIVILEGE_USER); // Set Bios Flash Info
George Liu0821a2e2025-04-03 10:12:10 +08002790 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_PPR, NULL,
2791 ipmiOemSetPpr,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002792 PRIVILEGE_USER); // Set PPR
George Liu0821a2e2025-04-03 10:12:10 +08002793 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_GET_PPR, NULL,
2794 ipmiOemGetPpr,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002795 PRIVILEGE_USER); // Get PPR
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002796 /* FB OEM QC Commands */
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05302797 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour,
2798 CMD_OEM_Q_SET_PROC_INFO, ipmi::Privilege::User,
2799 ipmiOemQSetProcInfo); // Set Proc Info
2800 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour,
2801 CMD_OEM_Q_GET_PROC_INFO, ipmi::Privilege::User,
2802 ipmiOemQGetProcInfo); // Get Proc Info
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05302803 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour,
2804 ipmi::cmdSetQDimmInfo, ipmi::Privilege::User,
2805 ipmiOemQSetDimmInfo); // Set Dimm Info
2806 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour,
2807 ipmi::cmdGetQDimmInfo, ipmi::Privilege::User,
2808 ipmiOemQGetDimmInfo); // Get Dimm Info
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002809 ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_DRIVE_INFO, NULL,
2810 ipmiOemQSetDriveInfo,
2811 PRIVILEGE_USER); // Set Drive Info
2812 ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_DRIVE_INFO, NULL,
2813 ipmiOemQGetDriveInfo,
2814 PRIVILEGE_USER); // Get Drive Info
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002815
2816 /* FB OEM DCMI Commands as per DCMI spec 1.5 Section 6 */
Patrick Williams010dee02024-08-16 15:19:44 -04002817 ipmi::registerGroupHandler(
2818 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdGetPowerReading,
2819 ipmi::Privilege::User,
2820 ipmiOemDCMIGetPowerReading); // Get Power Reading
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002821
Patrick Williams010dee02024-08-16 15:19:44 -04002822 ipmi::registerGroupHandler(
2823 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdGetPowerLimit,
2824 ipmi::Privilege::User,
2825 ipmiOemDCMIGetPowerLimit); // Get Power Limit
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002826
Patrick Williams010dee02024-08-16 15:19:44 -04002827 ipmi::registerGroupHandler(
2828 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdSetPowerLimit,
2829 ipmi::Privilege::Operator,
2830 ipmiOemDCMISetPowerLimit); // Set Power Limit
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002831
Patrick Williams010dee02024-08-16 15:19:44 -04002832 ipmi::registerGroupHandler(
2833 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdActDeactivatePwrLimit,
2834 ipmi::Privilege::Operator,
2835 ipmiOemDCMIApplyPowerLimit); // Apply Power Limit
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002836
Jayashree-Df0cf6652020-11-30 11:03:30 +05302837 /* FB OEM BOOT ORDER COMMANDS */
2838 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2839 CMD_OEM_GET_BOOT_ORDER, ipmi::Privilege::User,
2840 ipmiOemGetBootOrder); // Get Boot Order
2841
2842 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2843 CMD_OEM_SET_BOOT_ORDER, ipmi::Privilege::User,
2844 ipmiOemSetBootOrder); // Set Boot Order
2845
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002846 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
Cosmo Chou99d42b62024-08-15 10:42:47 +08002847 CMD_OEM_GET_HTTPS_BOOT_DATA, ipmi::Privilege::User,
2848 ipmiOemGetHttpsData);
2849
2850 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2851 CMD_OEM_GET_HTTPS_BOOT_ATTR, ipmi::Privilege::User,
2852 ipmiOemGetHttpsAttr);
2853
2854 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002855 CMD_OEM_CRASHDUMP, ipmi::Privilege::User,
2856 ipmiOemCrashdump);
2857
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002858 return;
2859}
2860
2861} // namespace ipmi