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