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