1 /* 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" 19 20 #include <commandutils.hpp> 21 #include <ipmid/api-types.hpp> 22 #include <ipmid/api.hpp> 23 #include <ipmid/utils.hpp> 24 #include <nlohmann/json.hpp> 25 #include <oemcommands.hpp> 26 #include <phosphor-logging/log.hpp> 27 #include <sdbusplus/bus.hpp> 28 #include <xyz/openbmc_project/Control/Boot/Mode/server.hpp> 29 #include <xyz/openbmc_project/Control/Boot/Source/server.hpp> 30 #include <xyz/openbmc_project/Control/Boot/Type/server.hpp> 31 32 #include <array> 33 #include <cstring> 34 #include <fstream> 35 #include <iomanip> 36 #include <iostream> 37 #include <regex> 38 #include <sstream> 39 #include <string> 40 #include <vector> 41 42 #define SIZE_IANA_ID 3 43 44 namespace ipmi 45 { 46 47 using namespace phosphor::logging; 48 49 void getSelectorPosition(size_t& position); 50 static void registerOEMFunctions() __attribute__((constructor)); 51 sdbusplus::bus_t dbus(ipmid_get_sd_bus_connection()); // from ipmid/api.h 52 static constexpr size_t maxFRUStringLength = 0x3F; 53 constexpr uint8_t cmdSetSystemGuid = 0xEF; 54 55 constexpr uint8_t cmdSetQDimmInfo = 0x12; 56 constexpr uint8_t cmdGetQDimmInfo = 0x13; 57 58 constexpr ipmi_ret_t ccInvalidParam = 0x80; 59 60 int plat_udbg_get_post_desc(uint8_t, uint8_t*, uint8_t, uint8_t*, uint8_t*, 61 uint8_t*); 62 int plat_udbg_get_gpio_desc(uint8_t, uint8_t*, uint8_t*, uint8_t*, uint8_t*, 63 uint8_t*); 64 int plat_udbg_get_frame_data(uint8_t, uint8_t, uint8_t*, uint8_t*, uint8_t*); 65 ipmi_ret_t plat_udbg_control_panel(uint8_t, uint8_t, uint8_t, uint8_t*, 66 uint8_t*); 67 int sendMeCmd(uint8_t, uint8_t, std::vector<uint8_t>&, std::vector<uint8_t>&); 68 69 int sendBicCmd(uint8_t, uint8_t, uint8_t, std::vector<uint8_t>&, 70 std::vector<uint8_t>&); 71 72 nlohmann::json oemData __attribute__((init_priority(101))); 73 74 static constexpr size_t GUID_SIZE = 16; 75 // TODO Make offset and location runtime configurable to ensure we 76 // can make each define their own locations. 77 static constexpr off_t OFFSET_SYS_GUID = 0x17F0; 78 static constexpr const char* FRU_EEPROM = "/sys/bus/i2c/devices/6-0054/eeprom"; 79 void flushOemData(); 80 81 enum class LanParam : uint8_t 82 { 83 INPROGRESS = 0, 84 AUTHSUPPORT = 1, 85 AUTHENABLES = 2, 86 IP = 3, 87 IPSRC = 4, 88 MAC = 5, 89 SUBNET = 6, 90 GATEWAY = 12, 91 VLAN = 20, 92 CIPHER_SUITE_COUNT = 22, 93 CIPHER_SUITE_ENTRIES = 23, 94 IPV6 = 59, 95 }; 96 97 namespace network 98 { 99 100 constexpr auto ROOT = "/xyz/openbmc_project/network"; 101 constexpr auto SERVICE = "xyz.openbmc_project.Network"; 102 constexpr auto IPV4_TYPE = "ipv4"; 103 constexpr auto IPV6_TYPE = "ipv6"; 104 constexpr auto IPV4_PREFIX = "169.254"; 105 constexpr auto IPV6_PREFIX = "fe80"; 106 constexpr auto IP_INTERFACE = "xyz.openbmc_project.Network.IP"; 107 constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress"; 108 constexpr auto IPV4_PROTOCOL = "xyz.openbmc_project.Network.IP.Protocol.IPv4"; 109 constexpr auto IPV6_PROTOCOL = "xyz.openbmc_project.Network.IP.Protocol.IPv6"; 110 111 bool isLinkLocalIP(const std::string& address) 112 { 113 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0; 114 } 115 116 DbusObjectInfo getIPObject(sdbusplus::bus_t& bus, const std::string& interface, 117 const std::string& serviceRoot, 118 const std::string& protocol, 119 const std::string& ethdev) 120 { 121 auto objectTree = getAllDbusObjects(bus, serviceRoot, interface, ethdev); 122 123 if (objectTree.empty()) 124 { 125 log<level::ERR>("No Object has implemented the IP interface", 126 entry("INTERFACE=%s", interface.c_str())); 127 } 128 129 DbusObjectInfo objectInfo; 130 131 for (auto& object : objectTree) 132 { 133 auto variant = ipmi::getDbusProperty(bus, object.second.begin()->first, 134 object.first, IP_INTERFACE, 135 "Type"); 136 if (std::get<std::string>(variant) != protocol) 137 { 138 continue; 139 } 140 141 variant = ipmi::getDbusProperty(bus, object.second.begin()->first, 142 object.first, IP_INTERFACE, "Address"); 143 144 objectInfo = std::make_pair(object.first, object.second.begin()->first); 145 146 // if LinkLocalIP found look for Non-LinkLocalIP 147 if (isLinkLocalIP(std::get<std::string>(variant))) 148 { 149 continue; 150 } 151 else 152 { 153 break; 154 } 155 } 156 return objectInfo; 157 } 158 159 } // namespace network 160 161 namespace boot 162 { 163 using BootSource = 164 sdbusplus::xyz::openbmc_project::Control::Boot::server::Source::Sources; 165 using BootMode = 166 sdbusplus::xyz::openbmc_project::Control::Boot::server::Mode::Modes; 167 using BootType = 168 sdbusplus::xyz::openbmc_project::Control::Boot::server::Type::Types; 169 170 using IpmiValue = uint8_t; 171 172 std::map<IpmiValue, BootSource> sourceIpmiToDbus = { 173 {0x0f, BootSource::Default}, {0x00, BootSource::RemovableMedia}, 174 {0x01, BootSource::Network}, {0x02, BootSource::Disk}, 175 {0x03, BootSource::ExternalMedia}, {0x04, BootSource::RemovableMedia}, 176 {0x09, BootSource::Network}}; 177 178 std::map<IpmiValue, BootMode> modeIpmiToDbus = {{0x04, BootMode::Setup}, 179 {0x00, BootMode::Regular}}; 180 181 std::map<IpmiValue, BootType> typeIpmiToDbus = {{0x00, BootType::Legacy}, 182 {0x01, BootType::EFI}}; 183 184 std::map<std::optional<BootSource>, IpmiValue> sourceDbusToIpmi = { 185 {BootSource::Default, 0x0f}, 186 {BootSource::RemovableMedia, 0x00}, 187 {BootSource::Network, 0x01}, 188 {BootSource::Disk, 0x02}, 189 {BootSource::ExternalMedia, 0x03}}; 190 191 std::map<std::optional<BootMode>, IpmiValue> modeDbusToIpmi = { 192 {BootMode::Setup, 0x04}, {BootMode::Regular, 0x00}}; 193 194 std::map<std::optional<BootType>, IpmiValue> typeDbusToIpmi = { 195 {BootType::Legacy, 0x00}, {BootType::EFI, 0x01}}; 196 197 static constexpr auto bootEnableIntf = "xyz.openbmc_project.Object.Enable"; 198 static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode"; 199 static constexpr auto bootSourceIntf = 200 "xyz.openbmc_project.Control.Boot.Source"; 201 static constexpr auto bootTypeIntf = "xyz.openbmc_project.Control.Boot.Type"; 202 static constexpr auto bootSourceProp = "BootSource"; 203 static constexpr auto bootModeProp = "BootMode"; 204 static constexpr auto bootTypeProp = "BootType"; 205 static constexpr auto bootEnableProp = "Enabled"; 206 207 std::tuple<std::string, std::string> objPath(size_t id) 208 { 209 std::string hostName = "host" + std::to_string(id); 210 std::string bootObjPath = "/xyz/openbmc_project/control/" + hostName + 211 "/boot"; 212 return std::make_tuple(std::move(bootObjPath), std::move(hostName)); 213 } 214 215 /* Helper functions to set boot order */ 216 void setBootOrder(std::string bootObjPath, const std::vector<uint8_t>& bootSeq, 217 std::string bootOrderKey) 218 { 219 if (bootSeq.size() != SIZE_BOOT_ORDER) 220 { 221 phosphor::logging::log<phosphor::logging::level::ERR>( 222 "Invalid Boot order length received"); 223 return; 224 } 225 226 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 227 228 uint8_t mode = bootSeq.front(); 229 230 // SETTING BOOT MODE PROPERTY 231 uint8_t bootModeBit = mode & 0x04; 232 auto bootValue = ipmi::boot::modeIpmiToDbus.at(bootModeBit); 233 234 std::string bootOption = 235 sdbusplus::message::convert_to_string<boot::BootMode>(bootValue); 236 237 std::string service = getService(*dbus, ipmi::boot::bootModeIntf, 238 bootObjPath); 239 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootModeIntf, 240 ipmi::boot::bootModeProp, bootOption); 241 242 // SETTING BOOT SOURCE PROPERTY 243 auto bootOrder = ipmi::boot::sourceIpmiToDbus.at(bootSeq.at(1)); 244 std::string bootSource = 245 sdbusplus::message::convert_to_string<boot::BootSource>(bootOrder); 246 247 service = getService(*dbus, ipmi::boot::bootSourceIntf, bootObjPath); 248 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootSourceIntf, 249 ipmi::boot::bootSourceProp, bootSource); 250 251 // SETTING BOOT TYPE PROPERTY 252 uint8_t bootTypeBit = mode & 0x01; 253 auto bootTypeVal = ipmi::boot::typeIpmiToDbus.at(bootTypeBit); 254 255 std::string bootType = 256 sdbusplus::message::convert_to_string<boot::BootType>(bootTypeVal); 257 258 service = getService(*dbus, ipmi::boot::bootTypeIntf, bootObjPath); 259 260 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootTypeIntf, 261 ipmi::boot::bootTypeProp, bootType); 262 263 // Set the valid bit to boot enabled property 264 service = getService(*dbus, ipmi::boot::bootEnableIntf, bootObjPath); 265 266 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootEnableIntf, 267 ipmi::boot::bootEnableProp, 268 (mode & BOOT_MODE_BOOT_FLAG) ? true : false); 269 270 nlohmann::json bootMode; 271 272 bootMode["UEFI"] = (mode & BOOT_MODE_UEFI) ? true : false; 273 bootMode["CMOS_CLR"] = (mode & BOOT_MODE_CMOS_CLR) ? true : false; 274 bootMode["FORCE_BOOT"] = (mode & BOOT_MODE_FORCE_BOOT) ? true : false; 275 bootMode["BOOT_FLAG"] = (mode & BOOT_MODE_BOOT_FLAG) ? true : false; 276 oemData[bootOrderKey][KEY_BOOT_MODE] = bootMode; 277 278 /* Initialize boot sequence array */ 279 oemData[bootOrderKey][KEY_BOOT_SEQ] = {}; 280 for (size_t i = 1; i < SIZE_BOOT_ORDER; i++) 281 { 282 if (bootSeq.at(i) >= BOOT_SEQ_ARRAY_SIZE) 283 oemData[bootOrderKey][KEY_BOOT_SEQ][i - 1] = "NA"; 284 else 285 oemData[bootOrderKey][KEY_BOOT_SEQ][i - 1] = 286 bootSeqDefine[bootSeq.at(i)]; 287 } 288 289 flushOemData(); 290 } 291 292 void getBootOrder(std::string bootObjPath, std::vector<uint8_t>& bootSeq, 293 std::string hostName) 294 { 295 if (oemData.find(hostName) == oemData.end()) 296 { 297 /* Return default boot order 0100090203ff */ 298 bootSeq.push_back(BOOT_MODE_UEFI); 299 bootSeq.push_back(static_cast<uint8_t>(bootMap["USB_DEV"])); 300 bootSeq.push_back(static_cast<uint8_t>(bootMap["NET_IPV6"])); 301 bootSeq.push_back(static_cast<uint8_t>(bootMap["SATA_HDD"])); 302 bootSeq.push_back(static_cast<uint8_t>(bootMap["SATA_CD"])); 303 bootSeq.push_back(0xff); 304 305 phosphor::logging::log<phosphor::logging::level::INFO>( 306 "Set default boot order"); 307 setBootOrder(bootObjPath, bootSeq, hostName); 308 return; 309 } 310 311 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 312 313 // GETTING PROPERTY OF MODE INTERFACE 314 315 std::string service = getService(*dbus, ipmi::boot::bootModeIntf, 316 bootObjPath); 317 Value variant = getDbusProperty(*dbus, service, bootObjPath, 318 ipmi::boot::bootModeIntf, 319 ipmi::boot::bootModeProp); 320 321 auto bootMode = sdbusplus::message::convert_from_string<boot::BootMode>( 322 std::get<std::string>(variant)); 323 324 uint8_t bootOption = ipmi::boot::modeDbusToIpmi.at(bootMode); 325 326 // GETTING PROPERTY OF TYPE INTERFACE 327 328 service = getService(*dbus, ipmi::boot::bootTypeIntf, bootObjPath); 329 variant = getDbusProperty(*dbus, service, bootObjPath, 330 ipmi::boot::bootTypeIntf, 331 ipmi::boot::bootTypeProp); 332 333 auto bootType = sdbusplus::message::convert_from_string<boot::BootType>( 334 std::get<std::string>(variant)); 335 336 // Get the valid bit to boot enabled property 337 service = getService(*dbus, ipmi::boot::bootEnableIntf, bootObjPath); 338 variant = getDbusProperty(*dbus, service, bootObjPath, 339 ipmi::boot::bootEnableIntf, 340 ipmi::boot::bootEnableProp); 341 342 bool validFlag = std::get<bool>(variant); 343 344 uint8_t bootTypeVal = ipmi::boot::typeDbusToIpmi.at(bootType); 345 346 bootSeq.push_back(bootOption | bootTypeVal); 347 348 if (validFlag) 349 { 350 bootSeq.front() |= BOOT_MODE_BOOT_FLAG; 351 } 352 353 nlohmann::json bootModeJson = oemData[hostName][KEY_BOOT_MODE]; 354 if (bootModeJson["CMOS_CLR"]) 355 bootSeq.front() |= BOOT_MODE_CMOS_CLR; 356 357 for (int i = 1; i < SIZE_BOOT_ORDER; i++) 358 { 359 std::string seqStr = oemData[hostName][KEY_BOOT_SEQ][i - 1]; 360 if (bootMap.find(seqStr) != bootMap.end()) 361 bootSeq.push_back(bootMap[seqStr]); 362 else 363 bootSeq.push_back(0xff); 364 } 365 } 366 367 } // namespace boot 368 369 //---------------------------------------------------------------------- 370 // Helper functions for storing oem data 371 //---------------------------------------------------------------------- 372 373 void flushOemData() 374 { 375 std::ofstream file(JSON_OEM_DATA_FILE); 376 file << oemData; 377 file.close(); 378 return; 379 } 380 381 std::string bytesToStr(uint8_t* byte, int len) 382 { 383 std::stringstream ss; 384 int i; 385 386 ss << std::hex; 387 for (i = 0; i < len; i++) 388 { 389 ss << std::setw(2) << std::setfill('0') << (int)byte[i]; 390 } 391 392 return ss.str(); 393 } 394 395 int strToBytes(std::string& str, uint8_t* data) 396 { 397 std::string sstr; 398 size_t i; 399 400 for (i = 0; i < (str.length()) / 2; i++) 401 { 402 sstr = str.substr(i * 2, 2); 403 data[i] = (uint8_t)std::strtol(sstr.c_str(), NULL, 16); 404 } 405 return i; 406 } 407 408 int readDimmType(std::string& data, uint8_t param) 409 { 410 nlohmann::json dimmObj; 411 /* Get dimm type names stored in json file */ 412 std::ifstream file(JSON_DIMM_TYPE_FILE); 413 if (file) 414 { 415 file >> dimmObj; 416 file.close(); 417 } 418 else 419 { 420 phosphor::logging::log<phosphor::logging::level::ERR>( 421 "DIMM type names file not found", 422 phosphor::logging::entry("DIMM_TYPE_FILE=%s", JSON_DIMM_TYPE_FILE)); 423 return -1; 424 } 425 426 std::string dimmKey = "dimm_type" + std::to_string(param); 427 auto obj = dimmObj[dimmKey]["short_name"]; 428 data = obj; 429 return 0; 430 } 431 432 ipmi_ret_t getNetworkData(uint8_t lan_param, char* data) 433 { 434 ipmi_ret_t rc = IPMI_CC_OK; 435 sdbusplus::bus_t bus(ipmid_get_sd_bus_connection()); 436 437 const std::string ethdevice = "eth0"; 438 439 switch (static_cast<LanParam>(lan_param)) 440 { 441 case LanParam::IP: 442 { 443 std::string ipaddress; 444 auto ipObjectInfo = ipmi::network::getIPObject( 445 bus, ipmi::network::IP_INTERFACE, ipmi::network::ROOT, 446 ipmi::network::IPV4_PROTOCOL, ethdevice); 447 448 auto properties = ipmi::getAllDbusProperties( 449 bus, ipObjectInfo.second, ipObjectInfo.first, 450 ipmi::network::IP_INTERFACE); 451 452 ipaddress = std::get<std::string>(properties["Address"]); 453 454 std::strcpy(data, ipaddress.c_str()); 455 } 456 break; 457 458 case LanParam::IPV6: 459 { 460 std::string ipaddress; 461 auto ipObjectInfo = ipmi::network::getIPObject( 462 bus, ipmi::network::IP_INTERFACE, ipmi::network::ROOT, 463 ipmi::network::IPV6_PROTOCOL, ethdevice); 464 465 auto properties = ipmi::getAllDbusProperties( 466 bus, ipObjectInfo.second, ipObjectInfo.first, 467 ipmi::network::IP_INTERFACE); 468 469 ipaddress = std::get<std::string>(properties["Address"]); 470 471 std::strcpy(data, ipaddress.c_str()); 472 } 473 break; 474 475 case LanParam::MAC: 476 { 477 std::string macAddress; 478 auto macObjectInfo = 479 ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE, 480 ipmi::network::ROOT, ethdevice); 481 482 auto variant = ipmi::getDbusProperty( 483 bus, macObjectInfo.second, macObjectInfo.first, 484 ipmi::network::MAC_INTERFACE, "MACAddress"); 485 486 macAddress = std::get<std::string>(variant); 487 488 sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT, 489 (data), (data + 1), (data + 2), (data + 3), (data + 4), 490 (data + 5)); 491 std::strcpy(data, macAddress.c_str()); 492 } 493 break; 494 495 default: 496 rc = IPMI_CC_PARM_OUT_OF_RANGE; 497 } 498 return rc; 499 } 500 501 bool isMultiHostPlatform() 502 { 503 bool platform; 504 if (hostInstances == "0") 505 { 506 platform = false; 507 } 508 else 509 { 510 platform = true; 511 } 512 return platform; 513 } 514 515 // return code: 0 successful 516 int8_t getFruData(std::string& data, std::string& name) 517 { 518 size_t pos; 519 static constexpr const auto depth = 0; 520 std::vector<std::string> paths; 521 std::string machinePath; 522 std::string baseBoard = "Baseboard"; 523 524 bool platform = isMultiHostPlatform(); 525 if (platform == true) 526 { 527 getSelectorPosition(pos); 528 } 529 530 sd_bus* bus = NULL; 531 int ret = sd_bus_default_system(&bus); 532 if (ret < 0) 533 { 534 phosphor::logging::log<phosphor::logging::level::ERR>( 535 "Failed to connect to system bus", 536 phosphor::logging::entry("ERRNO=0x%X", -ret)); 537 sd_bus_unref(bus); 538 return -1; 539 } 540 sdbusplus::bus_t dbus(bus); 541 auto mapperCall = dbus.new_method_call("xyz.openbmc_project.ObjectMapper", 542 "/xyz/openbmc_project/object_mapper", 543 "xyz.openbmc_project.ObjectMapper", 544 "GetSubTreePaths"); 545 static constexpr std::array<const char*, 1> interface = { 546 "xyz.openbmc_project.Inventory.Decorator.Asset"}; 547 mapperCall.append("/xyz/openbmc_project/inventory/", depth, interface); 548 549 try 550 { 551 auto reply = dbus.call(mapperCall); 552 reply.read(paths); 553 } 554 catch (sdbusplus::exception_t& e) 555 { 556 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 557 return -1; 558 } 559 560 for (const auto& path : paths) 561 { 562 if (platform == true) 563 { 564 if (pos == BMC_POS) 565 { 566 machinePath = baseBoard; 567 } 568 else 569 { 570 machinePath = "_" + std::to_string(pos); 571 } 572 } 573 else 574 { 575 machinePath = baseBoard; 576 } 577 578 auto found = path.find(machinePath); 579 if (found == std::string::npos) 580 { 581 continue; 582 } 583 584 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 585 std::string service = getService( 586 *dbus, "xyz.openbmc_project.Inventory.Decorator.Asset", path); 587 588 auto Value = ipmi::getDbusProperty( 589 *dbus, service, path, 590 "xyz.openbmc_project.Inventory.Decorator.Asset", name); 591 592 data = std::get<std::string>(Value); 593 return 0; 594 } 595 return -1; 596 } 597 598 int8_t sysConfig(std::vector<std::string>& data, size_t pos) 599 { 600 nlohmann::json sysObj; 601 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(pos); 602 std::string result, typeName; 603 uint8_t res[MAX_BUF]; 604 605 /* Get sysConfig data stored in json file */ 606 std::ifstream file(JSON_OEM_DATA_FILE); 607 if (file) 608 { 609 file >> sysObj; 610 file.close(); 611 } 612 else 613 { 614 phosphor::logging::log<phosphor::logging::level::ERR>( 615 "oemData file not found", 616 phosphor::logging::entry("OEM_DATA_FILE=%s", JSON_OEM_DATA_FILE)); 617 return -1; 618 } 619 620 if (sysObj.find(dimmInfo) == sysObj.end()) 621 { 622 phosphor::logging::log<phosphor::logging::level::ERR>( 623 "sysconfig key not available", 624 phosphor::logging::entry("SYS_JSON_KEY=%s", dimmInfo.c_str())); 625 return -1; 626 } 627 /* Get dimm type names stored in json file */ 628 nlohmann::json dimmObj; 629 std::ifstream dimmFile(JSON_DIMM_TYPE_FILE); 630 if (file) 631 { 632 dimmFile >> dimmObj; 633 dimmFile.close(); 634 } 635 else 636 { 637 phosphor::logging::log<phosphor::logging::level::ERR>( 638 "DIMM type names file not found", 639 phosphor::logging::entry("DIMM_TYPE_FILE=%s", JSON_DIMM_TYPE_FILE)); 640 return -1; 641 } 642 std::vector<std::string> a; 643 for (auto& j : dimmObj.items()) 644 { 645 std::string name = j.key(); 646 a.push_back(name); 647 } 648 649 uint8_t len = a.size(); 650 for (uint8_t ii = 0; ii < len; ii++) 651 { 652 std::string indKey = std::to_string(ii); 653 std::string speedSize = sysObj[dimmInfo][indKey][DIMM_SPEED]; 654 strToBytes(speedSize, res); 655 auto speed = (res[1] << 8 | res[0]); 656 size_t dimmSize = ((res[3] << 8 | res[2]) / 1000); 657 658 if (dimmSize == 0) 659 { 660 std::cerr << "Dimm information not available for slot_" + 661 std::to_string(ii) 662 << std::endl; 663 continue; 664 } 665 std::string type = sysObj[dimmInfo][indKey][DIMM_TYPE]; 666 std::string dualInlineMem = sysObj[dimmInfo][indKey][KEY_DIMM_TYPE]; 667 strToBytes(type, res); 668 size_t dimmType = res[0]; 669 if (dimmVenMap.find(dimmType) == dimmVenMap.end()) 670 { 671 typeName = "unknown"; 672 } 673 else 674 { 675 typeName = dimmVenMap[dimmType]; 676 } 677 result = dualInlineMem + "/" + typeName + "/" + std::to_string(speed) + 678 "MHz" + "/" + std::to_string(dimmSize) + "GB"; 679 data.push_back(result); 680 } 681 return 0; 682 } 683 684 int8_t procInfo(std::string& result, size_t pos) 685 { 686 std::vector<char> data; 687 uint8_t res[MAX_BUF]; 688 std::string procIndex = "00"; 689 nlohmann::json proObj; 690 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(pos); 691 /* Get processor data stored in json file */ 692 std::ifstream file(JSON_OEM_DATA_FILE); 693 if (file) 694 { 695 file >> proObj; 696 file.close(); 697 } 698 else 699 { 700 phosphor::logging::log<phosphor::logging::level::ERR>( 701 "oemData file not found", 702 phosphor::logging::entry("OEM_DATA_FILE=%s", JSON_OEM_DATA_FILE)); 703 return -1; 704 } 705 if (proObj.find(procInfo) == proObj.end()) 706 { 707 phosphor::logging::log<phosphor::logging::level::ERR>( 708 "processor info key not available", 709 phosphor::logging::entry("PROC_JSON_KEY=%s", procInfo.c_str())); 710 return -1; 711 } 712 std::string procName = proObj[procInfo][procIndex][KEY_PROC_NAME]; 713 std::string basicInfo = proObj[procInfo][procIndex][KEY_BASIC_INFO]; 714 // Processor Product Name 715 strToBytes(procName, res); 716 data.assign(reinterpret_cast<char*>(&res), 717 reinterpret_cast<char*>(&res) + sizeof(res)); 718 719 std::string s(data.begin(), data.end()); 720 std::regex regex(" "); 721 std::vector<std::string> productName( 722 std::sregex_token_iterator(s.begin(), s.end(), regex, -1), 723 std::sregex_token_iterator()); 724 725 // Processor core and frequency 726 strToBytes(basicInfo, res); 727 uint16_t coreNum = res[0]; 728 double procFrequency = (float)(res[4] << 8 | res[3]) / 1000; 729 result = "CPU:" + productName[2] + "/" + std::to_string(procFrequency) + 730 "GHz" + "/" + std::to_string(coreNum) + "c"; 731 return 0; 732 } 733 734 typedef struct 735 { 736 uint8_t cur_power_state; 737 uint8_t last_power_event; 738 uint8_t misc_power_state; 739 uint8_t front_panel_button_cap_status; 740 } ipmi_get_chassis_status_t; 741 742 //---------------------------------------------------------------------- 743 // Get Debug Frame Info 744 //---------------------------------------------------------------------- 745 ipmi_ret_t ipmiOemDbgGetFrameInfo(ipmi_netfn_t, ipmi_cmd_t, 746 ipmi_request_t request, 747 ipmi_response_t response, 748 ipmi_data_len_t data_len, ipmi_context_t) 749 { 750 uint8_t* req = reinterpret_cast<uint8_t*>(request); 751 uint8_t* res = reinterpret_cast<uint8_t*>(response); 752 uint8_t num_frames = debugCardFrameSize; 753 754 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID 755 res[SIZE_IANA_ID] = num_frames; 756 *data_len = SIZE_IANA_ID + 1; 757 758 return IPMI_CC_OK; 759 } 760 761 //---------------------------------------------------------------------- 762 // Get Debug Updated Frames 763 //---------------------------------------------------------------------- 764 ipmi_ret_t ipmiOemDbgGetUpdFrames(ipmi_netfn_t, ipmi_cmd_t, 765 ipmi_request_t request, 766 ipmi_response_t response, 767 ipmi_data_len_t data_len, ipmi_context_t) 768 { 769 uint8_t* req = reinterpret_cast<uint8_t*>(request); 770 uint8_t* res = reinterpret_cast<uint8_t*>(response); 771 uint8_t num_updates = 3; 772 *data_len = 4; 773 774 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID 775 res[SIZE_IANA_ID] = num_updates; 776 *data_len = SIZE_IANA_ID + num_updates + 1; 777 res[SIZE_IANA_ID + 1] = 1; // info page update 778 res[SIZE_IANA_ID + 2] = 2; // cri sel update 779 res[SIZE_IANA_ID + 3] = 3; // cri sensor update 780 781 return IPMI_CC_OK; 782 } 783 784 //---------------------------------------------------------------------- 785 // Get Debug POST Description 786 //---------------------------------------------------------------------- 787 ipmi_ret_t ipmiOemDbgGetPostDesc(ipmi_netfn_t, ipmi_cmd_t, 788 ipmi_request_t request, 789 ipmi_response_t response, 790 ipmi_data_len_t data_len, ipmi_context_t) 791 { 792 uint8_t* req = reinterpret_cast<uint8_t*>(request); 793 uint8_t* res = reinterpret_cast<uint8_t*>(response); 794 uint8_t index = 0; 795 uint8_t next = 0; 796 uint8_t end = 0; 797 uint8_t phase = 0; 798 uint8_t descLen = 0; 799 int ret; 800 801 index = req[3]; 802 phase = req[4]; 803 804 ret = plat_udbg_get_post_desc(index, &next, phase, &end, &descLen, &res[8]); 805 if (ret) 806 { 807 memcpy(res, req, SIZE_IANA_ID); // IANA ID 808 *data_len = SIZE_IANA_ID; 809 return IPMI_CC_UNSPECIFIED_ERROR; 810 } 811 812 memcpy(res, req, SIZE_IANA_ID); // IANA ID 813 res[3] = index; 814 res[4] = next; 815 res[5] = phase; 816 res[6] = end; 817 res[7] = descLen; 818 *data_len = SIZE_IANA_ID + 5 + descLen; 819 820 return IPMI_CC_OK; 821 } 822 823 //---------------------------------------------------------------------- 824 // Get Debug GPIO Description 825 //---------------------------------------------------------------------- 826 ipmi_ret_t ipmiOemDbgGetGpioDesc(ipmi_netfn_t, ipmi_cmd_t, 827 ipmi_request_t request, 828 ipmi_response_t response, 829 ipmi_data_len_t data_len, ipmi_context_t) 830 { 831 uint8_t* req = reinterpret_cast<uint8_t*>(request); 832 uint8_t* res = reinterpret_cast<uint8_t*>(response); 833 834 uint8_t index = 0; 835 uint8_t next = 0; 836 uint8_t level = 0; 837 uint8_t pinDef = 0; 838 uint8_t descLen = 0; 839 int ret; 840 841 index = req[3]; 842 843 ret = plat_udbg_get_gpio_desc(index, &next, &level, &pinDef, &descLen, 844 &res[8]); 845 if (ret) 846 { 847 memcpy(res, req, SIZE_IANA_ID); // IANA ID 848 *data_len = SIZE_IANA_ID; 849 return IPMI_CC_UNSPECIFIED_ERROR; 850 } 851 852 memcpy(res, req, SIZE_IANA_ID); // IANA ID 853 res[3] = index; 854 res[4] = next; 855 res[5] = level; 856 res[6] = pinDef; 857 res[7] = descLen; 858 *data_len = SIZE_IANA_ID + 5 + descLen; 859 860 return IPMI_CC_OK; 861 } 862 863 //---------------------------------------------------------------------- 864 // Get Debug Frame Data 865 //---------------------------------------------------------------------- 866 ipmi_ret_t ipmiOemDbgGetFrameData(ipmi_netfn_t, ipmi_cmd_t, 867 ipmi_request_t request, 868 ipmi_response_t response, 869 ipmi_data_len_t data_len, ipmi_context_t) 870 { 871 uint8_t* req = reinterpret_cast<uint8_t*>(request); 872 uint8_t* res = reinterpret_cast<uint8_t*>(response); 873 uint8_t frame; 874 uint8_t page; 875 uint8_t next; 876 uint8_t count; 877 int ret; 878 879 frame = req[3]; 880 page = req[4]; 881 882 ret = plat_udbg_get_frame_data(frame, page, &next, &count, &res[7]); 883 if (ret) 884 { 885 memcpy(res, req, SIZE_IANA_ID); // IANA ID 886 *data_len = SIZE_IANA_ID; 887 return IPMI_CC_UNSPECIFIED_ERROR; 888 } 889 890 memcpy(res, req, SIZE_IANA_ID); // IANA ID 891 res[3] = frame; 892 res[4] = page; 893 res[5] = next; 894 res[6] = count; 895 *data_len = SIZE_IANA_ID + 4 + count; 896 897 return IPMI_CC_OK; 898 } 899 900 //---------------------------------------------------------------------- 901 // Get Debug Control Panel 902 //---------------------------------------------------------------------- 903 ipmi_ret_t ipmiOemDbgGetCtrlPanel(ipmi_netfn_t, ipmi_cmd_t, 904 ipmi_request_t request, 905 ipmi_response_t response, 906 ipmi_data_len_t data_len, ipmi_context_t) 907 { 908 uint8_t* req = reinterpret_cast<uint8_t*>(request); 909 uint8_t* res = reinterpret_cast<uint8_t*>(response); 910 911 uint8_t panel; 912 uint8_t operation; 913 uint8_t item; 914 uint8_t count; 915 ipmi_ret_t ret; 916 917 panel = req[3]; 918 operation = req[4]; 919 item = req[5]; 920 921 ret = plat_udbg_control_panel(panel, operation, item, &count, &res[3]); 922 923 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID 924 *data_len = SIZE_IANA_ID + count; 925 926 return ret; 927 } 928 929 //---------------------------------------------------------------------- 930 // Set Dimm Info (CMD_OEM_SET_DIMM_INFO) 931 //---------------------------------------------------------------------- 932 ipmi_ret_t ipmiOemSetDimmInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, 933 ipmi_response_t, ipmi_data_len_t data_len, 934 ipmi_context_t) 935 { 936 uint8_t* req = reinterpret_cast<uint8_t*>(request); 937 938 uint8_t index = req[0]; 939 uint8_t type = req[1]; 940 uint16_t speed; 941 uint32_t size; 942 943 memcpy(&speed, &req[2], 2); 944 memcpy(&size, &req[4], 4); 945 946 std::stringstream ss; 947 ss << std::hex; 948 ss << std::setw(2) << std::setfill('0') << (int)index; 949 950 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_INDEX] = index; 951 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_TYPE] = type; 952 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_SPEED] = speed; 953 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_SIZE] = size; 954 955 flushOemData(); 956 957 *data_len = 0; 958 959 return IPMI_CC_OK; 960 } 961 962 //---------------------------------------------------------------------- 963 // Get Board ID (CMD_OEM_GET_BOARD_ID) 964 //---------------------------------------------------------------------- 965 ipmi_ret_t ipmiOemGetBoardID(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t, 966 ipmi_response_t, ipmi_data_len_t data_len, 967 ipmi_context_t) 968 { 969 /* TODO: Needs to implement this after GPIO implementation */ 970 *data_len = 0; 971 972 return IPMI_CC_OK; 973 } 974 975 //---------------------------------------------------------------------- 976 // Get port 80 record (CMD_OEM_GET_80PORT_RECORD) 977 //---------------------------------------------------------------------- 978 ipmi::RspType<std::vector<uint8_t>> 979 ipmiOemGet80PortRecord(ipmi::Context::ptr ctx) 980 { 981 auto postCodeService = "xyz.openbmc_project.State.Boot.PostCode" + 982 std::to_string(ctx->hostIdx + 1); 983 auto postCodeObjPath = "/xyz/openbmc_project/State/Boot/PostCode" + 984 std::to_string(ctx->hostIdx + 1); 985 constexpr auto postCodeInterface = 986 "xyz.openbmc_project.State.Boot.PostCode"; 987 const static uint16_t lastestPostCodeIndex = 1; 988 constexpr const auto maxPostCodeLen = 989 224; // The length must be lower than IPMB limitation 990 size_t startIndex = 0; 991 992 std::vector<std::tuple<uint64_t, std::vector<uint8_t>>> postCodes; 993 std::vector<uint8_t> resData; 994 995 auto conn = getSdBus(); 996 /* Get the post codes by calling GetPostCodes method */ 997 auto msg = conn->new_method_call(postCodeService.c_str(), 998 postCodeObjPath.c_str(), postCodeInterface, 999 "GetPostCodes"); 1000 msg.append(lastestPostCodeIndex); 1001 1002 try 1003 { 1004 auto reply = conn->call(msg); 1005 reply.read(postCodes); 1006 } 1007 catch (const sdbusplus::exception::SdBusError& e) 1008 { 1009 phosphor::logging::log<phosphor::logging::level::ERR>( 1010 "IPMI Get80PortRecord Failed in call method", 1011 phosphor::logging::entry("ERROR=%s", e.what())); 1012 return ipmi::responseUnspecifiedError(); 1013 } 1014 1015 /* Get post code data */ 1016 for (size_t i = 0; i < postCodes.size(); ++i) 1017 { 1018 uint64_t primaryPostCode = std::get<uint64_t>(postCodes[i]); 1019 for (int j = postCodeSize - 1; j >= 0; --j) 1020 { 1021 uint8_t postCode = 1022 ((primaryPostCode >> (sizeof(uint64_t) * j)) & 0xFF); 1023 resData.emplace_back(postCode); 1024 } 1025 } 1026 1027 std::vector<uint8_t> response; 1028 if (resData.size() > maxPostCodeLen) 1029 { 1030 startIndex = resData.size() - maxPostCodeLen; 1031 } 1032 1033 response.assign(resData.begin() + startIndex, resData.end()); 1034 1035 return ipmi::responseSuccess(response); 1036 } 1037 1038 //---------------------------------------------------------------------- 1039 // Set Boot Order (CMD_OEM_SET_BOOT_ORDER) 1040 //---------------------------------------------------------------------- 1041 ipmi::RspType<std::vector<uint8_t>> 1042 ipmiOemSetBootOrder(ipmi::Context::ptr ctx, std::vector<uint8_t> bootSeq) 1043 { 1044 size_t len = bootSeq.size(); 1045 1046 if (len != SIZE_BOOT_ORDER) 1047 { 1048 phosphor::logging::log<phosphor::logging::level::ERR>( 1049 "Invalid Boot order length received"); 1050 return ipmi::responseReqDataLenInvalid(); 1051 } 1052 1053 std::optional<size_t> hostId = findHost(ctx->hostIdx); 1054 1055 if (!hostId) 1056 { 1057 phosphor::logging::log<phosphor::logging::level::ERR>( 1058 "Invalid Host Id received"); 1059 return ipmi::responseInvalidCommand(); 1060 } 1061 auto [bootObjPath, hostName] = ipmi::boot::objPath(*hostId); 1062 1063 ipmi::boot::setBootOrder(bootObjPath, bootSeq, hostName); 1064 1065 return ipmi::responseSuccess(bootSeq); 1066 } 1067 1068 //---------------------------------------------------------------------- 1069 // Get Boot Order (CMD_OEM_GET_BOOT_ORDER) 1070 //---------------------------------------------------------------------- 1071 ipmi::RspType<std::vector<uint8_t>> ipmiOemGetBootOrder(ipmi::Context::ptr ctx) 1072 { 1073 std::vector<uint8_t> bootSeq; 1074 1075 std::optional<size_t> hostId = findHost(ctx->hostIdx); 1076 1077 if (!hostId) 1078 { 1079 phosphor::logging::log<phosphor::logging::level::ERR>( 1080 "Invalid Host Id received"); 1081 return ipmi::responseInvalidCommand(); 1082 } 1083 auto [bootObjPath, hostName] = ipmi::boot::objPath(*hostId); 1084 1085 ipmi::boot::getBootOrder(bootObjPath, bootSeq, hostName); 1086 1087 return ipmi::responseSuccess(bootSeq); 1088 } 1089 // Set Machine Config Info (CMD_OEM_SET_MACHINE_CONFIG_INFO) 1090 //---------------------------------------------------------------------- 1091 ipmi_ret_t ipmiOemSetMachineCfgInfo(ipmi_netfn_t, ipmi_cmd_t, 1092 ipmi_request_t request, ipmi_response_t, 1093 ipmi_data_len_t data_len, ipmi_context_t) 1094 { 1095 machineConfigInfo_t* req = reinterpret_cast<machineConfigInfo_t*>(request); 1096 uint8_t len = *data_len; 1097 1098 *data_len = 0; 1099 1100 if (len < sizeof(machineConfigInfo_t)) 1101 { 1102 phosphor::logging::log<phosphor::logging::level::ERR>( 1103 "Invalid machine configuration length received"); 1104 return IPMI_CC_REQ_DATA_LEN_INVALID; 1105 } 1106 1107 if (req->chassis_type >= sizeof(chassisType) / sizeof(uint8_t*)) 1108 oemData[KEY_MC_CONFIG][KEY_MC_CHAS_TYPE] = "UNKNOWN"; 1109 else 1110 oemData[KEY_MC_CONFIG][KEY_MC_CHAS_TYPE] = 1111 chassisType[req->chassis_type]; 1112 1113 if (req->mb_type >= sizeof(mbType) / sizeof(uint8_t*)) 1114 oemData[KEY_MC_CONFIG][KEY_MC_MB_TYPE] = "UNKNOWN"; 1115 else 1116 oemData[KEY_MC_CONFIG][KEY_MC_MB_TYPE] = mbType[req->mb_type]; 1117 1118 oemData[KEY_MC_CONFIG][KEY_MC_PROC_CNT] = req->proc_cnt; 1119 oemData[KEY_MC_CONFIG][KEY_MC_MEM_CNT] = req->mem_cnt; 1120 oemData[KEY_MC_CONFIG][KEY_MC_HDD35_CNT] = req->hdd35_cnt; 1121 oemData[KEY_MC_CONFIG][KEY_MC_HDD25_CNT] = req->hdd25_cnt; 1122 1123 if (req->riser_type >= sizeof(riserType) / sizeof(uint8_t*)) 1124 oemData[KEY_MC_CONFIG][KEY_MC_RSR_TYPE] = "UNKNOWN"; 1125 else 1126 oemData[KEY_MC_CONFIG][KEY_MC_RSR_TYPE] = riserType[req->riser_type]; 1127 1128 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC] = {}; 1129 int i = 0; 1130 if (req->pcie_card_loc & BIT_0) 1131 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT1"; 1132 if (req->pcie_card_loc & BIT_1) 1133 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT2"; 1134 if (req->pcie_card_loc & BIT_2) 1135 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT3"; 1136 if (req->pcie_card_loc & BIT_3) 1137 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT4"; 1138 1139 if (req->slot1_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*)) 1140 oemData[KEY_MC_CONFIG][KEY_MC_SLOT1_TYPE] = "UNKNOWN"; 1141 else 1142 oemData[KEY_MC_CONFIG][KEY_MC_SLOT1_TYPE] = 1143 pcieType[req->slot1_pcie_type]; 1144 1145 if (req->slot2_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*)) 1146 oemData[KEY_MC_CONFIG][KEY_MC_SLOT2_TYPE] = "UNKNOWN"; 1147 else 1148 oemData[KEY_MC_CONFIG][KEY_MC_SLOT2_TYPE] = 1149 pcieType[req->slot2_pcie_type]; 1150 1151 if (req->slot3_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*)) 1152 oemData[KEY_MC_CONFIG][KEY_MC_SLOT3_TYPE] = "UNKNOWN"; 1153 else 1154 oemData[KEY_MC_CONFIG][KEY_MC_SLOT3_TYPE] = 1155 pcieType[req->slot3_pcie_type]; 1156 1157 if (req->slot4_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*)) 1158 oemData[KEY_MC_CONFIG][KEY_MC_SLOT4_TYPE] = "UNKNOWN"; 1159 else 1160 oemData[KEY_MC_CONFIG][KEY_MC_SLOT4_TYPE] = 1161 pcieType[req->slot4_pcie_type]; 1162 1163 oemData[KEY_MC_CONFIG][KEY_MC_AEP_CNT] = req->aep_mem_cnt; 1164 1165 flushOemData(); 1166 1167 return IPMI_CC_OK; 1168 } 1169 1170 //---------------------------------------------------------------------- 1171 // Set POST start (CMD_OEM_SET_POST_START) 1172 //---------------------------------------------------------------------- 1173 ipmi_ret_t ipmiOemSetPostStart(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t, 1174 ipmi_response_t, ipmi_data_len_t data_len, 1175 ipmi_context_t) 1176 { 1177 phosphor::logging::log<phosphor::logging::level::INFO>("POST Start Event"); 1178 1179 /* Do nothing, return success */ 1180 *data_len = 0; 1181 return IPMI_CC_OK; 1182 } 1183 1184 //---------------------------------------------------------------------- 1185 // Set POST End (CMD_OEM_SET_POST_END) 1186 //---------------------------------------------------------------------- 1187 ipmi_ret_t ipmiOemSetPostEnd(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t, 1188 ipmi_response_t, ipmi_data_len_t data_len, 1189 ipmi_context_t) 1190 { 1191 struct timespec ts; 1192 1193 phosphor::logging::log<phosphor::logging::level::INFO>("POST End Event"); 1194 1195 *data_len = 0; 1196 1197 // Timestamp post end time. 1198 clock_gettime(CLOCK_REALTIME, &ts); 1199 oemData[KEY_TS_SLED] = ts.tv_sec; 1200 flushOemData(); 1201 1202 // Sync time with system 1203 // TODO: Add code for syncing time 1204 1205 return IPMI_CC_OK; 1206 } 1207 1208 //---------------------------------------------------------------------- 1209 // Set PPIN Info (CMD_OEM_SET_PPIN_INFO) 1210 //---------------------------------------------------------------------- 1211 // Inform BMC about PPIN data of 8 bytes for each CPU 1212 // 1213 // Request: 1214 // Byte 1:8 – CPU0 PPIN data 1215 // Optional: 1216 // Byte 9:16 – CPU1 PPIN data 1217 // 1218 // Response: 1219 // Byte 1 – Completion Code 1220 ipmi_ret_t ipmiOemSetPPINInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, 1221 ipmi_response_t, ipmi_data_len_t data_len, 1222 ipmi_context_t) 1223 { 1224 uint8_t* req = reinterpret_cast<uint8_t*>(request); 1225 std::string ppinStr; 1226 int len; 1227 1228 if (*data_len > SIZE_CPU_PPIN * 2) 1229 len = SIZE_CPU_PPIN * 2; 1230 else 1231 len = *data_len; 1232 *data_len = 0; 1233 1234 ppinStr = bytesToStr(req, len); 1235 oemData[KEY_PPIN_INFO] = ppinStr.c_str(); 1236 flushOemData(); 1237 1238 return IPMI_CC_OK; 1239 } 1240 1241 //---------------------------------------------------------------------- 1242 // Set ADR Trigger (CMD_OEM_SET_ADR_TRIGGER) 1243 //---------------------------------------------------------------------- 1244 ipmi_ret_t ipmiOemSetAdrTrigger(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t, 1245 ipmi_response_t, ipmi_data_len_t data_len, 1246 ipmi_context_t) 1247 { 1248 /* Do nothing, return success */ 1249 *data_len = 0; 1250 return IPMI_CC_OK; 1251 } 1252 1253 // Helper function to set guid at offset in EEPROM 1254 [[maybe_unused]] static int setGUID(off_t offset, uint8_t* guid) 1255 { 1256 int fd = -1; 1257 ssize_t len; 1258 int ret = 0; 1259 std::string eepromPath = FRU_EEPROM; 1260 1261 // find the eeprom path of MB FRU 1262 auto device = getMbFruDevice(); 1263 if (device) 1264 { 1265 auto [bus, address] = *device; 1266 std::stringstream ss; 1267 ss << "/sys/bus/i2c/devices/" << static_cast<int>(bus) << "-" 1268 << std::setw(4) << std::setfill('0') << std::hex 1269 << static_cast<int>(address) << "/eeprom"; 1270 eepromPath = ss.str(); 1271 } 1272 1273 errno = 0; 1274 1275 // Check if file is present 1276 if (access(eepromPath.c_str(), F_OK) == -1) 1277 { 1278 std::cerr << "Unable to access: " << eepromPath << std::endl; 1279 return errno; 1280 } 1281 1282 // Open the file 1283 fd = open(eepromPath.c_str(), O_WRONLY); 1284 if (fd == -1) 1285 { 1286 std::cerr << "Unable to open: " << eepromPath << std::endl; 1287 return errno; 1288 } 1289 1290 // seek to the offset 1291 lseek(fd, offset, SEEK_SET); 1292 1293 // Write bytes to location 1294 len = write(fd, guid, GUID_SIZE); 1295 if (len != GUID_SIZE) 1296 { 1297 phosphor::logging::log<phosphor::logging::level::ERR>( 1298 "GUID write data to EEPROM failed"); 1299 ret = errno; 1300 } 1301 1302 close(fd); 1303 return ret; 1304 } 1305 1306 //---------------------------------------------------------------------- 1307 // Set System GUID (CMD_OEM_SET_SYSTEM_GUID) 1308 //---------------------------------------------------------------------- 1309 #if BIC_ENABLED 1310 ipmi::RspType<> ipmiOemSetSystemGuid(ipmi::Context::ptr ctx, 1311 std::vector<uint8_t> reqData) 1312 { 1313 std::vector<uint8_t> respData; 1314 1315 if (reqData.size() != GUID_SIZE) // 16bytes 1316 { 1317 return ipmi::responseReqDataLenInvalid(); 1318 } 1319 1320 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2; 1321 1322 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, reqData, respData)) 1323 return ipmi::responseUnspecifiedError(); 1324 1325 return ipmi::responseSuccess(); 1326 } 1327 1328 #else 1329 ipmi_ret_t ipmiOemSetSystemGuid(ipmi_netfn_t, ipmi_cmd_t, 1330 ipmi_request_t request, ipmi_response_t, 1331 ipmi_data_len_t data_len, ipmi_context_t) 1332 { 1333 uint8_t* req = reinterpret_cast<uint8_t*>(request); 1334 1335 if (*data_len != GUID_SIZE) // 16bytes 1336 { 1337 *data_len = 0; 1338 return IPMI_CC_REQ_DATA_LEN_INVALID; 1339 } 1340 1341 *data_len = 0; 1342 1343 if (setGUID(OFFSET_SYS_GUID, req)) 1344 { 1345 return IPMI_CC_UNSPECIFIED_ERROR; 1346 } 1347 return IPMI_CC_OK; 1348 } 1349 #endif 1350 1351 //---------------------------------------------------------------------- 1352 // Set Bios Flash Info (CMD_OEM_SET_BIOS_FLASH_INFO) 1353 //---------------------------------------------------------------------- 1354 ipmi_ret_t ipmiOemSetBiosFlashInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t, 1355 ipmi_response_t, ipmi_data_len_t data_len, 1356 ipmi_context_t) 1357 { 1358 /* Do nothing, return success */ 1359 *data_len = 0; 1360 return IPMI_CC_OK; 1361 } 1362 1363 //---------------------------------------------------------------------- 1364 // Set PPR (CMD_OEM_SET_PPR) 1365 //---------------------------------------------------------------------- 1366 ipmi_ret_t ipmiOemSetPpr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, 1367 ipmi_response_t, ipmi_data_len_t data_len, 1368 ipmi_context_t) 1369 { 1370 uint8_t* req = reinterpret_cast<uint8_t*>(request); 1371 uint8_t pprCnt, pprAct, pprIndex; 1372 uint8_t selParam = req[0]; 1373 uint8_t len = *data_len; 1374 std::stringstream ss; 1375 std::string str; 1376 1377 *data_len = 0; 1378 1379 switch (selParam) 1380 { 1381 case PPR_ACTION: 1382 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) == 1383 oemData[KEY_PPR].end()) 1384 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 1385 1386 pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT]; 1387 if (pprCnt == 0) 1388 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 1389 1390 pprAct = req[1]; 1391 /* Check if ppr is enabled or disabled */ 1392 if (!(pprAct & 0x80)) 1393 pprAct = 0; 1394 1395 oemData[KEY_PPR][KEY_PPR_ACTION] = pprAct; 1396 break; 1397 case PPR_ROW_COUNT: 1398 if (req[1] > 100) 1399 return IPMI_CC_PARM_OUT_OF_RANGE; 1400 1401 oemData[KEY_PPR][KEY_PPR_ROW_COUNT] = req[1]; 1402 break; 1403 case PPR_ROW_ADDR: 1404 pprIndex = req[1]; 1405 if (pprIndex > 100) 1406 return IPMI_CC_PARM_OUT_OF_RANGE; 1407 1408 if (len < PPR_ROW_ADDR_LEN + 1) 1409 { 1410 phosphor::logging::log<phosphor::logging::level::ERR>( 1411 "Invalid PPR Row Address length received"); 1412 return IPMI_CC_REQ_DATA_LEN_INVALID; 1413 } 1414 1415 ss << std::hex; 1416 ss << std::setw(2) << std::setfill('0') << (int)pprIndex; 1417 1418 oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex; 1419 1420 str = bytesToStr(&req[1], PPR_ROW_ADDR_LEN); 1421 oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR] = str.c_str(); 1422 break; 1423 case PPR_HISTORY_DATA: 1424 pprIndex = req[1]; 1425 if (pprIndex > 100) 1426 return IPMI_CC_PARM_OUT_OF_RANGE; 1427 1428 if (len < PPR_HST_DATA_LEN + 1) 1429 { 1430 phosphor::logging::log<phosphor::logging::level::ERR>( 1431 "Invalid PPR history data length received"); 1432 return IPMI_CC_REQ_DATA_LEN_INVALID; 1433 } 1434 1435 ss << std::hex; 1436 ss << std::setw(2) << std::setfill('0') << (int)pprIndex; 1437 1438 oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex; 1439 1440 str = bytesToStr(&req[1], PPR_HST_DATA_LEN); 1441 oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA] = str.c_str(); 1442 break; 1443 default: 1444 return IPMI_CC_PARM_OUT_OF_RANGE; 1445 break; 1446 } 1447 1448 flushOemData(); 1449 1450 return IPMI_CC_OK; 1451 } 1452 1453 //---------------------------------------------------------------------- 1454 // Get PPR (CMD_OEM_GET_PPR) 1455 //---------------------------------------------------------------------- 1456 ipmi_ret_t ipmiOemGetPpr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, 1457 ipmi_response_t response, ipmi_data_len_t data_len, 1458 ipmi_context_t) 1459 { 1460 uint8_t* req = reinterpret_cast<uint8_t*>(request); 1461 uint8_t* res = reinterpret_cast<uint8_t*>(response); 1462 uint8_t pprCnt, pprIndex; 1463 uint8_t selParam = req[0]; 1464 std::stringstream ss; 1465 std::string str; 1466 1467 /* Any failure will return zero length data */ 1468 *data_len = 0; 1469 1470 switch (selParam) 1471 { 1472 case PPR_ACTION: 1473 res[0] = 0; 1474 *data_len = 1; 1475 1476 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) != 1477 oemData[KEY_PPR].end()) 1478 { 1479 pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT]; 1480 if (pprCnt != 0) 1481 { 1482 if (oemData[KEY_PPR].find(KEY_PPR_ACTION) != 1483 oemData[KEY_PPR].end()) 1484 { 1485 res[0] = oemData[KEY_PPR][KEY_PPR_ACTION]; 1486 } 1487 } 1488 } 1489 break; 1490 case PPR_ROW_COUNT: 1491 res[0] = 0; 1492 *data_len = 1; 1493 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) != 1494 oemData[KEY_PPR].end()) 1495 res[0] = oemData[KEY_PPR][KEY_PPR_ROW_COUNT]; 1496 break; 1497 case PPR_ROW_ADDR: 1498 pprIndex = req[1]; 1499 if (pprIndex > 100) 1500 return IPMI_CC_PARM_OUT_OF_RANGE; 1501 1502 ss << std::hex; 1503 ss << std::setw(2) << std::setfill('0') << (int)pprIndex; 1504 1505 if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end()) 1506 return IPMI_CC_PARM_OUT_OF_RANGE; 1507 1508 if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_ROW_ADDR) == 1509 oemData[KEY_PPR][ss.str()].end()) 1510 return IPMI_CC_PARM_OUT_OF_RANGE; 1511 1512 str = oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR]; 1513 *data_len = strToBytes(str, res); 1514 break; 1515 case PPR_HISTORY_DATA: 1516 pprIndex = req[1]; 1517 if (pprIndex > 100) 1518 return IPMI_CC_PARM_OUT_OF_RANGE; 1519 1520 ss << std::hex; 1521 ss << std::setw(2) << std::setfill('0') << (int)pprIndex; 1522 1523 if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end()) 1524 return IPMI_CC_PARM_OUT_OF_RANGE; 1525 1526 if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_HST_DATA) == 1527 oemData[KEY_PPR][ss.str()].end()) 1528 return IPMI_CC_PARM_OUT_OF_RANGE; 1529 1530 str = oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA]; 1531 *data_len = strToBytes(str, res); 1532 break; 1533 default: 1534 return IPMI_CC_PARM_OUT_OF_RANGE; 1535 break; 1536 } 1537 1538 return IPMI_CC_OK; 1539 } 1540 1541 /* FB OEM QC Commands */ 1542 1543 //---------------------------------------------------------------------- 1544 // Set Proc Info (CMD_OEM_Q_SET_PROC_INFO) 1545 //---------------------------------------------------------------------- 1546 //"Request: 1547 // Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first 1548 // Byte 4 – Processor Index, 0 base 1549 // Byte 5 – Parameter Selector 1550 // Byte 6..N – Configuration parameter data (see below for Parameters 1551 // of Processor Information) 1552 // Response: 1553 // Byte 1 – Completion code 1554 // 1555 // Parameter#1: (Processor Product Name) 1556 // 1557 // Byte 1..48 –Product name(ASCII code) 1558 // Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz 1559 // 1560 // Param#2: Processor Basic Information 1561 // Byte 1 – Core Number 1562 // Byte 2 – Thread Number (LSB) 1563 // Byte 3 – Thread Number (MSB) 1564 // Byte 4 – Processor frequency in MHz (LSB) 1565 // Byte 5 – Processor frequency in MHz (MSB) 1566 // Byte 6..7 – Revision 1567 // 1568 1569 ipmi::RspType<> ipmiOemQSetProcInfo(ipmi::Context::ptr ctx, uint8_t, uint8_t, 1570 uint8_t, uint8_t procIndex, 1571 uint8_t paramSel, 1572 std::vector<uint8_t> request) 1573 { 1574 uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*); 1575 std::stringstream ss; 1576 std::string str; 1577 uint8_t len = request.size(); 1578 auto hostId = findHost(ctx->hostIdx); 1579 if (!hostId) 1580 { 1581 phosphor::logging::log<phosphor::logging::level::ERR>( 1582 "Invalid Host Id received"); 1583 return ipmi::responseInvalidCommand(); 1584 } 1585 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(*hostId); 1586 /* check for requested data params */ 1587 if (len < 5 || paramSel < 1 || paramSel >= numParam) 1588 { 1589 phosphor::logging::log<phosphor::logging::level::ERR>( 1590 "Invalid parameter received"); 1591 return ipmi::responseParmOutOfRange(); 1592 } 1593 ss << std::hex; 1594 ss << std::setw(2) << std::setfill('0') << (int)procIndex; 1595 oemData[procInfo][ss.str()][KEY_PROC_INDEX] = procIndex; 1596 str = bytesToStr(request.data(), len); 1597 oemData[procInfo][ss.str()][cpuInfoKey[paramSel]] = str.c_str(); 1598 flushOemData(); 1599 return ipmi::responseSuccess(); 1600 } 1601 1602 //---------------------------------------------------------------------- 1603 // Get Proc Info (CMD_OEM_Q_GET_PROC_INFO) 1604 //---------------------------------------------------------------------- 1605 // Request: 1606 // Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first 1607 // Byte 4 – Processor Index, 0 base 1608 // Byte 5 – Parameter Selector 1609 // Response: 1610 // Byte 1 – Completion code 1611 // Byte 2..N – Configuration Parameter Data (see below for Parameters 1612 // of Processor Information) 1613 // 1614 // Parameter#1: (Processor Product Name) 1615 // 1616 // Byte 1..48 –Product name(ASCII code) 1617 // Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz 1618 // 1619 // Param#2: Processor Basic Information 1620 // Byte 1 – Core Number 1621 // Byte 2 – Thread Number (LSB) 1622 // Byte 3 – Thread Number (MSB) 1623 // Byte 4 – Processor frequency in MHz (LSB) 1624 // Byte 5 – Processor frequency in MHz (MSB) 1625 // Byte 6..7 – Revision 1626 // 1627 1628 ipmi::RspType<std::vector<uint8_t>> 1629 ipmiOemQGetProcInfo(ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, 1630 uint8_t procIndex, uint8_t paramSel) 1631 { 1632 uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*); 1633 std::stringstream ss; 1634 std::string str; 1635 uint8_t res[MAX_BUF]; 1636 auto hostId = findHost(ctx->hostIdx); 1637 if (!hostId) 1638 { 1639 phosphor::logging::log<phosphor::logging::level::ERR>( 1640 "Invalid Host Id received"); 1641 return ipmi::responseInvalidCommand(); 1642 } 1643 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(*hostId); 1644 if (paramSel < 1 || paramSel >= numParam) 1645 { 1646 phosphor::logging::log<phosphor::logging::level::ERR>( 1647 "Invalid parameter received"); 1648 return ipmi::responseParmOutOfRange(); 1649 } 1650 ss << std::hex; 1651 ss << std::setw(2) << std::setfill('0') << (int)procIndex; 1652 if (oemData[procInfo].find(ss.str()) == oemData[procInfo].end()) 1653 return ipmi::responseCommandNotAvailable(); 1654 if (oemData[procInfo][ss.str()].find(cpuInfoKey[paramSel]) == 1655 oemData[procInfo][ss.str()].end()) 1656 return ipmi::responseCommandNotAvailable(); 1657 str = oemData[procInfo][ss.str()][cpuInfoKey[paramSel]]; 1658 int dataLen = strToBytes(str, res); 1659 std::vector<uint8_t> response(&res[0], &res[dataLen]); 1660 return ipmi::responseSuccess(response); 1661 } 1662 1663 //---------------------------------------------------------------------- 1664 // Set Dimm Info (CMD_OEM_Q_SET_DIMM_INFO) 1665 //---------------------------------------------------------------------- 1666 // Request: 1667 // Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first 1668 // Byte 4 – DIMM Index, 0 base 1669 // Byte 5 – Parameter Selector 1670 // Byte 6..N – Configuration parameter data (see below for Parameters 1671 // of DIMM Information) 1672 // Response: 1673 // Byte 1 – Completion code 1674 // 1675 // Param#1 (DIMM Location): 1676 // Byte 1 – DIMM Present 1677 // Byte 1 – DIMM Present 1678 // 01h – Present 1679 // FFh – Not Present 1680 // Byte 2 – Node Number, 0 base 1681 // Byte 3 – Channel Number , 0 base 1682 // Byte 4 – DIMM Number , 0 base 1683 // 1684 // Param#2 (DIMM Type): 1685 // Byte 1 – DIMM Type 1686 // Bit [7:6] 1687 // For DDR3 1688 // 00 – Normal Voltage (1.5V) 1689 // 01 – Ultra Low Voltage (1.25V) 1690 // 10 – Low Voltage (1.35V) 1691 // 11 – Reserved 1692 // For DDR4 1693 // 00 – Reserved 1694 // 01 – Reserved 1695 // 10 – Reserved 1696 // 11 – Normal Voltage (1.2V) 1697 // Bit [5:0] 1698 // 0x00 – SDRAM 1699 // 0x01 – DDR-1 RAM 1700 // 0x02 – Rambus 1701 // 0x03 – DDR-2 RAM 1702 // 0x04 – FBDIMM 1703 // 0x05 – DDR-3 RAM 1704 // 0x06 – DDR-4 RAM 1705 // 1706 // Param#3 (DIMM Speed): 1707 // Byte 1..2 – DIMM speed in MHz, LSB 1708 // Byte 3..6 – DIMM size in Mbytes, LSB 1709 // 1710 // Param#4 (Module Part Number): 1711 // Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C) 1712 // 1713 // Param#5 (Module Serial Number): 1714 // Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C) 1715 // 1716 // Param#6 (Module Manufacturer ID): 1717 // Byte 1 - Module Manufacturer ID, LSB 1718 // Byte 2 - Module Manufacturer ID, MSB 1719 // 1720 ipmi::RspType<> ipmiOemQSetDimmInfo(ipmi::Context::ptr ctx, uint8_t, uint8_t, 1721 uint8_t, uint8_t dimmIndex, 1722 uint8_t paramSel, 1723 std::vector<uint8_t> request) 1724 { 1725 uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*); 1726 std::stringstream ss; 1727 std::string str; 1728 uint8_t len = request.size(); 1729 std::string dimmType; 1730 readDimmType(dimmType, dimmIndex); 1731 auto hostId = findHost(ctx->hostIdx); 1732 if (!hostId) 1733 { 1734 phosphor::logging::log<phosphor::logging::level::ERR>( 1735 "Invalid Host Id received"); 1736 return ipmi::responseInvalidCommand(); 1737 } 1738 1739 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(*hostId); 1740 1741 if (len < 3 || paramSel < 1 || paramSel >= numParam) 1742 { 1743 phosphor::logging::log<phosphor::logging::level::ERR>( 1744 "Invalid parameter received"); 1745 return ipmi::responseParmOutOfRange(); 1746 } 1747 1748 ss << std::hex; 1749 ss << (int)dimmIndex; 1750 oemData[dimmInfo][ss.str()][KEY_DIMM_INDEX] = dimmIndex; 1751 oemData[dimmInfo][ss.str()][KEY_DIMM_TYPE] = dimmType; 1752 str = bytesToStr(request.data(), len); 1753 oemData[dimmInfo][ss.str()][dimmInfoKey[paramSel]] = str.c_str(); 1754 flushOemData(); 1755 return ipmi::responseSuccess(); 1756 } 1757 1758 // Get Dimm Info (CMD_OEM_Q_GET_DIMM_INFO) 1759 //---------------------------------------------------------------------- 1760 // Request: 1761 // Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first 1762 // Byte 4 – DIMM Index, 0 base 1763 // Byte 5 – Parameter Selector 1764 // Byte 6..N – Configuration parameter data (see below for Parameters 1765 // of DIMM Information) 1766 // Response: 1767 // Byte 1 – Completion code 1768 // Byte 2..N – Configuration Parameter Data (see Table_1213h Parameters 1769 // of DIMM Information) 1770 // 1771 // Param#1 (DIMM Location): 1772 // Byte 1 – DIMM Present 1773 // Byte 1 – DIMM Present 1774 // 01h – Present 1775 // FFh – Not Present 1776 // Byte 2 – Node Number, 0 base 1777 // Byte 3 – Channel Number , 0 base 1778 // Byte 4 – DIMM Number , 0 base 1779 // 1780 // Param#2 (DIMM Type): 1781 // Byte 1 – DIMM Type 1782 // Bit [7:6] 1783 // For DDR3 1784 // 00 – Normal Voltage (1.5V) 1785 // 01 – Ultra Low Voltage (1.25V) 1786 // 10 – Low Voltage (1.35V) 1787 // 11 – Reserved 1788 // For DDR4 1789 // 00 – Reserved 1790 // 01 – Reserved 1791 // 10 – Reserved 1792 // 11 – Normal Voltage (1.2V) 1793 // Bit [5:0] 1794 // 0x00 – SDRAM 1795 // 0x01 – DDR-1 RAM 1796 // 0x02 – Rambus 1797 // 0x03 – DDR-2 RAM 1798 // 0x04 – FBDIMM 1799 // 0x05 – DDR-3 RAM 1800 // 0x06 – DDR-4 RAM 1801 // 1802 // Param#3 (DIMM Speed): 1803 // Byte 1..2 – DIMM speed in MHz, LSB 1804 // Byte 3..6 – DIMM size in Mbytes, LSB 1805 // 1806 // Param#4 (Module Part Number): 1807 // Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C) 1808 // 1809 // Param#5 (Module Serial Number): 1810 // Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C) 1811 // 1812 // Param#6 (Module Manufacturer ID): 1813 // Byte 1 - Module Manufacturer ID, LSB 1814 // Byte 2 - Module Manufacturer ID, MSB 1815 // 1816 ipmi::RspType<std::vector<uint8_t>> 1817 ipmiOemQGetDimmInfo(ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, 1818 uint8_t dimmIndex, uint8_t paramSel) 1819 { 1820 uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*); 1821 uint8_t res[MAX_BUF]; 1822 std::stringstream ss; 1823 std::string str; 1824 std::string dimmType; 1825 readDimmType(dimmType, dimmIndex); 1826 auto hostId = findHost(ctx->hostIdx); 1827 if (!hostId) 1828 { 1829 phosphor::logging::log<phosphor::logging::level::ERR>( 1830 "Invalid Host Id received"); 1831 return ipmi::responseInvalidCommand(); 1832 } 1833 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(*hostId); 1834 1835 if (paramSel < 1 || paramSel >= numParam) 1836 { 1837 phosphor::logging::log<phosphor::logging::level::ERR>( 1838 "Invalid parameter received"); 1839 return ipmi::responseParmOutOfRange(); 1840 } 1841 ss << std::hex; 1842 ss << (int)dimmIndex; 1843 oemData[dimmInfo][ss.str()][KEY_DIMM_TYPE] = dimmType; 1844 if (oemData[dimmInfo].find(ss.str()) == oemData[dimmInfo].end()) 1845 return ipmi::responseCommandNotAvailable(); 1846 if (oemData[dimmInfo][ss.str()].find(dimmInfoKey[paramSel]) == 1847 oemData[dimmInfo][ss.str()].end()) 1848 return ipmi::responseCommandNotAvailable(); 1849 str = oemData[dimmInfo][ss.str()][dimmInfoKey[paramSel]]; 1850 int data_length = strToBytes(str, res); 1851 std::vector<uint8_t> response(&res[0], &res[data_length]); 1852 return ipmi::responseSuccess(response); 1853 } 1854 1855 //---------------------------------------------------------------------- 1856 // Set Drive Info (CMD_OEM_Q_SET_DRIVE_INFO) 1857 //---------------------------------------------------------------------- 1858 // BIOS issue this command to provide HDD information to BMC. 1859 // 1860 // BIOS just can get information by standard ATA / SMART command for 1861 // OB SATA controller. 1862 // BIOS can get 1863 // 1. Serial Number 1864 // 2. Model Name 1865 // 3. HDD FW Version 1866 // 4. HDD Capacity 1867 // 5. HDD WWN 1868 // 1869 // Use Get HDD info Param #5 to know the MAX HDD info index. 1870 // 1871 // Request: 1872 // Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first 1873 // Byte 4 – 1874 // [7:4] Reserved 1875 // [3:0] HDD Controller Type 1876 // 0x00 – BIOS 1877 // 0x01 – Expander 1878 // 0x02 – LSI 1879 // Byte 5 – HDD Info Index, 0 base 1880 // Byte 6 – Parameter Selector 1881 // Byte 7..N – Configuration parameter data (see Table_1415h Parameters of HDD 1882 // Information) 1883 // 1884 // Response: 1885 // Byte 1 – Completion Code 1886 // 1887 // Param#0 (HDD Location): 1888 // Byte 1 – Controller 1889 // [7:3] Device Number 1890 // [2:0] Function Number 1891 // For Intel C610 series (Wellsburg) 1892 // D31:F2 (0xFA) – SATA control 1 1893 // D31:F5 (0xFD) – SATA control 2 1894 // D17:F4 (0x8C) – sSata control 1895 // Byte 2 – Port Number 1896 // Byte 3 – Location (0xFF: No HDD Present) 1897 // BIOS default set Byte 3 to 0xFF, if No HDD Present. And then skip send param 1898 // #1~4, #6, #7 to BMC (still send param #5) BIOS default set Byte 3 to 0, if 1899 // the HDD present. BMC or other people who know the HDD location has 1900 // responsibility for update Location info 1901 // 1902 // Param#1 (Serial Number): 1903 // Bytes 1..33: HDD Serial Number 1904 // 1905 // Param#2 (Model Name): 1906 // Byte 1..33 – HDD Model Name 1907 // 1908 // Param#3 (HDD FW Version): 1909 // Byte 1..17 –HDD FW version 1910 // 1911 // Param#4 (Capacity): 1912 // Byte 1..4 –HDD Block Size, LSB 1913 // Byte 5..12 - HDD Block Number, LSB 1914 // HDD Capacity = HDD Block size * HDD BLock number (Unit Byte) 1915 // 1916 // Param#5 (Max HDD Quantity): 1917 // Byte 1 - Max HDD Quantity 1918 // Max supported port numbers in this PCH 1919 // 1920 // Param#6 (HDD Type) 1921 // Byte 1 – HDD Type 1922 // 0h – Reserved 1923 // 1h – SAS 1924 // 2h – SATA 1925 // 3h – PCIE SSD (NVME) 1926 // 1927 // Param#7 (HDD WWN) 1928 // Data 1...8: HDD World Wide Name, LSB 1929 // 1930 ipmi_ret_t ipmiOemQSetDriveInfo(ipmi_netfn_t, ipmi_cmd_t, 1931 ipmi_request_t request, ipmi_response_t, 1932 ipmi_data_len_t data_len, ipmi_context_t) 1933 { 1934 qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request); 1935 uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*); 1936 uint8_t ctrlType = req->hddCtrlType & 0x0f; 1937 std::stringstream ss; 1938 std::string str; 1939 uint8_t len = *data_len; 1940 1941 *data_len = 0; 1942 1943 /* check for requested data params */ 1944 if (len < 6 || req->paramSel < 1 || req->paramSel >= numParam || 1945 ctrlType > 2) 1946 { 1947 phosphor::logging::log<phosphor::logging::level::ERR>( 1948 "Invalid parameter received"); 1949 return IPMI_CC_PARM_OUT_OF_RANGE; 1950 } 1951 1952 len = len - 6; // Get Actual data length 1953 1954 ss << std::hex; 1955 ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex; 1956 oemData[KEY_Q_DRIVE_INFO][KEY_HDD_CTRL_TYPE] = req->hddCtrlType; 1957 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()][KEY_HDD_INDEX] = 1958 req->hddIndex; 1959 1960 str = bytesToStr(req->data, len); 1961 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()] 1962 [driveInfoKey[req->paramSel]] = str.c_str(); 1963 flushOemData(); 1964 1965 return IPMI_CC_OK; 1966 } 1967 1968 //---------------------------------------------------------------------- 1969 // Get Drive Info (CMD_OEM_Q_GET_DRIVE_INFO) 1970 //---------------------------------------------------------------------- 1971 // BMC needs to check HDD presented or not first. If NOT presented, return 1972 // completion code 0xD5. 1973 // 1974 // Request: 1975 // Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first 1976 // Byte 4 – 1977 //[7:4] Reserved 1978 //[3:0] HDD Controller Type 1979 // 0x00 – BIOS 1980 // 0x01 – Expander 1981 // 0x02 – LSI 1982 // Byte 5 – HDD Index, 0 base 1983 // Byte 6 – Parameter Selector (See Above Set HDD Information) 1984 // Response: 1985 // Byte 1 – Completion Code 1986 // 0xD5 – Not support in current status (HDD Not Present) 1987 // Byte 2..N – Configuration parameter data (see Table_1415h Parameters of HDD 1988 // Information) 1989 // 1990 ipmi_ret_t ipmiOemQGetDriveInfo(ipmi_netfn_t, ipmi_cmd_t, 1991 ipmi_request_t request, 1992 ipmi_response_t response, 1993 ipmi_data_len_t data_len, ipmi_context_t) 1994 { 1995 qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request); 1996 uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*); 1997 uint8_t* res = reinterpret_cast<uint8_t*>(response); 1998 uint8_t ctrlType = req->hddCtrlType & 0x0f; 1999 std::stringstream ss; 2000 std::string str; 2001 2002 *data_len = 0; 2003 2004 /* check for requested data params */ 2005 if (req->paramSel < 1 || req->paramSel >= numParam || ctrlType > 2) 2006 { 2007 phosphor::logging::log<phosphor::logging::level::ERR>( 2008 "Invalid parameter received"); 2009 return IPMI_CC_PARM_OUT_OF_RANGE; 2010 } 2011 2012 if (oemData[KEY_Q_DRIVE_INFO].find(ctrlTypeKey[ctrlType]) == 2013 oemData[KEY_Q_DRIVE_INFO].end()) 2014 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 2015 2016 ss << std::hex; 2017 ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex; 2018 2019 if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]].find(ss.str()) == 2020 oemData[KEY_Q_DRIVE_INFO].end()) 2021 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 2022 2023 if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()].find( 2024 dimmInfoKey[req->paramSel]) == 2025 oemData[KEY_Q_DRIVE_INFO][ss.str()].end()) 2026 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 2027 2028 str = oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()] 2029 [dimmInfoKey[req->paramSel]]; 2030 *data_len = strToBytes(str, res); 2031 2032 return IPMI_CC_OK; 2033 } 2034 2035 /* Helper function for sending DCMI commands to ME/BIC and 2036 * getting response back 2037 */ 2038 ipmi::RspType<std::vector<uint8_t>> 2039 sendDCMICmd([[maybe_unused]] ipmi::Context::ptr ctx, 2040 [[maybe_unused]] uint8_t cmd, std::vector<uint8_t>& cmdData) 2041 { 2042 std::vector<uint8_t> respData; 2043 2044 #if BIC_ENABLED 2045 2046 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2; 2047 2048 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, cmdData, respData)) 2049 { 2050 return ipmi::responseUnspecifiedError(); 2051 } 2052 2053 #else 2054 2055 /* Add group id as first byte to request for ME command */ 2056 cmdData.insert(cmdData.begin(), groupDCMI); 2057 2058 if (sendMeCmd(ipmi::netFnGroup, cmd, cmdData, respData)) 2059 { 2060 return ipmi::responseUnspecifiedError(); 2061 } 2062 2063 /* Remove group id as first byte as it will be added by IPMID */ 2064 respData.erase(respData.begin()); 2065 2066 #endif 2067 2068 return ipmi::responseSuccess(std::move(respData)); 2069 } 2070 2071 /* DCMI Command handellers. */ 2072 2073 ipmi::RspType<std::vector<uint8_t>> 2074 ipmiOemDCMIGetPowerReading(ipmi::Context::ptr ctx, 2075 std::vector<uint8_t> reqData) 2076 { 2077 return sendDCMICmd(ctx, ipmi::dcmi::cmdGetPowerReading, reqData); 2078 } 2079 2080 ipmi::RspType<std::vector<uint8_t>> 2081 ipmiOemDCMIGetPowerLimit(ipmi::Context::ptr ctx, 2082 std::vector<uint8_t> reqData) 2083 { 2084 return sendDCMICmd(ctx, ipmi::dcmi::cmdGetPowerLimit, reqData); 2085 } 2086 2087 ipmi::RspType<std::vector<uint8_t>> 2088 ipmiOemDCMISetPowerLimit(ipmi::Context::ptr ctx, 2089 std::vector<uint8_t> reqData) 2090 { 2091 return sendDCMICmd(ctx, ipmi::dcmi::cmdSetPowerLimit, reqData); 2092 } 2093 2094 ipmi::RspType<std::vector<uint8_t>> 2095 ipmiOemDCMIApplyPowerLimit(ipmi::Context::ptr ctx, 2096 std::vector<uint8_t> reqData) 2097 { 2098 return sendDCMICmd(ctx, ipmi::dcmi::cmdActDeactivatePwrLimit, reqData); 2099 } 2100 2101 // OEM Crashdump related functions 2102 static ipmi_ret_t setDumpState(CrdState& currState, CrdState newState) 2103 { 2104 switch (newState) 2105 { 2106 case CrdState::waitData: 2107 if (currState == CrdState::packing) 2108 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 2109 break; 2110 case CrdState::packing: 2111 if (currState != CrdState::waitData) 2112 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 2113 break; 2114 case CrdState::free: 2115 break; 2116 default: 2117 return IPMI_CC_UNSPECIFIED_ERROR; 2118 } 2119 currState = newState; 2120 2121 return IPMI_CC_OK; 2122 } 2123 2124 static ipmi_ret_t handleMcaBank(const CrashDumpHdr& hdr, 2125 std::span<const uint8_t> data, 2126 CrdState& currState, std::stringstream& ss) 2127 { 2128 if (data.size() < sizeof(CrdMcaBank)) 2129 return IPMI_CC_REQ_DATA_LEN_INVALID; 2130 2131 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2132 if (res) 2133 return res; 2134 2135 const auto* pBank = reinterpret_cast<const CrdMcaBank*>(data.data()); 2136 ss << std::format(" Bank ID : 0x{:02X}, Core ID : 0x{:02X}\n", 2137 hdr.bankHdr.bankId, hdr.bankHdr.coreId); 2138 ss << std::format(" MCA_CTRL : 0x{:016X}\n", pBank->mcaCtrl); 2139 ss << std::format(" MCA_STATUS : 0x{:016X}\n", pBank->mcaSts); 2140 ss << std::format(" MCA_ADDR : 0x{:016X}\n", pBank->mcaAddr); 2141 ss << std::format(" MCA_MISC0 : 0x{:016X}\n", pBank->mcaMisc0); 2142 ss << std::format(" MCA_CTRL_MASK : 0x{:016X}\n", pBank->mcaCtrlMask); 2143 ss << std::format(" MCA_CONFIG : 0x{:016X}\n", pBank->mcaConfig); 2144 ss << std::format(" MCA_IPID : 0x{:016X}\n", pBank->mcaIpid); 2145 ss << std::format(" MCA_SYND : 0x{:016X}\n", pBank->mcaSynd); 2146 ss << std::format(" MCA_DESTAT : 0x{:016X}\n", pBank->mcaDestat); 2147 ss << std::format(" MCA_DEADDR : 0x{:016X}\n", pBank->mcaDeaddr); 2148 ss << std::format(" MCA_MISC1 : 0x{:016X}\n", pBank->mcaMisc1); 2149 ss << "\n"; 2150 2151 return IPMI_CC_OK; 2152 } 2153 2154 template <typename T> 2155 static ipmi_ret_t handleVirtualBank(std::span<const uint8_t> data, 2156 CrdState& currState, std::stringstream& ss) 2157 { 2158 if (data.size() < sizeof(T)) 2159 return IPMI_CC_REQ_DATA_LEN_INVALID; 2160 2161 const auto* pBank = reinterpret_cast<const T*>(data.data()); 2162 2163 if (data.size() < sizeof(T) + sizeof(BankCorePair) * pBank->mcaCount) 2164 return IPMI_CC_REQ_DATA_LEN_INVALID; 2165 2166 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2167 if (res) 2168 return res; 2169 2170 ss << " Virtual Bank\n"; 2171 ss << std::format(" S5_RESET_STATUS : 0x{:08X}\n", pBank->s5ResetSts); 2172 ss << std::format(" PM_BREAKEVENT : 0x{:08X}\n", pBank->breakevent); 2173 if constexpr (std::is_same_v<T, CrdVirtualBankV3>) 2174 { 2175 ss << std::format(" WARMCOLDRSTSTATUS : 0x{:08X}\n", pBank->rstSts); 2176 } 2177 ss << std::format(" PROCESSOR NUMBER : 0x{:04X}\n", pBank->procNum); 2178 ss << std::format(" APIC ID : 0x{:08X}\n", pBank->apicId); 2179 ss << std::format(" EAX : 0x{:08X}\n", pBank->eax); 2180 ss << std::format(" EBX : 0x{:08X}\n", pBank->ebx); 2181 ss << std::format(" ECX : 0x{:08X}\n", pBank->ecx); 2182 ss << std::format(" EDX : 0x{:08X}\n", pBank->edx); 2183 ss << " VALID LIST : "; 2184 for (size_t i = 0; i < pBank->mcaCount; i++) 2185 { 2186 ss << std::format("(0x{:02X},0x{:02X}) ", pBank->mcaList[i].bankId, 2187 pBank->mcaList[i].coreId); 2188 } 2189 ss << "\n\n"; 2190 2191 return IPMI_CC_OK; 2192 } 2193 2194 static ipmi_ret_t handleCpuWdtBank(std::span<const uint8_t> data, 2195 CrdState& currState, std::stringstream& ss) 2196 { 2197 if (data.size() < sizeof(CrdCpuWdtBank)) 2198 return IPMI_CC_REQ_DATA_LEN_INVALID; 2199 2200 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2201 if (res) 2202 return res; 2203 2204 const auto* pBank = reinterpret_cast<const CrdCpuWdtBank*>(data.data()); 2205 for (size_t i = 0; i < ccmNum; i++) 2206 { 2207 ss << std::format(" [CCM{}]\n", i); 2208 ss << std::format(" HwAssertStsHi : 0x{:08X}\n", 2209 pBank->hwAssertStsHi[i]); 2210 ss << std::format(" HwAssertStsLo : 0x{:08X}\n", 2211 pBank->hwAssertStsLo[i]); 2212 ss << std::format(" OrigWdtAddrLogHi : 0x{:08X}\n", 2213 pBank->origWdtAddrLogHi[i]); 2214 ss << std::format(" OrigWdtAddrLogLo : 0x{:08X}\n", 2215 pBank->origWdtAddrLogLo[i]); 2216 ss << std::format(" HwAssertMskHi : 0x{:08X}\n", 2217 pBank->hwAssertMskHi[i]); 2218 ss << std::format(" HwAssertMskLo : 0x{:08X}\n", 2219 pBank->hwAssertMskLo[i]); 2220 ss << std::format(" OrigWdtAddrLogStat : 0x{:08X}\n", 2221 pBank->origWdtAddrLogStat[i]); 2222 } 2223 ss << "\n"; 2224 2225 return IPMI_CC_OK; 2226 } 2227 2228 template <size_t N> 2229 static ipmi_ret_t handleHwAssertBank(const char* name, 2230 std::span<const uint8_t> data, 2231 CrdState& currState, std::stringstream& ss) 2232 { 2233 if (data.size() < sizeof(CrdHwAssertBank<N>)) 2234 return IPMI_CC_REQ_DATA_LEN_INVALID; 2235 2236 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2237 if (res) 2238 return res; 2239 2240 const CrdHwAssertBank<N>* pBank = 2241 reinterpret_cast<const CrdHwAssertBank<N>*>(data.data()); 2242 2243 for (size_t i = 0; i < N; i++) 2244 { 2245 ss << std::format(" [{}{}]\n", name, i); 2246 ss << std::format(" HwAssertStsHi : 0x{:08X}\n", 2247 pBank->hwAssertStsHi[i]); 2248 ss << std::format(" HwAssertStsLo : 0x{:08X}\n", 2249 pBank->hwAssertStsLo[i]); 2250 ss << std::format(" HwAssertMskHi : 0x{:08X}\n", 2251 pBank->hwAssertMskHi[i]); 2252 ss << std::format(" HwAssertMskLo : 0x{:08X}\n", 2253 pBank->hwAssertMskLo[i]); 2254 } 2255 ss << "\n"; 2256 2257 return IPMI_CC_OK; 2258 } 2259 2260 static ipmi_ret_t handlePcieAerBank(std::span<const uint8_t> data, 2261 CrdState& currState, std::stringstream& ss) 2262 { 2263 if (data.size() < sizeof(CrdPcieAerBank)) 2264 return IPMI_CC_REQ_DATA_LEN_INVALID; 2265 2266 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2267 if (res) 2268 return res; 2269 2270 const auto* pBank = reinterpret_cast<const CrdPcieAerBank*>(data.data()); 2271 ss << std::format(" [Bus{} Dev{} Fun{}]\n", pBank->bus, pBank->dev, 2272 pBank->fun); 2273 ss << std::format(" Command : 0x{:04X}\n", 2274 pBank->cmd); 2275 ss << std::format(" Status : 0x{:04X}\n", 2276 pBank->sts); 2277 ss << std::format(" Slot : 0x{:04X}\n", 2278 pBank->slot); 2279 ss << std::format(" Secondary Bus : 0x{:02X}\n", 2280 pBank->secondBus); 2281 ss << std::format(" Vendor ID : 0x{:04X}\n", 2282 pBank->vendorId); 2283 ss << std::format(" Device ID : 0x{:04X}\n", 2284 pBank->devId); 2285 ss << std::format(" Class Code : 0x{:02X}{:04X}\n", 2286 pBank->classCodeHi, pBank->classCodeLo); 2287 ss << std::format(" Bridge: Secondary Status : 0x{:04X}\n", 2288 pBank->secondSts); 2289 ss << std::format(" Bridge: Control : 0x{:04X}\n", 2290 pBank->ctrl); 2291 ss << std::format(" Uncorrectable Error Status : 0x{:08X}\n", 2292 pBank->uncorrErrSts); 2293 ss << std::format(" Uncorrectable Error Mask : 0x{:08X}\n", 2294 pBank->uncorrErrMsk); 2295 ss << std::format(" Uncorrectable Error Severity : 0x{:08X}\n", 2296 pBank->uncorrErrSeverity); 2297 ss << std::format(" Correctable Error Status : 0x{:08X}\n", 2298 pBank->corrErrSts); 2299 ss << std::format(" Correctable Error Mask : 0x{:08X}\n", 2300 pBank->corrErrMsk); 2301 ss << std::format(" Header Log DW0 : 0x{:08X}\n", 2302 pBank->hdrLogDw0); 2303 ss << std::format(" Header Log DW1 : 0x{:08X}\n", 2304 pBank->hdrLogDw1); 2305 ss << std::format(" Header Log DW2 : 0x{:08X}\n", 2306 pBank->hdrLogDw2); 2307 ss << std::format(" Header Log DW3 : 0x{:08X}\n", 2308 pBank->hdrLogDw3); 2309 ss << std::format(" Root Error Status : 0x{:08X}\n", 2310 pBank->rootErrSts); 2311 ss << std::format(" Correctable Error Source ID : 0x{:04X}\n", 2312 pBank->corrErrSrcId); 2313 ss << std::format(" Error Source ID : 0x{:04X}\n", 2314 pBank->errSrcId); 2315 ss << std::format(" Lane Error Status : 0x{:08X}\n", 2316 pBank->laneErrSts); 2317 ss << "\n"; 2318 2319 return IPMI_CC_OK; 2320 } 2321 2322 static ipmi_ret_t handleWdtRegBank(std::span<const uint8_t> data, 2323 CrdState& currState, std::stringstream& ss) 2324 { 2325 if (data.size() < sizeof(CrdWdtRegBank)) 2326 return IPMI_CC_REQ_DATA_LEN_INVALID; 2327 2328 const auto* pBank = reinterpret_cast<const CrdWdtRegBank*>(data.data()); 2329 if (data.size() < sizeof(CrdWdtRegBank) + sizeof(uint32_t) * pBank->count) 2330 return IPMI_CC_REQ_DATA_LEN_INVALID; 2331 2332 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2333 if (res) 2334 return res; 2335 2336 ss << std::format(" [NBIO{}] {}\n", pBank->nbio, pBank->name); 2337 ss << std::format(" Address: 0x{:08X}\n", pBank->addr); 2338 ss << std::format(" Data Count: {}\n", pBank->count); 2339 ss << " Data:\n"; 2340 for (size_t i = 0; i < pBank->count; i++) 2341 { 2342 ss << std::format(" {}: 0x{:08X}\n", i, pBank->data[i]); 2343 } 2344 ss << "\n"; 2345 2346 return IPMI_CC_OK; 2347 } 2348 2349 static ipmi_ret_t handleCrdHdrBank(std::span<const uint8_t> data, 2350 CrdState& currState, std::stringstream& ss) 2351 { 2352 if (data.size() < sizeof(CrdHdrBank)) 2353 return IPMI_CC_REQ_DATA_LEN_INVALID; 2354 2355 ipmi_ret_t res = setDumpState(currState, CrdState::waitData); 2356 if (res) 2357 return res; 2358 2359 const auto* pBank = reinterpret_cast<const CrdHdrBank*>(data.data()); 2360 ss << " Crashdump Header\n"; 2361 ss << std::format(" CPU PPIN : 0x{:016X}\n", pBank->ppin); 2362 ss << std::format(" UCODE VERSION : 0x{:08X}\n", pBank->ucodeVer); 2363 ss << std::format(" PMIO 80h : 0x{:08X}\n", pBank->pmio); 2364 ss << std::format( 2365 " BIT0 - SMN Parity/SMN Timeouts PSP/SMU Parity and ECC/SMN On-Package Link Error : {}\n", 2366 pBank->pmio & 0x1); 2367 ss << std::format(" BIT2 - PSP Parity and ECC : {}\n", 2368 (pBank->pmio & 0x4) >> 2); 2369 ss << std::format(" BIT3 - SMN Timeouts SMU : {}\n", 2370 (pBank->pmio & 0x8) >> 3); 2371 ss << std::format(" BIT4 - SMN Off-Package Link Packet Error : {}\n", 2372 (pBank->pmio & 0x10) >> 4); 2373 ss << "\n"; 2374 2375 return IPMI_CC_OK; 2376 } 2377 2378 static std::string getFilename(const std::filesystem::path& dir, 2379 const std::string& prefix) 2380 { 2381 std::vector<int> indices; 2382 std::regex pattern(prefix + "(\\d+)\\.txt"); 2383 2384 for (const auto& entry : std::filesystem::directory_iterator(dir)) 2385 { 2386 std::string filename = entry.path().filename().string(); 2387 std::smatch match; 2388 if (std::regex_match(filename, match, pattern)) 2389 indices.push_back(std::stoi(match[1])); 2390 } 2391 2392 std::sort(indices.rbegin(), indices.rend()); 2393 while (indices.size() > 2) // keep 3 files, so remove if more than 2 2394 { 2395 std::filesystem::remove( 2396 dir / (prefix + std::to_string(indices.back()) + ".txt")); 2397 indices.pop_back(); 2398 } 2399 2400 int nextIndex = indices.empty() ? 1 : indices.front() + 1; 2401 return prefix + std::to_string(nextIndex) + ".txt"; 2402 } 2403 2404 static ipmi_ret_t handleCtrlBank(std::span<const uint8_t> data, 2405 CrdState& currState, std::stringstream& ss) 2406 { 2407 if (data.empty()) 2408 return IPMI_CC_REQ_DATA_LEN_INVALID; 2409 2410 switch (static_cast<CrdCtrl>(data[0])) 2411 { 2412 case CrdCtrl::getState: 2413 break; 2414 case CrdCtrl::finish: 2415 { 2416 ipmi_ret_t res = setDumpState(currState, CrdState::packing); 2417 if (res) 2418 return res; 2419 2420 const std::filesystem::path dumpDir = "/var/lib/fb-ipmi-oem"; 2421 std::string filename = getFilename(dumpDir, "crashdump_"); 2422 std::ofstream outFile(dumpDir / filename); 2423 if (!outFile.is_open()) 2424 return IPMI_CC_UNSPECIFIED_ERROR; 2425 2426 auto now = std::chrono::system_clock::to_time_t( 2427 std::chrono::system_clock::now()); 2428 outFile << "Crash Dump generated at: " 2429 << std::put_time(std::localtime(&now), "%Y-%m-%d %H:%M:%S") 2430 << "\n\n"; 2431 outFile << ss.str(); 2432 outFile.close(); 2433 ss.str(""); 2434 ss.clear(); 2435 setDumpState(currState, CrdState::free); 2436 break; 2437 } 2438 default: 2439 return ccInvalidParam; 2440 } 2441 2442 return IPMI_CC_OK; 2443 } 2444 2445 ipmi::RspType<std::vector<uint8_t>> 2446 ipmiOemCrashdump([[maybe_unused]] ipmi::Context::ptr ctx, 2447 std::vector<uint8_t> reqData) 2448 { 2449 static CrdState dumpState = CrdState::free; 2450 static std::stringstream ss; 2451 2452 if (reqData.size() < sizeof(CrashDumpHdr)) 2453 return ipmi::responseReqDataLenInvalid(); 2454 2455 const auto* pHdr = reinterpret_cast<const CrashDumpHdr*>(reqData.data()); 2456 std::span<const uint8_t> bData{reqData.data() + sizeof(CrashDumpHdr), 2457 reqData.size() - sizeof(CrashDumpHdr)}; 2458 ipmi_ret_t res; 2459 2460 switch (pHdr->bankHdr.bankType) 2461 { 2462 case BankType::mca: 2463 res = handleMcaBank(*pHdr, bData, dumpState, ss); 2464 break; 2465 case BankType::virt: 2466 if (pHdr->bankHdr.version >= 3) 2467 { 2468 res = handleVirtualBank<CrdVirtualBankV3>(bData, dumpState, ss); 2469 break; 2470 } 2471 res = handleVirtualBank<CrdVirtualBankV2>(bData, dumpState, ss); 2472 break; 2473 case BankType::cpuWdt: 2474 res = handleCpuWdtBank(bData, dumpState, ss); 2475 break; 2476 case BankType::tcdx: 2477 res = handleHwAssertBank<tcdxNum>("TCDX", bData, dumpState, ss); 2478 break; 2479 case BankType::cake: 2480 res = handleHwAssertBank<cakeNum>("CAKE", bData, dumpState, ss); 2481 break; 2482 case BankType::pie0: 2483 res = handleHwAssertBank<pie0Num>("PIE", bData, dumpState, ss); 2484 break; 2485 case BankType::iom: 2486 res = handleHwAssertBank<iomNum>("IOM", bData, dumpState, ss); 2487 break; 2488 case BankType::ccix: 2489 res = handleHwAssertBank<ccixNum>("CCIX", bData, dumpState, ss); 2490 break; 2491 case BankType::cs: 2492 res = handleHwAssertBank<csNum>("CS", bData, dumpState, ss); 2493 break; 2494 case BankType::pcieAer: 2495 res = handlePcieAerBank(bData, dumpState, ss); 2496 break; 2497 case BankType::wdtReg: 2498 res = handleWdtRegBank(bData, dumpState, ss); 2499 break; 2500 case BankType::ctrl: 2501 res = handleCtrlBank(bData, dumpState, ss); 2502 if (res == IPMI_CC_OK && 2503 static_cast<CrdCtrl>(bData[0]) == CrdCtrl::getState) 2504 { 2505 return ipmi::responseSuccess( 2506 std::vector<uint8_t>{static_cast<uint8_t>(dumpState)}); 2507 } 2508 break; 2509 case BankType::crdHdr: 2510 res = handleCrdHdrBank(bData, dumpState, ss); 2511 break; 2512 default: 2513 return ipmi::responseInvalidFieldRequest(); 2514 } 2515 2516 return ipmi::response(res); 2517 } 2518 2519 static void registerOEMFunctions(void) 2520 { 2521 /* Get OEM data from json file */ 2522 std::ifstream file(JSON_OEM_DATA_FILE); 2523 if (file) 2524 { 2525 file >> oemData; 2526 file.close(); 2527 } 2528 2529 phosphor::logging::log<phosphor::logging::level::INFO>( 2530 "Registering OEM commands"); 2531 2532 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_INFO, 2533 NULL, ipmiOemDbgGetFrameInfo, 2534 PRIVILEGE_USER); // get debug frame info 2535 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, 2536 CMD_OEM_USB_DBG_GET_UPDATED_FRAMES, NULL, 2537 ipmiOemDbgGetUpdFrames, 2538 PRIVILEGE_USER); // get debug updated frames 2539 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_POST_DESC, 2540 NULL, ipmiOemDbgGetPostDesc, 2541 PRIVILEGE_USER); // get debug post description 2542 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_GPIO_DESC, 2543 NULL, ipmiOemDbgGetGpioDesc, 2544 PRIVILEGE_USER); // get debug gpio description 2545 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_DATA, 2546 NULL, ipmiOemDbgGetFrameData, 2547 PRIVILEGE_USER); // get debug frame data 2548 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_CTRL_PANEL, 2549 NULL, ipmiOemDbgGetCtrlPanel, 2550 PRIVILEGE_USER); // get debug control panel 2551 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_DIMM_INFO, NULL, 2552 ipmiOemSetDimmInfo, 2553 PRIVILEGE_USER); // Set Dimm Info 2554 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_GET_BOARD_ID, NULL, 2555 ipmiOemGetBoardID, 2556 PRIVILEGE_USER); // Get Board ID 2557 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnOemOne, 2558 CMD_OEM_GET_80PORT_RECORD, ipmi::Privilege::User, 2559 ipmiOemGet80PortRecord); // Get 80 Port Record 2560 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_MACHINE_CONFIG_INFO, NULL, 2561 ipmiOemSetMachineCfgInfo, 2562 PRIVILEGE_USER); // Set Machine Config Info 2563 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_POST_START, NULL, 2564 ipmiOemSetPostStart, 2565 PRIVILEGE_USER); // Set POST start 2566 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_POST_END, NULL, 2567 ipmiOemSetPostEnd, 2568 PRIVILEGE_USER); // Set POST End 2569 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_PPIN_INFO, NULL, 2570 ipmiOemSetPPINInfo, 2571 PRIVILEGE_USER); // Set PPIN Info 2572 #if BIC_ENABLED 2573 2574 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 2575 ipmi::cmdSetSystemGuid, ipmi::Privilege::User, 2576 ipmiOemSetSystemGuid); 2577 #else 2578 2579 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_SYSTEM_GUID, NULL, 2580 ipmiOemSetSystemGuid, 2581 PRIVILEGE_USER); // Set System GUID 2582 #endif 2583 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_ADR_TRIGGER, NULL, 2584 ipmiOemSetAdrTrigger, 2585 PRIVILEGE_USER); // Set ADR Trigger 2586 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_BIOS_FLASH_INFO, NULL, 2587 ipmiOemSetBiosFlashInfo, 2588 PRIVILEGE_USER); // Set Bios Flash Info 2589 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_PPR, NULL, ipmiOemSetPpr, 2590 PRIVILEGE_USER); // Set PPR 2591 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_GET_PPR, NULL, ipmiOemGetPpr, 2592 PRIVILEGE_USER); // Get PPR 2593 /* FB OEM QC Commands */ 2594 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour, 2595 CMD_OEM_Q_SET_PROC_INFO, ipmi::Privilege::User, 2596 ipmiOemQSetProcInfo); // Set Proc Info 2597 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour, 2598 CMD_OEM_Q_GET_PROC_INFO, ipmi::Privilege::User, 2599 ipmiOemQGetProcInfo); // Get Proc Info 2600 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour, 2601 ipmi::cmdSetQDimmInfo, ipmi::Privilege::User, 2602 ipmiOemQSetDimmInfo); // Set Dimm Info 2603 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour, 2604 ipmi::cmdGetQDimmInfo, ipmi::Privilege::User, 2605 ipmiOemQGetDimmInfo); // Get Dimm Info 2606 ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_DRIVE_INFO, NULL, 2607 ipmiOemQSetDriveInfo, 2608 PRIVILEGE_USER); // Set Drive Info 2609 ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_DRIVE_INFO, NULL, 2610 ipmiOemQGetDriveInfo, 2611 PRIVILEGE_USER); // Get Drive Info 2612 2613 /* FB OEM DCMI Commands as per DCMI spec 1.5 Section 6 */ 2614 ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI, 2615 ipmi::dcmi::cmdGetPowerReading, 2616 ipmi::Privilege::User, 2617 ipmiOemDCMIGetPowerReading); // Get Power Reading 2618 2619 ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI, 2620 ipmi::dcmi::cmdGetPowerLimit, 2621 ipmi::Privilege::User, 2622 ipmiOemDCMIGetPowerLimit); // Get Power Limit 2623 2624 ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI, 2625 ipmi::dcmi::cmdSetPowerLimit, 2626 ipmi::Privilege::Operator, 2627 ipmiOemDCMISetPowerLimit); // Set Power Limit 2628 2629 ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI, 2630 ipmi::dcmi::cmdActDeactivatePwrLimit, 2631 ipmi::Privilege::Operator, 2632 ipmiOemDCMIApplyPowerLimit); // Apply Power Limit 2633 2634 /* FB OEM BOOT ORDER COMMANDS */ 2635 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 2636 CMD_OEM_GET_BOOT_ORDER, ipmi::Privilege::User, 2637 ipmiOemGetBootOrder); // Get Boot Order 2638 2639 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 2640 CMD_OEM_SET_BOOT_ORDER, ipmi::Privilege::User, 2641 ipmiOemSetBootOrder); // Set Boot Order 2642 2643 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 2644 CMD_OEM_CRASHDUMP, ipmi::Privilege::User, 2645 ipmiOemCrashdump); 2646 2647 return; 2648 } 2649 2650 } // namespace ipmi 2651