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