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