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