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 1259 errno = 0; 1260 1261 // Check if file is present 1262 if (access(FRU_EEPROM, F_OK) == -1) 1263 { 1264 std::cerr << "Unable to access: " << FRU_EEPROM << std::endl; 1265 return errno; 1266 } 1267 1268 // Open the file 1269 fd = open(FRU_EEPROM, O_WRONLY); 1270 if (fd == -1) 1271 { 1272 std::cerr << "Unable to open: " << FRU_EEPROM << std::endl; 1273 return errno; 1274 } 1275 1276 // seek to the offset 1277 lseek(fd, offset, SEEK_SET); 1278 1279 // Write bytes to location 1280 len = write(fd, guid, GUID_SIZE); 1281 if (len != GUID_SIZE) 1282 { 1283 phosphor::logging::log<phosphor::logging::level::ERR>( 1284 "GUID write data to EEPROM failed"); 1285 ret = errno; 1286 } 1287 1288 close(fd); 1289 return ret; 1290 } 1291 1292 //---------------------------------------------------------------------- 1293 // Set System GUID (CMD_OEM_SET_SYSTEM_GUID) 1294 //---------------------------------------------------------------------- 1295 #if BIC_ENABLED 1296 ipmi::RspType<> ipmiOemSetSystemGuid(ipmi::Context::ptr ctx, 1297 std::vector<uint8_t> reqData) 1298 { 1299 std::vector<uint8_t> respData; 1300 1301 if (reqData.size() != GUID_SIZE) // 16bytes 1302 { 1303 return ipmi::responseReqDataLenInvalid(); 1304 } 1305 1306 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2; 1307 1308 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, reqData, respData)) 1309 return ipmi::responseUnspecifiedError(); 1310 1311 return ipmi::responseSuccess(); 1312 } 1313 1314 #else 1315 ipmi_ret_t ipmiOemSetSystemGuid(ipmi_netfn_t, ipmi_cmd_t, 1316 ipmi_request_t request, ipmi_response_t, 1317 ipmi_data_len_t data_len, ipmi_context_t) 1318 { 1319 uint8_t* req = reinterpret_cast<uint8_t*>(request); 1320 1321 if (*data_len != GUID_SIZE) // 16bytes 1322 { 1323 *data_len = 0; 1324 return IPMI_CC_REQ_DATA_LEN_INVALID; 1325 } 1326 1327 *data_len = 0; 1328 1329 if (setGUID(OFFSET_SYS_GUID, req)) 1330 { 1331 return IPMI_CC_UNSPECIFIED_ERROR; 1332 } 1333 return IPMI_CC_OK; 1334 } 1335 #endif 1336 1337 //---------------------------------------------------------------------- 1338 // Set Bios Flash Info (CMD_OEM_SET_BIOS_FLASH_INFO) 1339 //---------------------------------------------------------------------- 1340 ipmi_ret_t ipmiOemSetBiosFlashInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t, 1341 ipmi_response_t, ipmi_data_len_t data_len, 1342 ipmi_context_t) 1343 { 1344 /* Do nothing, return success */ 1345 *data_len = 0; 1346 return IPMI_CC_OK; 1347 } 1348 1349 //---------------------------------------------------------------------- 1350 // Set PPR (CMD_OEM_SET_PPR) 1351 //---------------------------------------------------------------------- 1352 ipmi_ret_t ipmiOemSetPpr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, 1353 ipmi_response_t, ipmi_data_len_t data_len, 1354 ipmi_context_t) 1355 { 1356 uint8_t* req = reinterpret_cast<uint8_t*>(request); 1357 uint8_t pprCnt, pprAct, pprIndex; 1358 uint8_t selParam = req[0]; 1359 uint8_t len = *data_len; 1360 std::stringstream ss; 1361 std::string str; 1362 1363 *data_len = 0; 1364 1365 switch (selParam) 1366 { 1367 case PPR_ACTION: 1368 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) == 1369 oemData[KEY_PPR].end()) 1370 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 1371 1372 pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT]; 1373 if (pprCnt == 0) 1374 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 1375 1376 pprAct = req[1]; 1377 /* Check if ppr is enabled or disabled */ 1378 if (!(pprAct & 0x80)) 1379 pprAct = 0; 1380 1381 oemData[KEY_PPR][KEY_PPR_ACTION] = pprAct; 1382 break; 1383 case PPR_ROW_COUNT: 1384 if (req[1] > 100) 1385 return IPMI_CC_PARM_OUT_OF_RANGE; 1386 1387 oemData[KEY_PPR][KEY_PPR_ROW_COUNT] = req[1]; 1388 break; 1389 case PPR_ROW_ADDR: 1390 pprIndex = req[1]; 1391 if (pprIndex > 100) 1392 return IPMI_CC_PARM_OUT_OF_RANGE; 1393 1394 if (len < PPR_ROW_ADDR_LEN + 1) 1395 { 1396 phosphor::logging::log<phosphor::logging::level::ERR>( 1397 "Invalid PPR Row Address length received"); 1398 return IPMI_CC_REQ_DATA_LEN_INVALID; 1399 } 1400 1401 ss << std::hex; 1402 ss << std::setw(2) << std::setfill('0') << (int)pprIndex; 1403 1404 oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex; 1405 1406 str = bytesToStr(&req[1], PPR_ROW_ADDR_LEN); 1407 oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR] = str.c_str(); 1408 break; 1409 case PPR_HISTORY_DATA: 1410 pprIndex = req[1]; 1411 if (pprIndex > 100) 1412 return IPMI_CC_PARM_OUT_OF_RANGE; 1413 1414 if (len < PPR_HST_DATA_LEN + 1) 1415 { 1416 phosphor::logging::log<phosphor::logging::level::ERR>( 1417 "Invalid PPR history data length received"); 1418 return IPMI_CC_REQ_DATA_LEN_INVALID; 1419 } 1420 1421 ss << std::hex; 1422 ss << std::setw(2) << std::setfill('0') << (int)pprIndex; 1423 1424 oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex; 1425 1426 str = bytesToStr(&req[1], PPR_HST_DATA_LEN); 1427 oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA] = str.c_str(); 1428 break; 1429 default: 1430 return IPMI_CC_PARM_OUT_OF_RANGE; 1431 break; 1432 } 1433 1434 flushOemData(); 1435 1436 return IPMI_CC_OK; 1437 } 1438 1439 //---------------------------------------------------------------------- 1440 // Get PPR (CMD_OEM_GET_PPR) 1441 //---------------------------------------------------------------------- 1442 ipmi_ret_t ipmiOemGetPpr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, 1443 ipmi_response_t response, ipmi_data_len_t data_len, 1444 ipmi_context_t) 1445 { 1446 uint8_t* req = reinterpret_cast<uint8_t*>(request); 1447 uint8_t* res = reinterpret_cast<uint8_t*>(response); 1448 uint8_t pprCnt, pprIndex; 1449 uint8_t selParam = req[0]; 1450 std::stringstream ss; 1451 std::string str; 1452 1453 /* Any failure will return zero length data */ 1454 *data_len = 0; 1455 1456 switch (selParam) 1457 { 1458 case PPR_ACTION: 1459 res[0] = 0; 1460 *data_len = 1; 1461 1462 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) != 1463 oemData[KEY_PPR].end()) 1464 { 1465 pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT]; 1466 if (pprCnt != 0) 1467 { 1468 if (oemData[KEY_PPR].find(KEY_PPR_ACTION) != 1469 oemData[KEY_PPR].end()) 1470 { 1471 res[0] = oemData[KEY_PPR][KEY_PPR_ACTION]; 1472 } 1473 } 1474 } 1475 break; 1476 case PPR_ROW_COUNT: 1477 res[0] = 0; 1478 *data_len = 1; 1479 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) != 1480 oemData[KEY_PPR].end()) 1481 res[0] = oemData[KEY_PPR][KEY_PPR_ROW_COUNT]; 1482 break; 1483 case PPR_ROW_ADDR: 1484 pprIndex = req[1]; 1485 if (pprIndex > 100) 1486 return IPMI_CC_PARM_OUT_OF_RANGE; 1487 1488 ss << std::hex; 1489 ss << std::setw(2) << std::setfill('0') << (int)pprIndex; 1490 1491 if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end()) 1492 return IPMI_CC_PARM_OUT_OF_RANGE; 1493 1494 if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_ROW_ADDR) == 1495 oemData[KEY_PPR][ss.str()].end()) 1496 return IPMI_CC_PARM_OUT_OF_RANGE; 1497 1498 str = oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR]; 1499 *data_len = strToBytes(str, res); 1500 break; 1501 case PPR_HISTORY_DATA: 1502 pprIndex = req[1]; 1503 if (pprIndex > 100) 1504 return IPMI_CC_PARM_OUT_OF_RANGE; 1505 1506 ss << std::hex; 1507 ss << std::setw(2) << std::setfill('0') << (int)pprIndex; 1508 1509 if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end()) 1510 return IPMI_CC_PARM_OUT_OF_RANGE; 1511 1512 if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_HST_DATA) == 1513 oemData[KEY_PPR][ss.str()].end()) 1514 return IPMI_CC_PARM_OUT_OF_RANGE; 1515 1516 str = oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA]; 1517 *data_len = strToBytes(str, res); 1518 break; 1519 default: 1520 return IPMI_CC_PARM_OUT_OF_RANGE; 1521 break; 1522 } 1523 1524 return IPMI_CC_OK; 1525 } 1526 1527 /* FB OEM QC Commands */ 1528 1529 //---------------------------------------------------------------------- 1530 // Set Proc Info (CMD_OEM_Q_SET_PROC_INFO) 1531 //---------------------------------------------------------------------- 1532 //"Request: 1533 // Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first 1534 // Byte 4 – Processor Index, 0 base 1535 // Byte 5 – Parameter Selector 1536 // Byte 6..N – Configuration parameter data (see below for Parameters 1537 // of Processor Information) 1538 // Response: 1539 // Byte 1 – Completion code 1540 // 1541 // Parameter#1: (Processor Product Name) 1542 // 1543 // Byte 1..48 –Product name(ASCII code) 1544 // Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz 1545 // 1546 // Param#2: Processor Basic Information 1547 // Byte 1 – Core Number 1548 // Byte 2 – Thread Number (LSB) 1549 // Byte 3 – Thread Number (MSB) 1550 // Byte 4 – Processor frequency in MHz (LSB) 1551 // Byte 5 – Processor frequency in MHz (MSB) 1552 // Byte 6..7 – Revision 1553 // 1554 1555 ipmi::RspType<> ipmiOemQSetProcInfo(ipmi::Context::ptr ctx, uint8_t, uint8_t, 1556 uint8_t, uint8_t procIndex, 1557 uint8_t paramSel, 1558 std::vector<uint8_t> request) 1559 { 1560 uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*); 1561 std::stringstream ss; 1562 std::string str; 1563 uint8_t len = request.size(); 1564 auto hostId = findHost(ctx->hostIdx); 1565 if (!hostId) 1566 { 1567 phosphor::logging::log<phosphor::logging::level::ERR>( 1568 "Invalid Host Id received"); 1569 return ipmi::responseInvalidCommand(); 1570 } 1571 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(*hostId); 1572 /* check for requested data params */ 1573 if (len < 5 || paramSel < 1 || paramSel >= numParam) 1574 { 1575 phosphor::logging::log<phosphor::logging::level::ERR>( 1576 "Invalid parameter received"); 1577 return ipmi::responseParmOutOfRange(); 1578 } 1579 ss << std::hex; 1580 ss << std::setw(2) << std::setfill('0') << (int)procIndex; 1581 oemData[procInfo][ss.str()][KEY_PROC_INDEX] = procIndex; 1582 str = bytesToStr(request.data(), len); 1583 oemData[procInfo][ss.str()][cpuInfoKey[paramSel]] = str.c_str(); 1584 flushOemData(); 1585 return ipmi::responseSuccess(); 1586 } 1587 1588 //---------------------------------------------------------------------- 1589 // Get Proc Info (CMD_OEM_Q_GET_PROC_INFO) 1590 //---------------------------------------------------------------------- 1591 // Request: 1592 // Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first 1593 // Byte 4 – Processor Index, 0 base 1594 // Byte 5 – Parameter Selector 1595 // Response: 1596 // Byte 1 – Completion code 1597 // Byte 2..N – Configuration Parameter Data (see below for Parameters 1598 // of Processor Information) 1599 // 1600 // Parameter#1: (Processor Product Name) 1601 // 1602 // Byte 1..48 –Product name(ASCII code) 1603 // Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz 1604 // 1605 // Param#2: Processor Basic Information 1606 // Byte 1 – Core Number 1607 // Byte 2 – Thread Number (LSB) 1608 // Byte 3 – Thread Number (MSB) 1609 // Byte 4 – Processor frequency in MHz (LSB) 1610 // Byte 5 – Processor frequency in MHz (MSB) 1611 // Byte 6..7 – Revision 1612 // 1613 1614 ipmi::RspType<std::vector<uint8_t>> 1615 ipmiOemQGetProcInfo(ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, 1616 uint8_t procIndex, uint8_t paramSel) 1617 { 1618 uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*); 1619 std::stringstream ss; 1620 std::string str; 1621 uint8_t res[MAX_BUF]; 1622 auto hostId = findHost(ctx->hostIdx); 1623 if (!hostId) 1624 { 1625 phosphor::logging::log<phosphor::logging::level::ERR>( 1626 "Invalid Host Id received"); 1627 return ipmi::responseInvalidCommand(); 1628 } 1629 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(*hostId); 1630 if (paramSel < 1 || paramSel >= numParam) 1631 { 1632 phosphor::logging::log<phosphor::logging::level::ERR>( 1633 "Invalid parameter received"); 1634 return ipmi::responseParmOutOfRange(); 1635 } 1636 ss << std::hex; 1637 ss << std::setw(2) << std::setfill('0') << (int)procIndex; 1638 if (oemData[procInfo].find(ss.str()) == oemData[procInfo].end()) 1639 return ipmi::responseCommandNotAvailable(); 1640 if (oemData[procInfo][ss.str()].find(cpuInfoKey[paramSel]) == 1641 oemData[procInfo][ss.str()].end()) 1642 return ipmi::responseCommandNotAvailable(); 1643 str = oemData[procInfo][ss.str()][cpuInfoKey[paramSel]]; 1644 int dataLen = strToBytes(str, res); 1645 std::vector<uint8_t> response(&res[0], &res[dataLen]); 1646 return ipmi::responseSuccess(response); 1647 } 1648 1649 //---------------------------------------------------------------------- 1650 // Set Dimm Info (CMD_OEM_Q_SET_DIMM_INFO) 1651 //---------------------------------------------------------------------- 1652 // Request: 1653 // Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first 1654 // Byte 4 – DIMM Index, 0 base 1655 // Byte 5 – Parameter Selector 1656 // Byte 6..N – Configuration parameter data (see below for Parameters 1657 // of DIMM Information) 1658 // Response: 1659 // Byte 1 – Completion code 1660 // 1661 // Param#1 (DIMM Location): 1662 // Byte 1 – DIMM Present 1663 // Byte 1 – DIMM Present 1664 // 01h – Present 1665 // FFh – Not Present 1666 // Byte 2 – Node Number, 0 base 1667 // Byte 3 – Channel Number , 0 base 1668 // Byte 4 – DIMM Number , 0 base 1669 // 1670 // Param#2 (DIMM Type): 1671 // Byte 1 – DIMM Type 1672 // Bit [7:6] 1673 // For DDR3 1674 // 00 – Normal Voltage (1.5V) 1675 // 01 – Ultra Low Voltage (1.25V) 1676 // 10 – Low Voltage (1.35V) 1677 // 11 – Reserved 1678 // For DDR4 1679 // 00 – Reserved 1680 // 01 – Reserved 1681 // 10 – Reserved 1682 // 11 – Normal Voltage (1.2V) 1683 // Bit [5:0] 1684 // 0x00 – SDRAM 1685 // 0x01 – DDR-1 RAM 1686 // 0x02 – Rambus 1687 // 0x03 – DDR-2 RAM 1688 // 0x04 – FBDIMM 1689 // 0x05 – DDR-3 RAM 1690 // 0x06 – DDR-4 RAM 1691 // 1692 // Param#3 (DIMM Speed): 1693 // Byte 1..2 – DIMM speed in MHz, LSB 1694 // Byte 3..6 – DIMM size in Mbytes, LSB 1695 // 1696 // Param#4 (Module Part Number): 1697 // Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C) 1698 // 1699 // Param#5 (Module Serial Number): 1700 // Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C) 1701 // 1702 // Param#6 (Module Manufacturer ID): 1703 // Byte 1 - Module Manufacturer ID, LSB 1704 // Byte 2 - Module Manufacturer ID, MSB 1705 // 1706 ipmi::RspType<> ipmiOemQSetDimmInfo(ipmi::Context::ptr ctx, uint8_t, uint8_t, 1707 uint8_t, uint8_t dimmIndex, 1708 uint8_t paramSel, 1709 std::vector<uint8_t> request) 1710 { 1711 uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*); 1712 std::stringstream ss; 1713 std::string str; 1714 uint8_t len = request.size(); 1715 std::string dimmType; 1716 readDimmType(dimmType, dimmIndex); 1717 auto hostId = findHost(ctx->hostIdx); 1718 if (!hostId) 1719 { 1720 phosphor::logging::log<phosphor::logging::level::ERR>( 1721 "Invalid Host Id received"); 1722 return ipmi::responseInvalidCommand(); 1723 } 1724 1725 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(*hostId); 1726 1727 if (len < 3 || paramSel < 1 || paramSel >= numParam) 1728 { 1729 phosphor::logging::log<phosphor::logging::level::ERR>( 1730 "Invalid parameter received"); 1731 return ipmi::responseParmOutOfRange(); 1732 } 1733 1734 ss << std::hex; 1735 ss << (int)dimmIndex; 1736 oemData[dimmInfo][ss.str()][KEY_DIMM_INDEX] = dimmIndex; 1737 oemData[dimmInfo][ss.str()][KEY_DIMM_TYPE] = dimmType; 1738 str = bytesToStr(request.data(), len); 1739 oemData[dimmInfo][ss.str()][dimmInfoKey[paramSel]] = str.c_str(); 1740 flushOemData(); 1741 return ipmi::responseSuccess(); 1742 } 1743 1744 // Get Dimm Info (CMD_OEM_Q_GET_DIMM_INFO) 1745 //---------------------------------------------------------------------- 1746 // Request: 1747 // Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first 1748 // Byte 4 – DIMM Index, 0 base 1749 // Byte 5 – Parameter Selector 1750 // Byte 6..N – Configuration parameter data (see below for Parameters 1751 // of DIMM Information) 1752 // Response: 1753 // Byte 1 – Completion code 1754 // Byte 2..N – Configuration Parameter Data (see Table_1213h Parameters 1755 // of DIMM Information) 1756 // 1757 // Param#1 (DIMM Location): 1758 // Byte 1 – DIMM Present 1759 // Byte 1 – DIMM Present 1760 // 01h – Present 1761 // FFh – Not Present 1762 // Byte 2 – Node Number, 0 base 1763 // Byte 3 – Channel Number , 0 base 1764 // Byte 4 – DIMM Number , 0 base 1765 // 1766 // Param#2 (DIMM Type): 1767 // Byte 1 – DIMM Type 1768 // Bit [7:6] 1769 // For DDR3 1770 // 00 – Normal Voltage (1.5V) 1771 // 01 – Ultra Low Voltage (1.25V) 1772 // 10 – Low Voltage (1.35V) 1773 // 11 – Reserved 1774 // For DDR4 1775 // 00 – Reserved 1776 // 01 – Reserved 1777 // 10 – Reserved 1778 // 11 – Normal Voltage (1.2V) 1779 // Bit [5:0] 1780 // 0x00 – SDRAM 1781 // 0x01 – DDR-1 RAM 1782 // 0x02 – Rambus 1783 // 0x03 – DDR-2 RAM 1784 // 0x04 – FBDIMM 1785 // 0x05 – DDR-3 RAM 1786 // 0x06 – DDR-4 RAM 1787 // 1788 // Param#3 (DIMM Speed): 1789 // Byte 1..2 – DIMM speed in MHz, LSB 1790 // Byte 3..6 – DIMM size in Mbytes, LSB 1791 // 1792 // Param#4 (Module Part Number): 1793 // Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C) 1794 // 1795 // Param#5 (Module Serial Number): 1796 // Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C) 1797 // 1798 // Param#6 (Module Manufacturer ID): 1799 // Byte 1 - Module Manufacturer ID, LSB 1800 // Byte 2 - Module Manufacturer ID, MSB 1801 // 1802 ipmi::RspType<std::vector<uint8_t>> 1803 ipmiOemQGetDimmInfo(ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, 1804 uint8_t dimmIndex, uint8_t paramSel) 1805 { 1806 uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*); 1807 uint8_t res[MAX_BUF]; 1808 std::stringstream ss; 1809 std::string str; 1810 std::string dimmType; 1811 readDimmType(dimmType, dimmIndex); 1812 auto hostId = findHost(ctx->hostIdx); 1813 if (!hostId) 1814 { 1815 phosphor::logging::log<phosphor::logging::level::ERR>( 1816 "Invalid Host Id received"); 1817 return ipmi::responseInvalidCommand(); 1818 } 1819 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(*hostId); 1820 1821 if (paramSel < 1 || paramSel >= numParam) 1822 { 1823 phosphor::logging::log<phosphor::logging::level::ERR>( 1824 "Invalid parameter received"); 1825 return ipmi::responseParmOutOfRange(); 1826 } 1827 ss << std::hex; 1828 ss << (int)dimmIndex; 1829 oemData[dimmInfo][ss.str()][KEY_DIMM_TYPE] = dimmType; 1830 if (oemData[dimmInfo].find(ss.str()) == oemData[dimmInfo].end()) 1831 return ipmi::responseCommandNotAvailable(); 1832 if (oemData[dimmInfo][ss.str()].find(dimmInfoKey[paramSel]) == 1833 oemData[dimmInfo][ss.str()].end()) 1834 return ipmi::responseCommandNotAvailable(); 1835 str = oemData[dimmInfo][ss.str()][dimmInfoKey[paramSel]]; 1836 int data_length = strToBytes(str, res); 1837 std::vector<uint8_t> response(&res[0], &res[data_length]); 1838 return ipmi::responseSuccess(response); 1839 } 1840 1841 //---------------------------------------------------------------------- 1842 // Set Drive Info (CMD_OEM_Q_SET_DRIVE_INFO) 1843 //---------------------------------------------------------------------- 1844 // BIOS issue this command to provide HDD information to BMC. 1845 // 1846 // BIOS just can get information by standard ATA / SMART command for 1847 // OB SATA controller. 1848 // BIOS can get 1849 // 1. Serial Number 1850 // 2. Model Name 1851 // 3. HDD FW Version 1852 // 4. HDD Capacity 1853 // 5. HDD WWN 1854 // 1855 // Use Get HDD info Param #5 to know the MAX HDD info index. 1856 // 1857 // Request: 1858 // Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first 1859 // Byte 4 – 1860 // [7:4] Reserved 1861 // [3:0] HDD Controller Type 1862 // 0x00 – BIOS 1863 // 0x01 – Expander 1864 // 0x02 – LSI 1865 // Byte 5 – HDD Info Index, 0 base 1866 // Byte 6 – Parameter Selector 1867 // Byte 7..N – Configuration parameter data (see Table_1415h Parameters of HDD 1868 // Information) 1869 // 1870 // Response: 1871 // Byte 1 – Completion Code 1872 // 1873 // Param#0 (HDD Location): 1874 // Byte 1 – Controller 1875 // [7:3] Device Number 1876 // [2:0] Function Number 1877 // For Intel C610 series (Wellsburg) 1878 // D31:F2 (0xFA) – SATA control 1 1879 // D31:F5 (0xFD) – SATA control 2 1880 // D17:F4 (0x8C) – sSata control 1881 // Byte 2 – Port Number 1882 // Byte 3 – Location (0xFF: No HDD Present) 1883 // BIOS default set Byte 3 to 0xFF, if No HDD Present. And then skip send param 1884 // #1~4, #6, #7 to BMC (still send param #5) BIOS default set Byte 3 to 0, if 1885 // the HDD present. BMC or other people who know the HDD location has 1886 // responsibility for update Location info 1887 // 1888 // Param#1 (Serial Number): 1889 // Bytes 1..33: HDD Serial Number 1890 // 1891 // Param#2 (Model Name): 1892 // Byte 1..33 – HDD Model Name 1893 // 1894 // Param#3 (HDD FW Version): 1895 // Byte 1..17 –HDD FW version 1896 // 1897 // Param#4 (Capacity): 1898 // Byte 1..4 –HDD Block Size, LSB 1899 // Byte 5..12 - HDD Block Number, LSB 1900 // HDD Capacity = HDD Block size * HDD BLock number (Unit Byte) 1901 // 1902 // Param#5 (Max HDD Quantity): 1903 // Byte 1 - Max HDD Quantity 1904 // Max supported port numbers in this PCH 1905 // 1906 // Param#6 (HDD Type) 1907 // Byte 1 – HDD Type 1908 // 0h – Reserved 1909 // 1h – SAS 1910 // 2h – SATA 1911 // 3h – PCIE SSD (NVME) 1912 // 1913 // Param#7 (HDD WWN) 1914 // Data 1...8: HDD World Wide Name, LSB 1915 // 1916 ipmi_ret_t ipmiOemQSetDriveInfo(ipmi_netfn_t, ipmi_cmd_t, 1917 ipmi_request_t request, ipmi_response_t, 1918 ipmi_data_len_t data_len, ipmi_context_t) 1919 { 1920 qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request); 1921 uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*); 1922 uint8_t ctrlType = req->hddCtrlType & 0x0f; 1923 std::stringstream ss; 1924 std::string str; 1925 uint8_t len = *data_len; 1926 1927 *data_len = 0; 1928 1929 /* check for requested data params */ 1930 if (len < 6 || req->paramSel < 1 || req->paramSel >= numParam || 1931 ctrlType > 2) 1932 { 1933 phosphor::logging::log<phosphor::logging::level::ERR>( 1934 "Invalid parameter received"); 1935 return IPMI_CC_PARM_OUT_OF_RANGE; 1936 } 1937 1938 len = len - 6; // Get Actual data length 1939 1940 ss << std::hex; 1941 ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex; 1942 oemData[KEY_Q_DRIVE_INFO][KEY_HDD_CTRL_TYPE] = req->hddCtrlType; 1943 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()][KEY_HDD_INDEX] = 1944 req->hddIndex; 1945 1946 str = bytesToStr(req->data, len); 1947 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()] 1948 [driveInfoKey[req->paramSel]] = str.c_str(); 1949 flushOemData(); 1950 1951 return IPMI_CC_OK; 1952 } 1953 1954 //---------------------------------------------------------------------- 1955 // Get Drive Info (CMD_OEM_Q_GET_DRIVE_INFO) 1956 //---------------------------------------------------------------------- 1957 // BMC needs to check HDD presented or not first. If NOT presented, return 1958 // completion code 0xD5. 1959 // 1960 // Request: 1961 // Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first 1962 // Byte 4 – 1963 //[7:4] Reserved 1964 //[3:0] HDD Controller Type 1965 // 0x00 – BIOS 1966 // 0x01 – Expander 1967 // 0x02 – LSI 1968 // Byte 5 – HDD Index, 0 base 1969 // Byte 6 – Parameter Selector (See Above Set HDD Information) 1970 // Response: 1971 // Byte 1 – Completion Code 1972 // 0xD5 – Not support in current status (HDD Not Present) 1973 // Byte 2..N – Configuration parameter data (see Table_1415h Parameters of HDD 1974 // Information) 1975 // 1976 ipmi_ret_t ipmiOemQGetDriveInfo(ipmi_netfn_t, ipmi_cmd_t, 1977 ipmi_request_t request, 1978 ipmi_response_t response, 1979 ipmi_data_len_t data_len, ipmi_context_t) 1980 { 1981 qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request); 1982 uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*); 1983 uint8_t* res = reinterpret_cast<uint8_t*>(response); 1984 uint8_t ctrlType = req->hddCtrlType & 0x0f; 1985 std::stringstream ss; 1986 std::string str; 1987 1988 *data_len = 0; 1989 1990 /* check for requested data params */ 1991 if (req->paramSel < 1 || req->paramSel >= numParam || ctrlType > 2) 1992 { 1993 phosphor::logging::log<phosphor::logging::level::ERR>( 1994 "Invalid parameter received"); 1995 return IPMI_CC_PARM_OUT_OF_RANGE; 1996 } 1997 1998 if (oemData[KEY_Q_DRIVE_INFO].find(ctrlTypeKey[ctrlType]) == 1999 oemData[KEY_Q_DRIVE_INFO].end()) 2000 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 2001 2002 ss << std::hex; 2003 ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex; 2004 2005 if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]].find(ss.str()) == 2006 oemData[KEY_Q_DRIVE_INFO].end()) 2007 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 2008 2009 if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()].find( 2010 dimmInfoKey[req->paramSel]) == 2011 oemData[KEY_Q_DRIVE_INFO][ss.str()].end()) 2012 return CC_PARAM_NOT_SUPP_IN_CURR_STATE; 2013 2014 str = oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()] 2015 [dimmInfoKey[req->paramSel]]; 2016 *data_len = strToBytes(str, res); 2017 2018 return IPMI_CC_OK; 2019 } 2020 2021 /* Helper function for sending DCMI commands to ME/BIC and 2022 * getting response back 2023 */ 2024 ipmi::RspType<std::vector<uint8_t>> 2025 sendDCMICmd([[maybe_unused]] ipmi::Context::ptr ctx, 2026 [[maybe_unused]] uint8_t cmd, std::vector<uint8_t>& cmdData) 2027 { 2028 std::vector<uint8_t> respData; 2029 2030 #if BIC_ENABLED 2031 2032 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2; 2033 2034 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, cmdData, respData)) 2035 { 2036 return ipmi::responseUnspecifiedError(); 2037 } 2038 2039 #else 2040 2041 /* Add group id as first byte to request for ME command */ 2042 cmdData.insert(cmdData.begin(), groupDCMI); 2043 2044 if (sendMeCmd(ipmi::netFnGroup, cmd, cmdData, respData)) 2045 { 2046 return ipmi::responseUnspecifiedError(); 2047 } 2048 2049 /* Remove group id as first byte as it will be added by IPMID */ 2050 respData.erase(respData.begin()); 2051 2052 #endif 2053 2054 return ipmi::responseSuccess(std::move(respData)); 2055 } 2056 2057 /* DCMI Command handellers. */ 2058 2059 ipmi::RspType<std::vector<uint8_t>> 2060 ipmiOemDCMIGetPowerReading(ipmi::Context::ptr ctx, 2061 std::vector<uint8_t> reqData) 2062 { 2063 return sendDCMICmd(ctx, ipmi::dcmi::cmdGetPowerReading, reqData); 2064 } 2065 2066 ipmi::RspType<std::vector<uint8_t>> 2067 ipmiOemDCMIGetPowerLimit(ipmi::Context::ptr ctx, 2068 std::vector<uint8_t> reqData) 2069 { 2070 return sendDCMICmd(ctx, ipmi::dcmi::cmdGetPowerLimit, reqData); 2071 } 2072 2073 ipmi::RspType<std::vector<uint8_t>> 2074 ipmiOemDCMISetPowerLimit(ipmi::Context::ptr ctx, 2075 std::vector<uint8_t> reqData) 2076 { 2077 return sendDCMICmd(ctx, ipmi::dcmi::cmdSetPowerLimit, reqData); 2078 } 2079 2080 ipmi::RspType<std::vector<uint8_t>> 2081 ipmiOemDCMIApplyPowerLimit(ipmi::Context::ptr ctx, 2082 std::vector<uint8_t> reqData) 2083 { 2084 return sendDCMICmd(ctx, ipmi::dcmi::cmdActDeactivatePwrLimit, reqData); 2085 } 2086 2087 static void registerOEMFunctions(void) 2088 { 2089 /* Get OEM data from json file */ 2090 std::ifstream file(JSON_OEM_DATA_FILE); 2091 if (file) 2092 { 2093 file >> oemData; 2094 file.close(); 2095 } 2096 2097 phosphor::logging::log<phosphor::logging::level::INFO>( 2098 "Registering OEM commands"); 2099 2100 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_INFO, 2101 NULL, ipmiOemDbgGetFrameInfo, 2102 PRIVILEGE_USER); // get debug frame info 2103 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, 2104 CMD_OEM_USB_DBG_GET_UPDATED_FRAMES, NULL, 2105 ipmiOemDbgGetUpdFrames, 2106 PRIVILEGE_USER); // get debug updated frames 2107 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_POST_DESC, 2108 NULL, ipmiOemDbgGetPostDesc, 2109 PRIVILEGE_USER); // get debug post description 2110 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_GPIO_DESC, 2111 NULL, ipmiOemDbgGetGpioDesc, 2112 PRIVILEGE_USER); // get debug gpio description 2113 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_DATA, 2114 NULL, ipmiOemDbgGetFrameData, 2115 PRIVILEGE_USER); // get debug frame data 2116 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_CTRL_PANEL, 2117 NULL, ipmiOemDbgGetCtrlPanel, 2118 PRIVILEGE_USER); // get debug control panel 2119 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_DIMM_INFO, NULL, 2120 ipmiOemSetDimmInfo, 2121 PRIVILEGE_USER); // Set Dimm Info 2122 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_GET_BOARD_ID, NULL, 2123 ipmiOemGetBoardID, 2124 PRIVILEGE_USER); // Get Board ID 2125 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnOemOne, 2126 CMD_OEM_GET_80PORT_RECORD, ipmi::Privilege::User, 2127 ipmiOemGet80PortRecord); // Get 80 Port Record 2128 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_MACHINE_CONFIG_INFO, NULL, 2129 ipmiOemSetMachineCfgInfo, 2130 PRIVILEGE_USER); // Set Machine Config Info 2131 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_POST_START, NULL, 2132 ipmiOemSetPostStart, 2133 PRIVILEGE_USER); // Set POST start 2134 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_POST_END, NULL, 2135 ipmiOemSetPostEnd, 2136 PRIVILEGE_USER); // Set POST End 2137 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_PPIN_INFO, NULL, 2138 ipmiOemSetPPINInfo, 2139 PRIVILEGE_USER); // Set PPIN Info 2140 #if BIC_ENABLED 2141 2142 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 2143 ipmi::cmdSetSystemGuid, ipmi::Privilege::User, 2144 ipmiOemSetSystemGuid); 2145 #else 2146 2147 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_SYSTEM_GUID, NULL, 2148 ipmiOemSetSystemGuid, 2149 PRIVILEGE_USER); // Set System GUID 2150 #endif 2151 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_ADR_TRIGGER, NULL, 2152 ipmiOemSetAdrTrigger, 2153 PRIVILEGE_USER); // Set ADR Trigger 2154 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_BIOS_FLASH_INFO, NULL, 2155 ipmiOemSetBiosFlashInfo, 2156 PRIVILEGE_USER); // Set Bios Flash Info 2157 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_PPR, NULL, ipmiOemSetPpr, 2158 PRIVILEGE_USER); // Set PPR 2159 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_GET_PPR, NULL, ipmiOemGetPpr, 2160 PRIVILEGE_USER); // Get PPR 2161 /* FB OEM QC Commands */ 2162 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour, 2163 CMD_OEM_Q_SET_PROC_INFO, ipmi::Privilege::User, 2164 ipmiOemQSetProcInfo); // Set Proc Info 2165 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour, 2166 CMD_OEM_Q_GET_PROC_INFO, ipmi::Privilege::User, 2167 ipmiOemQGetProcInfo); // Get Proc Info 2168 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour, 2169 ipmi::cmdSetQDimmInfo, ipmi::Privilege::User, 2170 ipmiOemQSetDimmInfo); // Set Dimm Info 2171 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour, 2172 ipmi::cmdGetQDimmInfo, ipmi::Privilege::User, 2173 ipmiOemQGetDimmInfo); // Get Dimm Info 2174 ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_DRIVE_INFO, NULL, 2175 ipmiOemQSetDriveInfo, 2176 PRIVILEGE_USER); // Set Drive Info 2177 ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_DRIVE_INFO, NULL, 2178 ipmiOemQGetDriveInfo, 2179 PRIVILEGE_USER); // Get Drive Info 2180 2181 /* FB OEM DCMI Commands as per DCMI spec 1.5 Section 6 */ 2182 ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI, 2183 ipmi::dcmi::cmdGetPowerReading, 2184 ipmi::Privilege::User, 2185 ipmiOemDCMIGetPowerReading); // Get Power Reading 2186 2187 ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI, 2188 ipmi::dcmi::cmdGetPowerLimit, 2189 ipmi::Privilege::User, 2190 ipmiOemDCMIGetPowerLimit); // Get Power Limit 2191 2192 ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI, 2193 ipmi::dcmi::cmdSetPowerLimit, 2194 ipmi::Privilege::Operator, 2195 ipmiOemDCMISetPowerLimit); // Set Power Limit 2196 2197 ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI, 2198 ipmi::dcmi::cmdActDeactivatePwrLimit, 2199 ipmi::Privilege::Operator, 2200 ipmiOemDCMIApplyPowerLimit); // Apply Power Limit 2201 2202 /* FB OEM BOOT ORDER COMMANDS */ 2203 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 2204 CMD_OEM_GET_BOOT_ORDER, ipmi::Privilege::User, 2205 ipmiOemGetBootOrder); // Get Boot Order 2206 2207 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 2208 CMD_OEM_SET_BOOT_ORDER, ipmi::Privilege::User, 2209 ipmiOemSetBootOrder); // Set Boot Order 2210 2211 return; 2212 } 2213 2214 } // namespace ipmi 2215