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