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