diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host')
21 files changed, 3122 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0002-Modify-dbus-interface-for-power-control.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0002-Modify-dbus-interface-for-power-control.patch new file mode 100644 index 000000000..236bd18f4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0002-Modify-dbus-interface-for-power-control.patch @@ -0,0 +1,31 @@ +From 39df500f277eca01d6a0538d4db8ec34894d9441 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Mon, 17 Sep 2018 12:59:12 +0800 +Subject: [PATCH] Modify dbus interface for power control + +Switch power control service namespace from "org" to "xyz", +to compatible with new intel-chassis services + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + chassishandler.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 6002e7a..0e83bba 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -786,8 +786,8 @@ ipmi_ret_t ipmi_get_chassis_status(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_data_len_t data_len, + ipmi_context_t context) + { +- const char* objname = "/org/openbmc/control/power0"; +- const char* intf = "org.openbmc.control.Power"; ++ const char* objname = "/xyz/openbmc_project/Chassis/Control/Power0"; ++ const char* intf = "xyz.openbmc_project.Chassis.Control.Power"; + + sd_bus* bus = NULL; + sd_bus_message* reply = NULL; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0003-Modify-dbus-interface-for-chassis-control.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0003-Modify-dbus-interface-for-chassis-control.patch new file mode 100644 index 000000000..9061481ac --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0003-Modify-dbus-interface-for-chassis-control.patch @@ -0,0 +1,33 @@ +From 48ac37551cd51415deafe8b1dcb23ebeef1e8ade Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Mon, 17 Sep 2018 13:04:42 +0800 +Subject: [PATCH] Modify-dbus-interface-for-chassis-control + +Switch chassis control service namespace from "org" to "xyz", +to compatible with new intel-chassis services + +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + apphandler.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/apphandler.cpp b/apphandler.cpp +index b089331..f2889c5 100644 +--- a/apphandler.cpp ++++ b/apphandler.cpp +@@ -393,9 +393,9 @@ ipmi_ret_t ipmi_app_get_device_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_data_len_t data_len, + ipmi_context_t context) + { +- const char* objname = "/org/openbmc/control/chassis0"; ++ const char* objname = "/xyz/openbmc_project/Chassis/Control/Chassis"; + const char* iface = "org.freedesktop.DBus.Properties"; +- const char* chassis_iface = "org.openbmc.control.Chassis"; ++ const char* chassis_iface = "xyz.openbmc_project.Chassis.Control.Chassis"; + sd_bus_message* reply = NULL; + sd_bus_error error = SD_BUS_ERROR_NULL; + int r = 0; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0009-IPv6-Network-changes.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0009-IPv6-Network-changes.patch new file mode 100644 index 000000000..b54b22213 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0009-IPv6-Network-changes.patch @@ -0,0 +1,899 @@ +From c20bc8eb6a08d177d951012eb91b37398b15d81d Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Tue, 27 Nov 2018 11:01:15 -0800 +Subject: [PATCH] IPv6 Network changes + +Allow IPv6 IPMI set/get commands + +Signed-off-by: David Cobbley <david.j.cobbley@linux.intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> + +Change-Id: If5528d3b7294c5f8c17db5919439235d0fad0446 +--- + include/ipmid/types.hpp | 9 + + include/ipmid/utils.hpp | 1 + + transporthandler.cpp | 654 +++++++++++++++++++++++++++++++++++++++- + transporthandler.hpp | 50 +++ + 4 files changed, 713 insertions(+), 1 deletion(-) + +diff --git a/include/ipmid/types.hpp b/include/ipmid/types.hpp +index 57c5873..c06fd8c 100644 +--- a/include/ipmid/types.hpp ++++ b/include/ipmid/types.hpp +@@ -224,6 +224,7 @@ constexpr auto ADDR_TYPE_FORMAT = "%hhx"; + + constexpr auto IPV4_ADDRESS_SIZE_BYTE = 4; + constexpr auto IPV6_ADDRESS_SIZE_BYTE = 16; ++constexpr auto IPV6_ADDRESS_STATUS_SIZE = 22; + + constexpr auto DEFAULT_MAC_ADDRESS = "00:00:00:00:00:00"; + constexpr auto DEFAULT_ADDRESS = "0.0.0.0"; +@@ -235,6 +236,7 @@ constexpr auto BITS_32 = 32; + constexpr auto MASK_32_BIT = 0xFFFFFFFF; + constexpr auto VLAN_ID_MASK = 0x00000FFF; + constexpr auto VLAN_ENABLE_MASK = 0x8000; ++constexpr auto IPV6_DUID_SIZE = 18; + + enum class IPOrigin : uint8_t + { +@@ -243,5 +245,12 @@ enum class IPOrigin : uint8_t + DHCP = 2, + }; + ++enum class AddressingEnables : uint8_t ++{ ++ IPv4Only = 0, ++ IPv6Only = 1, ++ IPv4AndIPv6 = 2, ++}; ++ + } // namespace network + } // namespace ipmi +diff --git a/include/ipmid/utils.hpp b/include/ipmid/utils.hpp +index 9ef1488..8b91b12 100644 +--- a/include/ipmid/utils.hpp ++++ b/include/ipmid/utils.hpp +@@ -256,6 +256,7 @@ namespace network + constexpr auto ROOT = "/xyz/openbmc_project/network"; + constexpr auto SERVICE = "xyz.openbmc_project.Network"; + constexpr auto IP_TYPE = "ipv4"; ++constexpr auto IPV6_TYPE = "ipv6"; + constexpr auto IPV4_PREFIX = "169.254"; + constexpr auto IPV6_PREFIX = "fe80"; + constexpr auto IP_INTERFACE = "xyz.openbmc_project.Network.IP"; +diff --git a/transporthandler.cpp b/transporthandler.cpp +index 8172cc4..12d224a 100644 +--- a/transporthandler.cpp ++++ b/transporthandler.cpp +@@ -30,6 +30,12 @@ std::unique_ptr<phosphor::Timer> networkTimer = nullptr; + + const int SIZE_MAC = 18; // xx:xx:xx:xx:xx:xx + constexpr auto ipv4Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv4"; ++constexpr auto ipv6Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv6"; ++ ++static const std::array<std::string, 3> ipAddressEnablesType = { ++ "xyz.openbmc_project.Network.EthernetInterface.IPAllowed.IPv4Only", ++ "xyz.openbmc_project.Network.EthernetInterface.IPAllowed.IPv6Only", ++ "xyz.openbmc_project.Network.EthernetInterface.IPAllowed.IPv4AndIPv6"}; + + std::map<int, std::unique_ptr<struct ChannelConfig_t>> channelConfig; + +@@ -389,7 +395,6 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_context_t context) + { + ipmi_ret_t rc = IPMI_CC_OK; +- *data_len = 0; + + using namespace std::chrono_literals; + +@@ -403,6 +408,9 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + auto reqptr = reinterpret_cast<const set_lan_t*>(request); + sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); + ++ size_t reqLen = *data_len; ++ *data_len = 0; ++ + // channel number is the lower nibble + int channel = reqptr->channel & CHANNEL_MASK; + auto ethdevice = ipmi::getChannelName(channel); +@@ -426,6 +434,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + case LanParam::IPSRC: + { ++ if (reqLen != LAN_PARAM_IPSRC_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + uint8_t ipsrc{}; + std::memcpy(&ipsrc, reqptr->data, ipmi::network::IPSRC_SIZE_BYTE); + channelConf->ipsrc = static_cast<ipmi::network::IPOrigin>(ipsrc); +@@ -434,6 +447,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + case LanParam::MAC: + { ++ if (reqLen != LAN_PARAM_MAC_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + char mac[SIZE_MAC]; + + std::snprintf(mac, SIZE_MAC, ipmi::network::MAC_ADDRESS_FORMAT, +@@ -454,6 +472,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + case LanParam::SUBNET: + { ++ if (reqLen != LAN_PARAM_SUBNET_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + std::snprintf(netmask, INET_ADDRSTRLEN, + ipmi::network::IP_ADDRESS_FORMAT, reqptr->data[0], + reqptr->data[1], reqptr->data[2], reqptr->data[3]); +@@ -463,6 +486,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + case LanParam::GATEWAY: + { ++ if (reqLen != LAN_PARAM_GATEWAY_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + std::snprintf(gateway, INET_ADDRSTRLEN, + ipmi::network::IP_ADDRESS_FORMAT, reqptr->data[0], + reqptr->data[1], reqptr->data[2], reqptr->data[3]); +@@ -472,6 +500,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + case LanParam::VLAN: + { ++ if (reqLen != LAN_PARAM_VLAN_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + uint16_t vlan{}; + std::memcpy(&vlan, reqptr->data, ipmi::network::VLAN_SIZE_BYTE); + // We are not storing the enable bit +@@ -484,6 +517,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + case LanParam::INPROGRESS: + { ++ if (reqLen != LAN_PARAM_INPROGRESS_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + if (reqptr->data[0] == SET_COMPLETE) + { + channelConf->lan_set_in_progress = SET_COMPLETE; +@@ -512,6 +550,122 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + } + break; + ++ case LanParam::IPV6_AND_IPV4_ENABLES: ++ { ++ if (reqLen != LAN_PARAM_IPV6_AND_IPV4_ENABLES_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ channelConf->ipv6AddressingEnables = reqptr->data[0]; ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ADDRESSES: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ADDRESSES_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ channelConf->ipv6AddressSource = ++ reqptr->data[1] & 0x81; // Looking at bit 0 and bit 7 ++ char tmpIPV6[INET6_ADDRSTRLEN]; ++ inet_ntop(AF_INET6, &reqptr->data[2], tmpIPV6, INET6_ADDRSTRLEN); ++ channelConf->ipv6Addr.assign(tmpIPV6); ++ channelConf->ipv6Prefix = reqptr->data[19]; ++ break; ++ } ++ ++ case LanParam::IPV6_ROUTER_ADDRESS_CONF_CTRL: ++ { ++ if (reqLen != LAN_PARAM_IPV6_ROUTER_ADDRESS_CONF_CTRL_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ channelConf->ipv6RouterAddressConfigControl = reqptr->data[0]; ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_1_IP_ADDR: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_1_IP_ADDR_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ char tmpIPV6[INET6_ADDRSTRLEN]; ++ inet_ntop(AF_INET6, reinterpret_cast<const void*>(reqptr->data), ++ tmpIPV6, INET6_ADDRSTRLEN); ++ channelConf->ipv6GatewayAddr.assign(tmpIPV6); ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_1_PREFIX_LEN: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_1_PREFIX_LEN_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ channelConf->ipv6GatewayPrefixLength = reqptr->data[0]; ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_1_PREFIX_VAL: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_1_PREFIX_VAL_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ char tmpIPV6[INET6_ADDRSTRLEN]; ++ inet_ntop(AF_INET6, reinterpret_cast<const void*>(reqptr->data), ++ tmpIPV6, INET6_ADDRSTRLEN); ++ channelConf->ipv6GatewayPrefixValue.assign(tmpIPV6); ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_2_IP_ADDR: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_2_IP_ADDR_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ char tmpIPV6[INET6_ADDRSTRLEN]; ++ inet_ntop(AF_INET6, reinterpret_cast<const void*>(reqptr->data), ++ tmpIPV6, INET6_ADDRSTRLEN); ++ channelConf->ipv6BackupGatewayAddr.assign(tmpIPV6); ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_2_PREFIX_LEN: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_2_PREFIX_LEN_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ channelConf->ipv6BackupGatewayPrefixLength = reqptr->data[0]; ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_2_PREFIX_VAL: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_2_PREFIX_VAL_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ char tmpIPV6[INET6_ADDRSTRLEN]; ++ inet_ntop(AF_INET6, reinterpret_cast<const void*>(reqptr->data), ++ tmpIPV6, INET6_ADDRSTRLEN); ++ channelConf->ipv6BackupGatewayPrefixValue.assign(tmpIPV6); ++ break; ++ } ++ + default: + { + rc = IPMI_CC_PARM_NOT_SUPPORTED; +@@ -538,6 +692,7 @@ ipmi_ret_t ipmi_transport_get_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_ret_t rc = IPMI_CC_OK; + *data_len = 0; + const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0 ++ sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; + + get_lan_t* reqptr = (get_lan_t*)request; + // channel number is the lower nibble +@@ -676,6 +831,476 @@ ipmi_ret_t ipmi_transport_get_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + static_cast<uint8_t>(cipherList.size()); + break; + } ++ case LanParam::IPV6_AND_IPV4_SUPPORTED: ++ { ++ uint8_t addressSupport = ++ 0x1; // Allow both IPv4 & IPv6 simultaneously ++ std::array<uint8_t, 2> buf = {current_revision, addressSupport}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_AND_IPV4_ENABLES: ++ { ++ // If DHCP, check if you have an ipv6 and ipv4 address. If static ++ // return not supported ++ ++ // 00h check if conf DHCP == ipv4 or off ++ // 01h check if conf DHCP == ipv6 ++ // 02h check if DHCP == true ++ ++ auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE; ++ std::string networkInterfacePath; ++ uint8_t ipVAddressEnables = 0; ++ ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ try ++ { ++ ipmi::ObjectTree ancestorMap; ++ // if the system has an ip object,then ++ // get the IP object. ++ auto ipObject = ++ ipmi::getDbusObject(bus, ipmi::network::IP_INTERFACE, ++ ipmi::network::ROOT, ethIP); ++ // Get the parent interface of the IP object. ++ try ++ { ++ ipmi::InterfaceList interfaces; ++ interfaces.emplace_back( ++ ipmi::network::ETHERNET_INTERFACE); ++ ++ ancestorMap = ipmi::getAllAncestors( ++ bus, ipObject.first, std::move(interfaces)); ++ } ++ catch (InternalFailure& e) ++ { ++ // if unable to get the parent interface ++ // then commit the error and return. ++ log<level::ERR>( ++ "Unable to get the parent interface", ++ entry("PATH=%s", ipObject.first.c_str()), ++ entry("INTERFACE=%s", ++ ipmi::network::ETHERNET_INTERFACE)); ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ // for an ip object there would be single parent ++ // interface. ++ networkInterfacePath = ancestorMap.begin()->first; ++ } ++ catch (InternalFailure& e) ++ { ++ // if there is no ip configured on the system,then ++ // get the network interface object. ++ auto networkInterfaceObject = ipmi::getDbusObject( ++ bus, ipmi::network::ETHERNET_INTERFACE, ++ ipmi::network::ROOT, ethdevice); ++ ++ networkInterfacePath = networkInterfaceObject.first; ++ } ++ ++ ipmi::Value ipEnablesProp = ipmi::getDbusProperty( ++ bus, ipmi::network::SERVICE, networkInterfacePath, ++ ipmi::network::ETHERNET_INTERFACE, "IPAddressEnables"); ++ std::string ipEnables = std::get<std::string>(ipEnablesProp); ++ ++ // check if on off ipv4 ipv6, etc. ++ bool found = false; ++ for (uint8_t ii = 0; ii < ipAddressEnablesType.size(); ii++) ++ { ++ if (ipEnables == ipAddressEnablesType[ii]) ++ { ++ ipVAddressEnables = ii; ++ found = true; ++ break; ++ } ++ } ++ if (!found) ++ { ++ return IPMI_CC_PARM_NOT_SUPPORTED; ++ } ++ } ++ else ++ { ++ ipVAddressEnables = channelConf->ipv6AddressingEnables; ++ } ++ ++ std::array<uint8_t, 2> buf = {current_revision, ipVAddressEnables}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATUS: ++ { ++ // Number of IPV6 addresses that are supported ++ constexpr std::array<uint8_t, 3> statusData = {1, 1, 3}; ++ ++ std::array<uint8_t, 4> buf = {current_revision, statusData[0], ++ statusData[1], statusData[2]}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ADDRESSES: ++ { ++ // Only return set selector 0 ++ uint8_t ipv6SetSelector = 0; ++ std::string ipaddress; ++ auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE; ++ uint8_t ipv6AddressSource = 0; ++ uint8_t prefixLength = 0; ++ uint8_t status = 0; ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ try ++ { ++ auto ipObjectInfo = ++ ipmi::getIPObject(bus, ipmi::network::IP_INTERFACE, ++ ipmi::network::ROOT, ethIP); ++ ++ auto properties = ipmi::getAllDbusProperties( ++ bus, ipObjectInfo.second, ipObjectInfo.first, ++ ipmi::network::IP_INTERFACE); ++ ++ if (std::get<std::string>(properties["Origin"]) == ++ "xyz.openbmc_project.Network.IP.AddressOrigin.Static") ++ { ++ ipaddress = ++ std::get<std::string>(properties["Address"]); ++ ipv6AddressSource = 0x81; // Looking at bit 0 and bit 7 ++ prefixLength = ++ std::get<uint8_t>(properties["PrefixLength"]); ++ status = 0; ++ } ++ } ++ // ignore the exception, as it is a valid condition that ++ // the system is not configured with any IP. ++ catch (InternalFailure& e) ++ { ++ // nothing to do. ++ } ++ } ++ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) ++ { ++ ipv6AddressSource = channelConf->ipv6AddressSource; ++ ipaddress = channelConf->ipv6Addr.c_str(); ++ prefixLength = channelConf->ipv6Prefix; ++ status = 1; ++ } ++ ++ std::array<uint8_t, ipmi::network::IPV6_ADDRESS_STATUS_SIZE> buf = { ++ current_revision, ipv6SetSelector, ipv6AddressSource}; ++ inet_pton(AF_INET6, ipaddress.c_str(), ++ reinterpret_cast<void*>(&buf[3])); ++ buf[20] = prefixLength; ++ buf[21] = status; ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_DHCPV6_STATIC_DUID_STORAGE_LENGTH: ++ { ++ // DHCP unique identified ++ // Only 1 read-only 16-byte Block needed ++ uint8_t duidLength = 1; ++ std::array<uint8_t, 2> buf = {current_revision, duidLength}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_DHCPV6_STATIC_DUIDS: ++ { ++ std::string macAddress; ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ auto macObjectInfo = ++ ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE, ++ ipmi::network::ROOT, ethdevice); ++ ++ auto variant = ipmi::getDbusProperty( ++ bus, macObjectInfo.second, macObjectInfo.first, ++ ipmi::network::MAC_INTERFACE, "MACAddress"); ++ ++ macAddress = std::get<std::string>(variant); ++ } ++ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) ++ { ++ macAddress = channelConf->macAddress; ++ } ++ ++ std::array<uint8_t, ++ ipmi::network::IPV6_DUID_SIZE + sizeof(current_revision)> ++ buf; ++ buf = {current_revision, ++ reqptr->parameter_set, ++ reqptr->parameter_block, ++ DUID_LEN, ++ 0, // Filler byte ++ DUID_LL_TYPE, ++ 0, // Filler byte ++ DUIC_ETH_HW_TYPE}; ++ sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT, ++ (&buf[8]), (&buf[9]), (&buf[10]), (&buf[11]), (&buf[12]), ++ (&buf[13])); ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_DYNAMIC_ADDRESSES: ++ { ++ std::string ipaddress; ++ uint8_t ipv6AddressSource = 0; ++ uint8_t prefixLength = 0; ++ uint8_t status = 0; ++ auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE; ++ ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ try ++ { ++ auto ipObjectInfo = ++ ipmi::getIPObject(bus, ipmi::network::IP_INTERFACE, ++ ipmi::network::ROOT, ethIP); ++ ++ auto properties = ipmi::getAllDbusProperties( ++ bus, ipObjectInfo.second, ipObjectInfo.first, ++ ipmi::network::IP_INTERFACE); ++ ++ if (std::get<std::string>(properties["Origin"]) == ++ "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP") ++ { ++ ipaddress = ++ std::get<std::string>(properties["Address"]); ++ ipv6AddressSource = 0x81; // Looking at bit 0 and bit 7 ++ prefixLength = ++ std::get<uint8_t>(properties["PrefixLength"]); ++ status = 0; ++ } ++ else ++ { ++ status = 1; ++ } ++ } ++ // ignore the exception, as it is a valid condition that ++ // the system is not configured with any IP. ++ catch (InternalFailure& e) ++ { ++ // nothing to do. ++ } ++ } ++ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) ++ { ++ ipaddress = channelConf->ipv6Addr; ++ ipv6AddressSource = channelConf->ipv6AddressSource; ++ prefixLength = channelConf->ipv6Prefix; ++ status = channelConf->ipv6AddressStatus; ++ } ++ ++ uint8_t ipv6SetSelector = 0; ++ std::array<uint8_t, 22> buf = {current_revision, ipv6SetSelector, ++ ipv6AddressSource}; ++ inet_pton(AF_INET6, ipaddress.c_str(), ++ reinterpret_cast<void*>(&buf[3])); ++ buf[20] = prefixLength; ++ buf[21] = status; ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_DHCPV6_DYNAMIC_DUID_STOR_LEN: ++ { ++ uint8_t duidLength = 0; ++ // Only 1 read-only 16-byte Block needed ++ duidLength = 1; ++ ++ std::array<uint8_t, 2> buf = {current_revision, duidLength}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_DHCPV6_DYNAMIC_DUIDS: ++ { ++ std::string macAddress; ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ auto macObjectInfo = ++ ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE, ++ ipmi::network::ROOT, ethdevice); ++ ++ auto variant = ipmi::getDbusProperty( ++ bus, macObjectInfo.second, macObjectInfo.first, ++ ipmi::network::MAC_INTERFACE, "MACAddress"); ++ ++ macAddress = std::get<std::string>(variant); ++ } ++ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) ++ { ++ macAddress = channelConf->macAddress; ++ } ++ ++ std::array<uint8_t, ++ ipmi::network::IPV6_DUID_SIZE + sizeof(current_revision)> ++ buf; ++ buf = {current_revision, ++ reqptr->parameter_set, ++ reqptr->parameter_block, ++ DUID_LEN, ++ 0, // Filler byte ++ DUID_LL_TYPE, ++ 0, // Filler byte ++ DUIC_ETH_HW_TYPE}; ++ ++ sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT, ++ (&buf[8]), (&buf[9]), (&buf[10]), (&buf[11]), (&buf[12]), ++ (&buf[13])); ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_ROUTER_ADDRESS_CONF_CTRL: ++ { ++ // Determine if automated router discovery occurs when static ++ // addresses are used for the bmc ++ ++ auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE; ++ std::string networkInterfacePath; ++ uint8_t dynamicRA; ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ ++ try ++ { ++ ipmi::ObjectTree ancestorMap; ++ // if the system is having ip object,then ++ // get the IP object. ++ auto ipObject = ++ ipmi::getDbusObject(bus, ipmi::network::IP_INTERFACE, ++ ipmi::network::ROOT, ethIP); ++ ++ // Get the parent interface of the IP object. ++ try ++ { ++ ipmi::InterfaceList interfaces; ++ interfaces.emplace_back( ++ ipmi::network::ETHERNET_INTERFACE); ++ ++ ancestorMap = ipmi::getAllAncestors( ++ bus, ipObject.first, std::move(interfaces)); ++ } ++ catch (InternalFailure& e) ++ { ++ // if unable to get the parent interface ++ // then commit the error and return. ++ log<level::ERR>( ++ "Unable to get the parent interface", ++ entry("PATH=%s", ipObject.first.c_str()), ++ entry("INTERFACE=%s", ++ ipmi::network::ETHERNET_INTERFACE)); ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ // for an ip object there would be single parent ++ // interface. ++ networkInterfacePath = ancestorMap.begin()->first; ++ } ++ catch (InternalFailure& e) ++ { ++ // if there is no ip configured on the system,then ++ // get the network interface object. ++ auto networkInterfaceObject = ipmi::getDbusObject( ++ bus, ipmi::network::ETHERNET_INTERFACE, ++ ipmi::network::ROOT, ethdevice); ++ ++ networkInterfacePath = networkInterfaceObject.first; ++ } ++ ++ auto variant = ipmi::getDbusProperty( ++ bus, ipmi::network::SERVICE, networkInterfacePath, ++ ipmi::network::ETHERNET_INTERFACE, "IPv6AcceptRA"); ++ dynamicRA = std::get<bool>(variant); ++ } ++ else ++ { ++ dynamicRA = channelConf->ipv6RouterAddressConfigControl; ++ } ++ ++ std::array<uint8_t, 2> buf = {current_revision, dynamicRA}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_1_IP_ADDR: ++ { ++ std::array<uint8_t, ipmi::network::IPV6_ADDRESS_SIZE_BYTE + ++ sizeof(current_revision)> ++ buf = {current_revision}; ++ inet_pton(AF_INET6, channelConf->ipv6GatewayAddr.c_str(), ++ reinterpret_cast<void*>(&buf[1])); ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_1_PREFIX_LEN: ++ { ++ std::array<uint8_t, 2> buf = {current_revision, ++ channelConf->ipv6GatewayPrefixLength}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_1_PREFIX_VAL: ++ { ++ constexpr uint8_t setSelector = 0; ++ std::array<uint8_t, sizeof(setSelector) + ++ ipmi::network::IPV6_ADDRESS_SIZE_BYTE + ++ sizeof(current_revision)> ++ buf = {current_revision, setSelector}; ++ ++ inet_pton(AF_INET6, channelConf->ipv6GatewayPrefixValue.c_str(), ++ reinterpret_cast<void*>(&buf[2])); ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_2_IP_ADDR: ++ { ++ std::array<uint8_t, ipmi::network::IPV6_ADDRESS_SIZE_BYTE + ++ sizeof(current_revision)> ++ buf = {current_revision}; ++ inet_pton(AF_INET6, channelConf->ipv6BackupGatewayAddr.c_str(), ++ reinterpret_cast<void*>(&buf[1])); ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_2_PREFIX_LEN: ++ { ++ std::array<uint8_t, 2> buf = { ++ current_revision, channelConf->ipv6BackupGatewayPrefixLength}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_2_PREFIX_VAL: ++ { ++ ++ constexpr uint8_t setSelector = 0; ++ std::array<uint8_t, sizeof(setSelector) + ++ ipmi::network::IPV6_ADDRESS_SIZE_BYTE + ++ sizeof(current_revision)> ++ buf = {current_revision, setSelector}; ++ inet_pton(AF_INET6, ++ channelConf->ipv6BackupGatewayPrefixValue.c_str(), ++ reinterpret_cast<void*>(&buf[2])); ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } + default: + log<level::ERR>("Unsupported parameter", + entry("PARAMETER=0x%x", reqptr->parameter)); +@@ -921,6 +1546,16 @@ void applyChanges(int channel) + ipaddress, prefix); + } + ++ if (!channelConf->ipv6Addr.empty() && ++ channelConf->ipv6AddressSource == ++ 0x80) // Check if IPv6 static addresses are enabled ++ { ++ ipmi::network::createIP(bus, ipmi::network::SERVICE, ++ networkInterfacePath, ipv6Protocol, ++ channelConf->ipv6Addr, ++ channelConf->ipv6Prefix); ++ } ++ + if (!gateway.empty()) + { + ipmi::setDbusProperty(bus, systemObject.second, +@@ -928,7 +1563,24 @@ void applyChanges(int channel) + ipmi::network::SYSTEMCONFIG_INTERFACE, + "DefaultGateway", std::string(gateway)); + } ++ else if (!channelConf->ipv6GatewayAddr.empty()) ++ { ++ ipmi::setDbusProperty( ++ bus, systemObject.second, systemObject.first, ++ ipmi::network::SYSTEMCONFIG_INTERFACE, "DefaultGateway", ++ std::string(channelConf->ipv6GatewayAddr)); ++ } + } ++ // set IPAddress Enables ++ ipmi::setDbusProperty( ++ bus, ipmi::network::SERVICE, networkInterfaceObject.first, ++ ipmi::network::ETHERNET_INTERFACE, "IPAddressEnables", ++ ipAddressEnablesType[channelConf->ipv6AddressingEnables]); ++ ++ ipmi::setDbusProperty( ++ bus, ipmi::network::SERVICE, networkInterfaceObject.first, ++ ipmi::network::ETHERNET_INTERFACE, "IPv6AcceptRA", ++ (bool)channelConf->ipv6RouterAddressConfigControl); + } + catch (InternalFailure& e) + { +diff --git a/transporthandler.hpp b/transporthandler.hpp +index 04d4673..bd23391 100644 +--- a/transporthandler.hpp ++++ b/transporthandler.hpp +@@ -79,6 +79,28 @@ enum class LanParam : uint8_t + IPV6_NEIGHBOR_TIMING_CONFIGURATION = 80, + }; + ++// Data length of parameters ++constexpr size_t LAN_PARAM_INPROGRESS_SIZE = 3; ++constexpr size_t LAN_PARAM_IP_SIZE = 6; ++constexpr size_t LAN_PARAM_IPSRC_SIZE = 3; ++constexpr size_t LAN_PARAM_MAC_SIZE = 8; ++constexpr size_t LAN_PARAM_SUBNET_SIZE = 6; ++constexpr size_t LAN_PARAM_GATEWAY_SIZE = 6; ++constexpr size_t LAN_PARAM_VLAN_SIZE = 4; ++constexpr size_t LAN_PARAM_IPV6_AND_IPV4_ENABLES_SIZE = 3; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ADDRESSES_SIZE = 23; ++constexpr size_t LAN_PARAM_IPV6_ROUTER_ADDRESS_CONF_CTRL_SIZE = 3; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_1_IP_ADDR_SIZE = 18; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_1_PREFIX_LEN_SIZE = 3; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_1_PREFIX_VAL_SIZE = 19; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_2_IP_ADDR_SIZE = 18; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_2_PREFIX_LEN_SIZE = 3; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_2_PREFIX_VAL_SIZE = 19; ++ ++constexpr uint8_t DUID_LEN = 10; ++constexpr uint8_t DUID_LL_TYPE = 3; ++constexpr uint8_t DUIC_ETH_HW_TYPE = 1; ++ + constexpr uint8_t SET_COMPLETE = 0; + constexpr uint8_t SET_IN_PROGRESS = 1; + constexpr uint8_t SET_COMMIT_WRITE = 2; // Optional +@@ -101,6 +123,20 @@ struct ChannelConfig_t + uint8_t lan_set_in_progress = SET_COMPLETE; + bool flush = false; + ++ // IPV6 parameters ++ uint8_t ipv6AddressSource = 0x0; ++ uint8_t ipv6AddressingEnables = 0x2; ++ std::string ipv6Addr; ++ uint8_t ipv6Prefix = 32; ++ uint8_t ipv6AddressStatus = 0x0; ++ uint8_t ipv6RouterAddressConfigControl = 0x0; ++ std::string ipv6GatewayAddr; ++ std::string ipv6BackupGatewayAddr; ++ uint8_t ipv6GatewayPrefixLength; ++ std::string ipv6GatewayPrefixValue; ++ uint8_t ipv6BackupGatewayPrefixLength = 0x0; ++ std::string ipv6BackupGatewayPrefixValue; ++ + void clear() + { + ipaddr.clear(); +@@ -111,6 +147,20 @@ struct ChannelConfig_t + ipsrc = ipmi::network::IPOrigin::UNSPECIFIED; + lan_set_in_progress = SET_COMPLETE; + flush = false; ++ ++ // IPv6 ++ ipv6Addr.clear(); ++ ipv6GatewayAddr.clear(); ++ ipv6BackupGatewayAddr.clear(); ++ ipv6AddressingEnables = 0x2; ++ ipv6AddressSource = 0x0; ++ ipv6Prefix = 32; ++ ipv6AddressStatus = 0x0; ++ ipv6RouterAddressConfigControl = 0x0; ++ ipv6GatewayPrefixLength = 0x0; ++ ipv6GatewayPrefixValue.clear(); ++ ipv6BackupGatewayPrefixLength = 0x0; ++ ipv6BackupGatewayPrefixValue.clear(); + } + }; + +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch new file mode 100644 index 000000000..c1ec6ac6e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch @@ -0,0 +1,56 @@ +From 4953a9f2233fd24a28da84443cea6aebecd14fbc Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Mon, 17 Sep 2018 13:20:54 +0800 +Subject: [PATCH] fix "get system GUID" ipmi command + +Change-Id: I15c71607c24ad8b3e2c9065a5470002ecb1761bb +Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + apphandler.cpp | 7 ++----- + host-ipmid-whitelist.conf | 1 + + 2 files changed, 3 insertions(+), 5 deletions(-) + +diff --git a/apphandler.cpp b/apphandler.cpp +index f2889c5..9149373 100644 +--- a/apphandler.cpp ++++ b/apphandler.cpp +@@ -48,7 +48,7 @@ extern sd_bus* bus; + + constexpr auto bmc_state_interface = "xyz.openbmc_project.State.BMC"; + constexpr auto bmc_state_property = "CurrentBMCState"; +-constexpr auto bmc_interface = "xyz.openbmc_project.Inventory.Item.Bmc"; ++// phosphor-setting-manager is the unique service that holds this interface + constexpr auto bmc_guid_interface = "xyz.openbmc_project.Common.UUID"; + constexpr auto bmc_guid_property = "UUID"; + constexpr auto bmc_guid_len = 16; +@@ -546,8 +545,7 @@ ipmi_ret_t ipmi_app_get_sys_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + { + // Get the Inventory object implementing BMC interface + ipmi::DbusObjectInfo bmcObject = +- ipmi::getDbusObject(bus, bmc_interface); +- ++ ipmi::getDbusObject(bus, bmc_guid_interface); + // Read UUID property value from bmcObject + // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223 + auto variant = +@@ -591,7 +589,6 @@ ipmi_ret_t ipmi_app_get_sys_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + catch (const InternalFailure& e) + { + log<level::ERR>("Failed in reading BMC UUID property", +- entry("INTERFACE=%s", bmc_interface), + entry("PROPERTY_INTERFACE=%s", bmc_guid_interface), + entry("PROPERTY=%s", bmc_guid_property)); + return IPMI_CC_UNSPECIFIED_ERROR; +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index 2c37ac9..164edbe 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -40,3 +40,4 @@ + 0x2C:0x06 //<Group Extension>:<Get Asset Tag> + 0x2C:0x07 //<Group Extension>:<Get Sensor Info> + 0x2C:0x10 //<Group Extension>:<Get Temperature Readings> ++0x30:0x41 //<OEM>:<Set System GUID> +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0012-ipmi-set-get-boot-options.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0012-ipmi-set-get-boot-options.patch new file mode 100644 index 000000000..243015c95 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0012-ipmi-set-get-boot-options.patch @@ -0,0 +1,64 @@ +From 7b5c6a54c049a447b1fd3a42f9d63322dcee4dc7 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Sun, 16 Sep 2018 19:45:10 +0800 +Subject: [PATCH] [ipmi] set/get boot options + +1. fix issue for handling unsupported paramter +2. add support for floppy/USB boot + +Change-Id: I2b888c1ad67fec7924dd5825f78622cd216a55f4 +Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + chassishandler.cpp | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 666addb..77af2dc 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -1244,7 +1244,8 @@ constexpr auto ipmiDefault = 0; + std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = { + {0x01, Source::Sources::Network}, + {0x02, Source::Sources::Disk}, +- {0x05, Source::Sources::ExternalMedia}, ++ {0x05, Source::Sources::DVD}, ++ {0x0f, Source::Sources::Removable}, + {ipmiDefault, Source::Sources::Default}}; + + std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = { +@@ -1255,7 +1256,8 @@ std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = { + std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = { + {Source::Sources::Network, 0x01}, + {Source::Sources::Disk, 0x02}, +- {Source::Sources::ExternalMedia, 0x05}, ++ {Source::Sources::DVD, 0x05}, ++ {Source::Sources::Removable, 0x0f}, + {Source::Sources::Default, ipmiDefault}}; + + std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = { +@@ -1533,7 +1535,7 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + setBootMode(Mode::Modes::Regular); + } + } +- if (modeIpmiToDbus.end() != modeItr) ++ else if (modeIpmiToDbus.end() != modeItr) + { + rc = setBootMode(modeItr->second); + if (rc != IPMI_CC_OK) +@@ -1550,6 +1552,12 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + setBootSource(Source::Sources::Default); + } + } ++ else ++ { ++ // if boot option is not in support list, return error ++ *data_len = 0; ++ return IPMI_CC_INVALID_FIELD_REQUEST; ++ } + } + catch (InternalFailure& e) + { +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0013-ipmi-add-set-bios-id-to-whitelist.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0013-ipmi-add-set-bios-id-to-whitelist.patch new file mode 100644 index 000000000..ae10ab60a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0013-ipmi-add-set-bios-id-to-whitelist.patch @@ -0,0 +1,25 @@ +From ad7276f3aedb6f5aed315db57406c98f2bf71a09 Mon Sep 17 00:00:00 2001 +From: "Jia, Chunhui" <chunhui.jia@intel.com> +Date: Tue, 24 Jul 2018 13:21:52 +0800 +Subject: [PATCH] [ipmi] add set bios id to whitelist + +Add "SetBIOSId" and "GetDeviceInfo" 2 OEM commands into whitelist + +Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com> +--- + host-ipmid-whitelist.conf | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index 164edbe..db54a49 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -41,3 +41,5 @@ + 0x2C:0x07 //<Group Extension>:<Get Sensor Info> + 0x2C:0x10 //<Group Extension>:<Get Temperature Readings> + 0x30:0x41 //<OEM>:<Set System GUID> ++0x30:0x26 //<OEM>:<Set BIOS ID> ++0x30:0x27 //<OEM>:<Get Device Info> +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0014-Enable-get-device-guid-ipmi-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0014-Enable-get-device-guid-ipmi-command.patch new file mode 100644 index 000000000..46dd99466 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0014-Enable-get-device-guid-ipmi-command.patch @@ -0,0 +1,45 @@ +From 482a6cc52d0ec514d6da5f4bcb04b4991f3cc36e Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Mon, 17 Sep 2018 13:41:25 +0800 +Subject: [PATCH] Enable get device guid ipmi command + +The UUID interface is changed, modify the API to get the correct UUID +for device guid + +Change-Id: I0c0c7bd350992ac03f928707986a7180407d8f3f +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + apphandler.cpp | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/apphandler.cpp b/apphandler.cpp +index 937be71..89d797a 100644 +--- a/apphandler.cpp ++++ b/apphandler.cpp +@@ -392,9 +392,10 @@ ipmi_ret_t ipmi_app_get_device_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_data_len_t data_len, + ipmi_context_t context) + { +- const char* objname = "/xyz/openbmc_project/Chassis/Control/Chassis"; ++ const char* objname = ++ "/xyz/openbmc_project/inventory/system/chassis/motherboard/bmc"; + const char* iface = "org.freedesktop.DBus.Properties"; +- const char* chassis_iface = "xyz.openbmc_project.Chassis.Control.Chassis"; ++ const char* uuid_iface = "xyz.openbmc_project.Common.UUID"; + sd_bus_message* reply = NULL; + sd_bus_error error = SD_BUS_ERROR_NULL; + int r = 0; +@@ -426,8 +427,9 @@ ipmi_ret_t ipmi_app_get_device_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + entry("ERRNO=0x%X", -r)); + goto finish; + } ++ + r = sd_bus_call_method(bus, busname, objname, iface, "Get", &error, &reply, +- "ss", chassis_iface, "uuid"); ++ "ss", uuid_iface, "UUID"); + if (r < 0) + { + log<level::ERR>("Failed to call Get Method", entry("ERRNO=0x%X", -r)); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0021-Implement-IPMI-Commmand-Get-Host-Restart-Cause.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0021-Implement-IPMI-Commmand-Get-Host-Restart-Cause.patch new file mode 100644 index 000000000..af526c177 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0021-Implement-IPMI-Commmand-Get-Host-Restart-Cause.patch @@ -0,0 +1,143 @@ +From c14e31ebc35e0bb7b843d84683f9f2698c9c08d7 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Sun, 16 Sep 2018 21:32:38 +0800 +Subject: [PATCH] Implement IPMI Commmand - Get Host Restart Cause. + +It supports to track the information about what +action last caused the system to restart. +Return value includes: restart_cause and channel_number. + +According to IPMI Spec, it includes 12 types as following: +1. Unknown 0x0 +2. IpmiCommand 0x1 +3. ResetButton 0x2 +4. PowerButton 0x3 +5. WatchdogTimer 0x4 +6. OEM 0x5 +7. PowerPolicyAlwaysOn 0x6 +8. PowerPolicyPreviousState 0x7 +9. PEF-Reset 0x8 +10. PEF-PowerCycle 0x9 +11. SoftReset 0xA +12. RTC-Wakeup 0xB + +Change-Id: Id3b32e271b85b5fc4c69d5ca40227f8f9c08ce48 +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + chassishandler.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++++++ + chassishandler.hpp | 1 + + host-ipmid-whitelist.conf | 1 + + 3 files changed, 56 insertions(+) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 77af2dc..2a29755 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -107,6 +107,11 @@ static constexpr auto chassisPOHStateIntf = + "xyz.openbmc_project.State.PowerOnHours"; + static constexpr auto pOHCounterProperty = "POHCounter"; + static constexpr auto match = "chassis0"; ++const static constexpr char* stateHostInterface = ++ "xyz.openbmc_project.State.Host"; ++const static constexpr char* hostRestartCauseInterface = ++ "xyz.openbmc_project.State.Host.HostRestartCause"; ++const static constexpr char* hostRestartCause = "HostRestartCause"; + const static constexpr char chassisCapIntf[] = + "xyz.openbmc_project.Control.ChassisCapabilities"; + const static constexpr char chassisCapFlagsProp[] = "CapabilitiesFlags"; +@@ -324,6 +329,13 @@ struct set_sys_boot_options_t + uint8_t data[SIZE_BOOT_OPTION]; + } __attribute__((packed)); + ++struct GetSysRestartCauseResponse ++{ ++ uint8_t restartCause; ++ uint8_t channelNum; ++ ++} __attribute__((packed)); ++ + int getHostNetworkData(get_sys_boot_options_response_t* respptr) + { + ipmi::PropertyMap properties; +@@ -1598,6 +1610,44 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + return rc; + } + ++ipmi_ret_t ipmi_chassis_get_sys_restart_cause( ++ ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request, ++ ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context) ++{ ++ ipmi_ret_t rc = IPMI_CC_OK; ++ ++ GetSysRestartCauseResponse* resp = (GetSysRestartCauseResponse*)response; ++ std::fill(reinterpret_cast<uint8_t*>(resp), ++ reinterpret_cast<uint8_t*>(resp) + sizeof(*resp), 0); ++ if (*data_len != 0) ++ { ++ rc = IPMI_CC_REQ_DATA_LEN_INVALID; ++ return rc; ++ } ++ ++ try ++ { ++ sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; ++ ipmi::DbusObjectInfo hostObject = ++ ipmi::getDbusObject(bus, stateHostInterface); ++ ipmi::Value variant = ++ ipmi::getDbusProperty(bus, hostObject.second, hostObject.first, ++ hostRestartCauseInterface, hostRestartCause); ++ resp->restartCause = variant.get<uint8_t>(); ++ } ++ ++ catch (std::exception& e) ++ { ++ log<level::ERR>(e.what()); ++ rc = IPMI_CC_UNSPECIFIED_ERROR; ++ return rc; ++ } ++ resp->channelNum = 0; // Fix to primary channel. ++ *data_len = sizeof(GetSysRestartCauseResponse); ++ ++ return rc; ++} ++ + ipmi_ret_t ipmiGetPOHCounter(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_request_t request, ipmi_response_t response, + ipmi_data_len_t data_len, ipmi_context_t context) +@@ -1739,4 +1789,8 @@ void register_netfn_chassis_functions() + ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_SET_RESTORE_POLICY, NULL, + ipmi_chassis_set_power_restore_policy, + PRIVILEGE_OPERATOR); ++ ++ // <get Host Restart Cause> ++ ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_SYS_RESTART_CAUSE, NULL, ++ ipmi_chassis_get_sys_restart_cause, PRIVILEGE_USER); + } +diff --git a/chassishandler.hpp b/chassishandler.hpp +index 0c6d5a2..e37c4f1 100644 +--- a/chassishandler.hpp ++++ b/chassishandler.hpp +@@ -17,6 +17,7 @@ enum ipmi_netfn_chassis_cmds + // Set Power Restore Policy + IPMI_CMD_SET_RESTORE_POLICY = 0x06, + // Get capability bits ++ IPMI_CMD_GET_SYS_RESTART_CAUSE = 0x07, + IPMI_CMD_SET_SYS_BOOT_OPTIONS = 0x08, + IPMI_CMD_GET_SYS_BOOT_OPTIONS = 0x09, + IPMI_CMD_GET_POH_COUNTER = 0x0F, +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index db54a49..827e2dc 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -3,6 +3,7 @@ + 0x00:0x02 //<Chassis>:<Chassis Control> + 0x00:0x05 //<Chassis>:<Set Chassis Capabilities> + 0x00:0x06 //<Chassis>:<Set Power Restore Policy> ++0x00:0x07 //<Chassis>:<Get System Restart Cause> + 0x00:0x08 //<Chassis>:<Set System Boot Options> + 0x00:0x09 //<Chassis>:<Get System Boot Options> + 0x00:0x0F //<Chassis>:<Get POH Counter Command> +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0039-ipmi-add-oem-command-get-AIC-FRU-to-whitelist.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0039-ipmi-add-oem-command-get-AIC-FRU-to-whitelist.patch new file mode 100644 index 000000000..fdaa91085 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0039-ipmi-add-oem-command-get-AIC-FRU-to-whitelist.patch @@ -0,0 +1,25 @@ +From cf466ba2c66a95825ae0014d7c378ad63b050d2f Mon Sep 17 00:00:00 2001 +From: "Jia, Chunhui" <chunhui.jia@intel.com> +Date: Wed, 15 Aug 2018 14:50:04 +0800 +Subject: [PATCH] [ipmi] add oem command "get AIC FRU" to whitelist + +Intel BIOS requires this oem command to get addon card FRU info. +Add to whitelist to unblock. + +Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com> +--- + host-ipmid-whitelist.conf | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index db54a49..49746a2 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -43,3 +43,4 @@ + 0x30:0x41 //<OEM>:<Set System GUID> + 0x30:0x26 //<OEM>:<Set BIOS ID> + 0x30:0x27 //<OEM>:<Get Device Info> ++0x30:0x31 //<OEM>:<Get AIC card FRU> +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0048-Implement-IPMI-Master-Write-Read-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0048-Implement-IPMI-Master-Write-Read-command.patch new file mode 100644 index 000000000..542c4f667 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0048-Implement-IPMI-Master-Write-Read-command.patch @@ -0,0 +1,351 @@ +From a8d7429b7bd9dea33d59c6e83f17372e77fe6145 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Fri, 21 Sep 2018 09:21:14 +0800 +Subject: [PATCH] Implement IPMI Master Write-Read command + +This command can be used for low-level I2C/SMBus write, read, or write-read +accesses to the IPMB or private busses behind a management controller. + +The command can also be used for providing low-level access to devices +that provide an SMBus slave interface. + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + apphandler.cpp | 276 +++++++++++++++++++++++++++++++++++++- + apphandler.hpp | 1 + + host-ipmid-whitelist.conf | 1 + + 3 files changed, 274 insertions(+), 4 deletions(-) + +diff --git a/apphandler.cpp b/apphandler.cpp +index 15965ca..d8fb23d 100644 +--- a/apphandler.cpp ++++ b/apphandler.cpp +@@ -1,6 +1,19 @@ ++#include "apphandler.hpp" ++ ++#include "app/watchdog.hpp" ++#include "sys_info_param.hpp" ++#include "transporthandler.hpp" ++ + #include <arpa/inet.h> ++#include <fcntl.h> ++#include <ipmid/api.h> + #include <limits.h> ++#include <linux/i2c-dev.h> ++#include <linux/i2c.h> + #include <mapper.h> ++#include <sys/ioctl.h> ++#include <sys/stat.h> ++#include <sys/types.h> + #include <systemd/sd-bus.h> + #include <unistd.h> + +@@ -41,6 +54,8 @@ constexpr auto bmc_guid_interface = "xyz.openbmc_project.Common.UUID"; + constexpr auto bmc_guid_property = "UUID"; + constexpr auto bmc_guid_len = 16; + ++static constexpr uint8_t maxIPMIWriteReadSize = 144; ++ + static constexpr auto redundancyIntf = + "xyz.openbmc_project.Software.RedundancyPriority"; + static constexpr auto versionIntf = "xyz.openbmc_project.Software.Version"; +@@ -59,6 +74,47 @@ using BMC = sdbusplus::xyz::openbmc_project::State::server::BMC; + namespace fs = std::filesystem; + namespace variant_ns = sdbusplus::message::variant_ns; + ++// Offset in get device id command. ++typedef struct ++{ ++ uint8_t id; ++ uint8_t revision; ++ uint8_t fw[2]; ++ uint8_t ipmi_ver; ++ uint8_t addn_dev_support; ++ uint8_t manuf_id[3]; ++ uint8_t prod_id[2]; ++ uint8_t aux[4]; ++} __attribute__((packed)) ipmi_device_id_t; ++ ++typedef struct ++{ ++ uint8_t busId; ++ uint8_t slaveAddr; ++ uint8_t readCount; ++} __attribute__((packed)) ipmiI2cRwReq; ++ ++typedef struct ++{ ++ uint8_t busId; ++ uint8_t slaveAddr; ++ std::vector<uint8_t> data; ++} ipmiMasterRwWhitelist; ++ ++static std::vector<ipmiMasterRwWhitelist>& getWhiteList() ++{ ++ static std::vector<ipmiMasterRwWhitelist> rwWhiteList; ++ return rwWhiteList; ++} ++ ++static constexpr const char* whiteListFilename = ++ "/usr/share/ipmi-providers/master_write_read_white_list.json"; ++ ++static constexpr const char* filtersStr = "filters"; ++static constexpr const char* busIdStr = "busId"; ++static constexpr const char* slaveAddrStr = "slaveAddr"; ++static constexpr const char* cmdStr = "command"; ++ + /** + * @brief Returns the Version info from primary s/w object + * +@@ -1022,6 +1078,192 @@ writeResponse: + return IPMI_CC_OK; + } + ++static int loadI2CWhiteList() ++{ ++ nlohmann::json data = nullptr; ++ std::ifstream jsonFile(whiteListFilename); ++ ++ if (!jsonFile.good()) ++ { ++ log<level::WARNING>("whitelist file not found!"); ++ return -1; ++ } ++ ++ try ++ { ++ data = nlohmann::json::parse(jsonFile, nullptr, false); ++ } ++ catch (nlohmann::json::parse_error& e) ++ { ++ log<level::ERR>("Corrupted whitelist config file", ++ entry("MSG: %s", e.what())); ++ return -1; ++ } ++ ++ try ++ { ++ unsigned int i = 0; ++ nlohmann::json filters = data[filtersStr].get<nlohmann::json>(); ++ getWhiteList().resize(filters.size()); ++ ++ for (const auto& it : filters.items()) ++ { ++ nlohmann::json filter = it.value(); ++ if (filter.is_null()) ++ { ++ log<level::ERR>("Incorrect filter"); ++ return -1; ++ } ++ ++ getWhiteList()[i].busId = ++ std::stoul(filter[busIdStr].get<std::string>(), nullptr, 16); ++ ++ getWhiteList()[i].slaveAddr = std::stoul( ++ filter[slaveAddrStr].get<std::string>(), nullptr, 16); ++ ++ std::string command = filter[cmdStr].get<std::string>(); ++ ++ log<level::DEBUG>("IPMI I2C whitelist ", entry("INDEX=%d", i), ++ entry("BUS=%d", getWhiteList()[i].busId), ++ entry("ADDR=0x%x", getWhiteList()[i].slaveAddr), ++ entry("LEN=0x%x", command.length()), ++ entry("COMMAND=[%s]", command.c_str())); ++ ++ // convert data string ++ std::istringstream iss(command); ++ std::string token; ++ while (std::getline(iss, token, ' ')) ++ { ++ log<level::DEBUG>("IPMI I2C command\n", ++ entry("TOKEN=%s", token.c_str())); ++ getWhiteList()[i].data.emplace_back( ++ std::stoul(token, nullptr, 16)); ++ } ++ i++; ++ } ++ } ++ catch (std::exception& e) ++ { ++ log<level::ERR>("unexpected exception", entry("ERROR=%s", e.what())); ++ return -1; ++ } ++ return 0; ++} ++ ++ipmi_ret_t ipmiMasterWriteRead(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ++ ipmi_request_t request, ipmi_response_t response, ++ ipmi_data_len_t data_len, ipmi_context_t context) ++{ ++ bool foundInList = false; ++ int ret = 0; ++ i2c_rdwr_ioctl_data msgRdwr = {0}; ++ i2c_msg i2cmsg[2] = {0}; ++ ipmiI2cRwReq* reqi2c = reinterpret_cast<ipmiI2cRwReq*>(request); ++ ++ if (*data_len <= sizeof(ipmiI2cRwReq)) ++ { ++ log<level::ERR>("Failed in request", entry("LEN=%d", *data_len)); ++ *data_len = 0; ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ if (reqi2c->readCount > maxIPMIWriteReadSize) ++ { ++ log<level::ERR>("Failed in request", entry("R=%d", reqi2c->readCount)); ++ *data_len = 0; ++ return IPMI_CC_PARM_OUT_OF_RANGE; ++ } ++ ++ uint8_t* resptr = reinterpret_cast<uint8_t*>(response); ++ uint8_t busId = (reqi2c->busId & 0xFF) >> 1; ++ // Convert the I2C address from 7-bit format ++ uint8_t i2cAddr = reqi2c->slaveAddr >> 1; ++ size_t writeCount = *data_len - sizeof(ipmiI2cRwReq); ++ ++ log<level::DEBUG>( ++ "INPUT: ", entry("LEN=%d", *data_len), entry("ID=0x%x", busId), ++ entry("ADDR=0x%x", reqi2c->slaveAddr), entry("R=%d", reqi2c->readCount), ++ entry("W=%d", writeCount)); ++ ++ *data_len = 0; ++ ++ std::vector<uint8_t> inBuf(reqi2c->readCount); ++ std::vector<uint8_t> outBuf(writeCount); ++ uint8_t* reqptr = reinterpret_cast<uint8_t*>(request); ++ ++ reqptr += sizeof(ipmiI2cRwReq); ++ std::copy(reqptr, reqptr + writeCount, outBuf.begin()); ++ ++ log<level::DEBUG>("checking list ", ++ entry("SIZE=%d", getWhiteList().size())); ++ // command whitelist checking ++ for (unsigned int i = 0; i < getWhiteList().size(); i++) ++ { ++ // TODO add wildchard/regex support ++ if ((busId == getWhiteList()[i].busId) && ++ (i2cAddr == getWhiteList()[i].slaveAddr) && ++ (outBuf == getWhiteList()[i].data)) ++ { ++ log<level::DEBUG>("In whitelist"); ++ foundInList = true; ++ break; ++ } ++ } ++ ++ if (!foundInList) ++ { ++ log<level::ERR>("Request blocked!", entry("BUS=%d", busId), ++ entry("ADDR=0x%x", reqi2c->slaveAddr)); ++ return IPMI_CC_INVALID_FIELD_REQUEST; ++ } ++ ++ log<level::DEBUG>("IPMI Master WriteRead ", entry("BUS=%d", busId), ++ entry("ADDR=0x%x", reqi2c->slaveAddr), ++ entry("R=%d", reqi2c->readCount), ++ entry("W=%d", writeCount)); ++ ++ std::string i2cBus = "/dev/i2c-" + std::to_string(busId); ++ ++ int i2cDev = ::open(i2cBus.c_str(), O_RDWR | O_CLOEXEC); ++ if (i2cDev < 0) ++ { ++ log<level::ERR>("Failed in opening i2c device", ++ entry("BUS=%s", i2cBus.c_str())); ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ ++ // write message ++ i2cmsg[0].addr = i2cAddr; ++ i2cmsg[0].flags = 0x00; ++ i2cmsg[0].len = writeCount; ++ i2cmsg[0].buf = outBuf.data(); ++ ++ // read message ++ i2cmsg[1].addr = i2cAddr; ++ i2cmsg[1].flags = I2C_M_RD; ++ i2cmsg[1].len = reqi2c->readCount; ++ i2cmsg[1].buf = inBuf.data(); ++ ++ msgRdwr.msgs = i2cmsg; ++ msgRdwr.nmsgs = 2; ++ ++ ret = ::ioctl(i2cDev, I2C_RDWR, &msgRdwr); ++ ::close(i2cDev); ++ ++ // TODO add completion code support ++ if (ret < 0) ++ { ++ log<level::ERR>("RDWR ioctl error", entry("RET=%d", ret)); ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ ++ *data_len = msgRdwr.msgs[1].len; ++ std::copy(msgRdwr.msgs[1].buf, msgRdwr.msgs[1].buf + msgRdwr.msgs[1].len, ++ resptr); ++ ++ return IPMI_CC_OK; ++} ++ + void register_netfn_app_functions() + { + // <Get Device ID> +@@ -1063,6 +1306,31 @@ void register_netfn_app_functions() + ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_ACPI, NULL, + ipmi_app_get_acpi_power_state, PRIVILEGE_ADMIN); + ++// TODO: Below code and associated api's need to be removed later. ++// Its commented for now to avoid merge conflicts with upstream ++// changes and smooth upstream upgrades. ++#if 0 ++>>>>>>> IPMI Channel commands implementation ++ // <Get Channel Access> ++ ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_ACCESS, NULL, ++ ipmi_get_channel_access, PRIVILEGE_USER); ++ ++ // <Get Channel Info Command> ++ ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHAN_INFO, NULL, ++ ipmi_app_channel_info, PRIVILEGE_USER); ++#endif ++ ++ int ret = loadI2CWhiteList(); ++ log<level::DEBUG>("i2c white list is loaded", entry("RET=%d", ret), ++ entry("SIZE=%d", getWhiteList().size())); ++ if (ret == 0) ++ { ++ log<level::DEBUG>("Register Master RW command"); ++ // <Master Write Read Command> ++ ipmi_register_callback(NETFUN_APP, IPMI_CMD_MASTER_WRITE_READ, NULL, ++ ipmiMasterWriteRead, PRIVILEGE_OPERATOR); ++ } ++ + // <Get System GUID Command> + ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SYS_GUID, NULL, + ipmi_app_get_sys_guid, PRIVILEGE_USER); +diff --git a/apphandler.hpp b/apphandler.hpp +index d4dd8e8..f9e5c59 100644 +--- a/apphandler.hpp ++++ b/apphandler.hpp +@@ -19,6 +19,7 @@ enum ipmi_netfn_app_cmds + IPMI_CMD_SET_CHAN_ACCESS = 0x40, + IPMI_CMD_GET_CHANNEL_ACCESS = 0x41, + IPMI_CMD_GET_CHAN_INFO = 0x42, ++ IPMI_CMD_MASTER_WRITE_READ = 0x52, + IPMI_CMD_GET_CHAN_CIPHER_SUITES = 0x54, + IPMI_CMD_SET_SYSTEM_INFO = 0x58, + IPMI_CMD_GET_SYSTEM_INFO = 0x59, +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index 49ff7b0..1ae79fd 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -27,6 +27,7 @@ + 0x06:0x37 //<App>:<Get System GUID> + 0x06:0x42 //<App>:<Get Channel Info Command> + 0x06:0x4E //<App>:<Get Channel Payload Support> ++0x06:0x52 //<App>:<Master Write Read Command> + 0x06:0x54 //<App>:<Get Channel Cipher Suites> + 0x0A:0x10 //<Storage>:<Get FRU Inventory Area Info> + 0x0A:0x11 //<Storage>:<Read FRU Data> +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0049-Fix-Unspecified-error-on-ipmi-restart-cause-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0049-Fix-Unspecified-error-on-ipmi-restart-cause-command.patch new file mode 100644 index 000000000..aba5eb095 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0049-Fix-Unspecified-error-on-ipmi-restart-cause-command.patch @@ -0,0 +1,71 @@ +From 59287a8869b5253a1b4203e0cc8a92f063dcc7e6 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Tue, 25 Sep 2018 16:08:22 +0800 +Subject: [PATCH] Fix "Unspecified error" on ipmi restart cause command + +Needs to convert the dbus value(enum) into ipmi value(uint8) + +Tested by: +ipmitool chassis restart_cause + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + chassishandler.cpp | 28 ++++++++++++++++++++++++++-- + 1 file changed, 26 insertions(+), 2 deletions(-) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 40eb4f5..c3d4931 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -106,7 +106,7 @@ static constexpr auto match = "chassis0"; + const static constexpr char* stateHostInterface = + "xyz.openbmc_project.State.Host"; + const static constexpr char* hostRestartCauseInterface = +- "xyz.openbmc_project.State.Host.HostRestartCause"; ++ "xyz.openbmc_project.State.Host"; + const static constexpr char* hostRestartCause = "HostRestartCause"; + const static constexpr char chassisCapIntf[] = + "xyz.openbmc_project.Control.ChassisCapabilities"; +@@ -1764,6 +1764,26 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + return rc; + } + ++namespace restart_cause ++{ ++ ++using namespace sdbusplus::xyz::openbmc_project::State::server; ++ ++std::map<Host::RestartCause, uint8_t> dbusToIpmi = { ++ {Host::RestartCause::Unknown, 0x0}, ++ {Host::RestartCause::IpmiCommand, 0x1}, ++ {Host::RestartCause::ResetButton, 0x2}, ++ {Host::RestartCause::PowerButton, 0x3}, ++ {Host::RestartCause::WatchdogTimer, 0x4}, ++ {Host::RestartCause::OEM, 0x5}, ++ {Host::RestartCause::PowerPolicyAlwaysOn, 0x6}, ++ {Host::RestartCause::PowerPolicyPreviousState, 0x7}, ++ {Host::RestartCause::PEFReset, 0x8}, ++ {Host::RestartCause::PEFPowerCycle, 0x9}, ++ {Host::RestartCause::SoftReset, 0xa}, ++ {Host::RestartCause::RTCWakeup, 0xb}}; ++} // namespace restart_cause ++ + ipmi_ret_t ipmi_chassis_get_sys_restart_cause( + ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request, + ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context) +@@ -1787,7 +1807,11 @@ ipmi_ret_t ipmi_chassis_get_sys_restart_cause( + ipmi::Value variant = + ipmi::getDbusProperty(bus, hostObject.second, hostObject.first, + hostRestartCauseInterface, hostRestartCause); +- resp->restartCause = variant.get<uint8_t>(); ++ ++ std::string restartCause = ++ sdbusplus::message::variant_ns::get<std::string>(variant); ++ resp->restartCause = restart_cause::dbusToIpmi.at( ++ restart_cause::Host::convertRestartCauseFromString(restartCause)); + } + + catch (std::exception& e) +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0050-enable-6-oem-commands.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0050-enable-6-oem-commands.patch new file mode 100644 index 000000000..b800632cc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0050-enable-6-oem-commands.patch @@ -0,0 +1,15 @@ +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index 22a2a3c..5d71698 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -49,3 +49,10 @@ + 0x30:0x26 //<OEM>:<Set BIOS ID> + 0x30:0x27 //<OEM>:<Get Device Info> + 0x30:0x31 //<OEM>:<Get AIC card FRU> ++0x30:0x54 //<OEM>:<Set Power Restore Delay> ++0x30:0x55 //<OEM>:<Get Power Restore Delay> ++0x30:0x9A //<OEM>:<Get Processor Error Config> ++0x30:0x9B //<OEM>:<Set Processor Error Config> ++0x30:0xB0 //<OEM>:<Get LED Status> ++0x30:0xE9 //<OEM>:<Get BIOS Post Codes> ++ diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0053-Fix-keep-looping-issue-when-entering-OS.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0053-Fix-keep-looping-issue-when-entering-OS.patch new file mode 100644 index 000000000..2a4cc9bb1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0053-Fix-keep-looping-issue-when-entering-OS.patch @@ -0,0 +1,80 @@ +From 9ed3fd11047f8c360b7d808946939ef280813811 Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@linux.intel.com> +Date: Wed, 23 Jan 2019 17:02:40 +0800 +Subject: [PATCH] Fix keep looping issue when entering OS + +Sometimes when entering OS, OS will keep continuously sending ipmi command +"READ EVENT MESSAGE BUFFER" to BMC. This issue is caused by incorrect KCS +status. If restart the host immediately while OS is still running, SMS_ATN +will be set, after that KCS come into an incorrect status, and then KCS +communction between BMC and OS crash. To make KCS go back to correct status +and fix the issue, clear SMS_ATN after every time power cycle happen. + +Unit Test: + After entered OS, force reset system, after enter OS again, OS can start +normally without keep sending READ EVENT MESSAGE BUFFER command. + After power on system, enter EFI SHELL, check cmdtool.efi can work +correctly through KCS channel. +--- + host-cmd-manager.cpp | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/host-cmd-manager.cpp b/host-cmd-manager.cpp +index 0a61e63..6e50684 100644 +--- a/host-cmd-manager.cpp ++++ b/host-cmd-manager.cpp +@@ -26,6 +26,8 @@ constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper"; + constexpr auto HOST_STATE_PATH = "/xyz/openbmc_project/state/host0"; + constexpr auto HOST_STATE_INTERFACE = "xyz.openbmc_project.State.Host"; + constexpr auto HOST_TRANS_PROP = "RequestedHostTransition"; ++constexpr const char* IPMI_PATH = "/org/openbmc/HostIpmi/1"; ++constexpr const char* IPMI_INTERFACE = "org.openbmc.HostIpmi"; + + // For throwing exceptions + using namespace phosphor::logging; +@@ -107,6 +109,20 @@ void Manager::clearQueue() + // `false` indicating Failure + std::get<CallBack>(command)(ipmiCmdData, false); + } ++ ++ auto host = ::ipmi::getService(this->bus, IPMI_INTERFACE, IPMI_PATH); ++ auto method = this->bus.new_method_call(host.c_str(), IPMI_PATH, ++ IPMI_INTERFACE, "clearAttention"); ++ ++ try ++ { ++ auto reply = this->bus.call(method); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ log<level::ERR>("Error in clearing SMS attention"); ++ elog<InternalFailure>(); ++ } + } + + // Called for alerting the host +@@ -116,9 +132,6 @@ void Manager::checkQueueAndAlertHost() + { + log<level::DEBUG>("Asserting SMS Attention"); + +- std::string IPMI_PATH("/org/openbmc/HostIpmi/1"); +- std::string IPMI_INTERFACE("org.openbmc.HostIpmi"); +- + auto host = ::ipmi::getService(this->bus, IPMI_INTERFACE, IPMI_PATH); + + // Start the timer for this transaction +@@ -132,9 +145,8 @@ void Manager::checkQueueAndAlertHost() + return; + } + +- auto method = +- this->bus.new_method_call(host.c_str(), IPMI_PATH.c_str(), +- IPMI_INTERFACE.c_str(), "setAttention"); ++ auto method = this->bus.new_method_call(host.c_str(), IPMI_PATH, ++ IPMI_INTERFACE, "setAttention"); + auto reply = this->bus.call(method); + + if (reply.is_method_error()) +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0054-Fix-User-commands-require-channel-layer-lib.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0054-Fix-User-commands-require-channel-layer-lib.patch new file mode 100644 index 000000000..bf6f672cf --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0054-Fix-User-commands-require-channel-layer-lib.patch @@ -0,0 +1,37 @@ +From 5d0c9d2217dbe369daffb8a92d7b5e7d7d34d566 Mon Sep 17 00:00:00 2001 +From: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +Date: Sat, 2 Mar 2019 20:08:32 +0530 +Subject: [PATCH] Fix: User commands require channel layer lib + +As channel layer is separated out from user layer lib, it +has to be manually included in libusercommands, as user +command handlers use channel layer API's + +Tested-by: +1. Made sure that libusercommands are loaded on it's own +without any undefined symbol error. +2. ipmitool user list 1 works on host interface + +Change-Id: I6652ad248e01afc1349e3a9612754dbdb84b96ad +Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +--- + Makefile.am | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/Makefile.am b/Makefile.am +index bb7bdbf..4e9101e 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -120,7 +120,8 @@ libipmi20_la_CXXFLAGS = $(COMMON_CXX) + providers_LTLIBRARIES += libusercmds.la + libusercmds_la_LIBADD = \ + libipmid/libipmid.la \ +- user_channel/libuserlayer.la ++ user_channel/libuserlayer.la \ ++ user_channel/libchannellayer.la + libusercmds_la_SOURCES = \ + user_channel/usercommands.cpp + libusercmds_la_LDFLAGS = \ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0055-Implement-set-front-panel-button-enables-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0055-Implement-set-front-panel-button-enables-command.patch new file mode 100644 index 000000000..170e530f9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0055-Implement-set-front-panel-button-enables-command.patch @@ -0,0 +1,185 @@ +From b8b88a5c0f9e9cb6023cb8d5453e5cfadaa1a375 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Fri, 4 Jan 2019 10:50:21 +0800 +Subject: [PATCH] Implement set front panel button enables command + +Through modify buttons' property "Enabled" to disable/enable +corresponding button. +Currently support power and reset button. + +Test-By: ipmitool raw 0x0 0xa 0x2 //disable reset button + ipmitool raw 0x0 0xa 0x1 //disable power button + ipmitool raw 0x0 0xa 0x0 //enable all buttons + +Change-Id: Ice6f58edb898689f7a7fa08ad078d25fccaab27e +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + chassishandler.cpp | 98 +++++++++++++++++++++++++++++++++++++++ + chassishandler.hpp | 1 + + host-ipmid-whitelist.conf | 1 + + 3 files changed, 100 insertions(+) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 4b42b3c..1a5b805 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -112,6 +112,8 @@ const static constexpr char chassisSMDevAddrProp[] = "SMDeviceAddress"; + const static constexpr char chassisBridgeDevAddrProp[] = "BridgeDeviceAddress"; + static constexpr uint8_t chassisCapFlagMask = 0x0f; + static constexpr uint8_t chassisCapAddrMask = 0xfe; ++static constexpr uint8_t disableResetButton = 0x2; ++static constexpr uint8_t disablePowerButton = 0x1; + + typedef struct + { +@@ -140,6 +142,19 @@ struct GetPOHCountResponse + uint8_t counterReading[4]; ///< Counter reading + } __attribute__((packed)); + ++typedef struct ++{ ++ uint8_t disables; // Front Panel Button Enables ++ //[7:4] - reserved ++ //[3] - 1b = disable Standby (sleep) button for entering standby (sleep) ++ //(control can still be used to wake the system) ++ //[2] - 1b = disable Diagnostic Interrupt button ++ //[1] - 1b = disable Reset button ++ //[0] - 1b = disable Power off button for power off only (in the case there ++ // is a single combined power/standby (sleep) button, then this also ++ // disables sleep requests via that button) ++} __attribute__((packed)) IPMISetFrontPanelButtonEnablesReq; ++ + // Phosphor Host State manager + namespace State = sdbusplus::xyz::openbmc_project::State::server; + +@@ -948,6 +963,8 @@ ipmi_ret_t ipmi_get_chassis_status(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + // Front Panel Button Capabilities and disable/enable status(Optional) + // set to 0, for we don't support them. ++ // TODO, it is tracked by an issue: ++ // https://github.com/openbmc/phosphor-host-ipmid/issues/122 + chassis_status.front_panel_button_cap_status = 0; + + // Pack the actual response +@@ -1721,6 +1738,82 @@ ipmi_ret_t ipmi_chassis_set_power_restore_policy( + return IPMI_CC_OK; + } + ++ipmi_ret_t ipmiSetFrontPanelButtonEnables(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ++ ipmi_request_t request, ++ ipmi_response_t response, ++ ipmi_data_len_t data_len, ++ ipmi_context_t context) ++{ ++ bool enable = false; ++ constexpr const char* powerButtonIntf = ++ "xyz.openbmc_project.Chassis.Buttons.Power"; ++ constexpr const char* powerButtonPath = ++ "/xyz/openbmc_project/Chassis/Buttons/Power0"; ++ constexpr const char* resetButtonIntf = ++ "xyz.openbmc_project.Chassis.Buttons.Reset"; ++ constexpr const char* resetButtonPath = ++ "/xyz/openbmc_project/Chassis/Buttons/Reset0"; ++ using namespace chassis::internal; ++ ++ IPMISetFrontPanelButtonEnablesReq* req = ++ static_cast<IPMISetFrontPanelButtonEnablesReq*>(request); ++ if (*data_len != 1) ++ { ++ *data_len = 0; ++ log<level::ERR>("IPMI request len is invalid"); ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ *data_len = 0; ++ if (req->disables & disablePowerButton) ++ { ++ // Disable power button ++ enable = false; ++ } ++ else ++ { ++ // Enable power button ++ enable = true; ++ } ++ // set power button Enabled property ++ try ++ { ++ auto service = ipmi::getService(dbus, powerButtonIntf, powerButtonPath); ++ ipmi::setDbusProperty(dbus, service, powerButtonPath, powerButtonIntf, ++ "Enabled", enable); ++ } ++ catch (sdbusplus::exception::SdBusError& e) ++ { ++ log<level::ERR>(e.what()); ++ log<level::ERR>("Fail to set power button Enabled property"); ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ ++ if (req->disables & disableResetButton) ++ { ++ // disable reset button ++ enable = false; ++ } ++ else ++ { ++ // enable reset button ++ enable = true; ++ } ++ // set reset button Enabled property ++ try ++ { ++ auto service = ipmi::getService(dbus, resetButtonIntf, resetButtonPath); ++ ipmi::setDbusProperty(dbus, service, resetButtonPath, resetButtonIntf, ++ "Enabled", enable); ++ } ++ catch (sdbusplus::exception::SdBusError& e) ++ { ++ log<level::ERR>(e.what()); ++ log<level::ERR>("Fail to set reset button Enabled property"); ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ return IPMI_CC_OK; ++} ++ + void register_netfn_chassis_functions() + { + createIdentifyTimer(); +@@ -1733,6 +1826,11 @@ void register_netfn_chassis_functions() + ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_CHASSIS_CAP, NULL, + ipmi_get_chassis_cap, PRIVILEGE_USER); + ++ // Set Front Panel Button Enables ++ ipmi_register_callback(NETFUN_CHASSIS, ++ IPMI_CMD_SET_FRONT_PANEL_BUTTON_ENABLES, NULL, ++ ipmiSetFrontPanelButtonEnables, PRIVILEGE_ADMIN); ++ + // Set Chassis Capabilities + ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_SET_CHASSIS_CAP, NULL, + ipmi_set_chassis_cap, PRIVILEGE_USER); +diff --git a/chassishandler.hpp b/chassishandler.hpp +index 49b5ef8..f4a6bff 100644 +--- a/chassishandler.hpp ++++ b/chassishandler.hpp +@@ -19,6 +19,7 @@ enum ipmi_netfn_chassis_cmds + // Get capability bits + IPMI_CMD_SET_SYS_BOOT_OPTIONS = 0x08, + IPMI_CMD_GET_SYS_BOOT_OPTIONS = 0x09, ++ IPMI_CMD_SET_FRONT_PANEL_BUTTON_ENABLES = 0x0A, + IPMI_CMD_GET_POH_COUNTER = 0x0F, + }; + +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index e5cd0b5..d96d9ed 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -6,6 +6,7 @@ + 0x00:0x06 //<Chassis>:<Set Power Restore Policy> + 0x00:0x08 //<Chassis>:<Set System Boot Options> + 0x00:0x09 //<Chassis>:<Get System Boot Options> ++0x00:0x0A //<Chassis>:<Set Front Panel Button Enables> + 0x00:0x0F //<Chassis>:<Get POH Counter Command> + 0x04:0x2D //<Sensor/Event>:<Get Sensor Reading> + 0x04:0x2F //<Sensor/Event>:<Get Sensor Type> +-- +2.19.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch new file mode 100644 index 000000000..3a77887a0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch @@ -0,0 +1,102 @@ +From 949db3a985719335d3df77db368eb2b296756749 Mon Sep 17 00:00:00 2001 +From: "Jia, chunhui" <chunhui.jia@linux.intel.com> +Date: Tue, 19 Mar 2019 16:09:06 +0800 +Subject: [PATCH] add SetInProgress to get/set boot option cmd + +It is required by BIOS. BIOS will check setinprogress first. +If this flag is not supported, BIOS will bypass all boot +option flow. + +Change-Id: Ibb0501ea5bc36c4f1f72339efef03724dd4e613f +Signed-off-by: Jia, chunhui <chunhui.jia@linux.intel.com> +--- + chassishandler.cpp | 26 +++++++++++++++++++++++++- + chassishandler.hpp | 3 +++ + 2 files changed, 28 insertions(+), 1 deletion(-) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 6d14d1b..553afa8 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -1351,6 +1351,10 @@ static ipmi_ret_t setBootMode(const Mode::Modes& mode) + return IPMI_CC_OK; + } + ++static constexpr uint8_t setComplete = 0x0; ++static constexpr uint8_t setInProgress = 0x1; ++static uint8_t transferStatus = setComplete; ++ + ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_request_t request, + ipmi_response_t response, +@@ -1365,11 +1369,21 @@ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + get_sys_boot_options_t* reqptr = (get_sys_boot_options_t*)request; + IpmiValue bootOption = ipmiDefault; + ++ if (reqptr->parameter == ++ static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS)) ++ { ++ *data_len = ++ static_cast<uint8_t>(BootOptionResponseSize::SET_IN_PROGRESS); ++ resp->version = SET_PARM_VERSION; ++ resp->parm = static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS); ++ resp->data[0] = transferStatus; ++ return IPMI_CC_OK; ++ } ++ + std::memset(resp, 0, sizeof(*resp)); + resp->version = SET_PARM_VERSION; + resp->parm = 5; + resp->data[0] = SET_PARM_BOOT_FLAGS_VALID_ONE_TIME; +- + /* + * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc. + * This is the only parameter used by petitboot. +@@ -1505,6 +1519,16 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + // This IPMI command does not have any resposne data + *data_len = 0; + ++ if (reqptr->parameter == ++ static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS)) ++ { ++ if (transferStatus == setInProgress) { ++ return IPMI_CC_FAIL_SET_IN_PROGRESS; ++ } ++ transferStatus = reqptr->data[0]; ++ return IPMI_CC_OK; ++ } ++ + /* 000101 + * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc. + * This is the only parameter used by petitboot. +diff --git a/chassishandler.hpp b/chassishandler.hpp +index 2c42b11..6a24507 100644 +--- a/chassishandler.hpp ++++ b/chassishandler.hpp +@@ -28,6 +28,7 @@ enum ipmi_chassis_return_codes + { + IPMI_OK = 0x0, + IPMI_CC_PARM_NOT_SUPPORTED = 0x80, ++ IPMI_CC_FAIL_SET_IN_PROGRESS = 0x81, + }; + + // Generic completion codes, +@@ -49,6 +50,7 @@ enum ipmi_chassis_control_cmds : uint8_t + }; + enum class BootOptionParameter : size_t + { ++ SET_IN_PROGRESS = 0x0, + BOOT_INFO = 0x4, + BOOT_FLAGS = 0x5, + OPAL_NETWORK_SETTINGS = 0x61 +@@ -56,6 +58,7 @@ enum class BootOptionParameter : size_t + + enum class BootOptionResponseSize : size_t + { ++ SET_IN_PROGRESS = 3, + BOOT_FLAGS = 5, + OPAL_NETWORK_SETTINGS = 50 + }; +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0057-Add-timer-use-actions-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0057-Add-timer-use-actions-support.patch new file mode 100644 index 000000000..5813cceae --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0057-Add-timer-use-actions-support.patch @@ -0,0 +1,195 @@ +From 6e37e02a4f200507627a82f6dba00a9c9d877cb2 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Mon, 18 Mar 2019 23:05:16 +0800 +Subject: [PATCH] Add timer use/actions support + +Based on IPMI spec, add timer use/actions support, +and add input data checking + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + app/watchdog.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++----- + app/watchdog_service.cpp | 8 +++++++ + app/watchdog_service.hpp | 8 +++++++ + 3 files changed, 72 insertions(+), 6 deletions(-) + +diff --git a/app/watchdog.cpp b/app/watchdog.cpp +index 1a5d19c..3b61055 100644 +--- a/app/watchdog.cpp ++++ b/app/watchdog.cpp +@@ -89,6 +89,13 @@ static constexpr uint8_t wd_dont_stop = 0x1 << 6; + static constexpr uint8_t wd_timeout_action_mask = 0x3; + + static constexpr uint8_t wdTimerUseMask = 0x7; ++static constexpr uint8_t wdTimerUseResTimer1 = 0x0; ++static constexpr uint8_t wdTimerUseResTimer2 = 0x6; ++static constexpr uint8_t wdTimerUseResTimer3 = 0x7; ++static constexpr uint8_t wdTimerUseRes = 0x38; ++ ++static constexpr uint8_t wdTimerActionMask = 0xcc; ++static constexpr uint8_t wdTimerUseExpMask = 0xc1; + + enum class IpmiAction : uint8_t + { +@@ -186,6 +193,11 @@ static_assert(sizeof(wd_set_req) == 6, "wd_set_req has invalid size."); + static_assert(sizeof(wd_set_req) <= MAX_IPMI_BUFFER, + "wd_get_res can't fit in request buffer."); + ++static uint8_t timerLogFlags = 0; ++static uint8_t timerActions = 0; ++ ++static uint8_t timerUseExpirationFlags = 0; ++ + ipmi_ret_t ipmi_app_watchdog_set(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_request_t request, + ipmi_response_t response, +@@ -203,6 +215,24 @@ ipmi_ret_t ipmi_app_watchdog_set(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + req.initial_countdown = le16toh(req.initial_countdown); + *data_len = 0; + ++ if (((req.timer_use & wdTimerUseMask) == wdTimerUseResTimer1) || ++ ((req.timer_use & wdTimerUseMask) == wdTimerUseResTimer2) || ++ ((req.timer_use & wdTimerUseMask) == wdTimerUseResTimer3) || ++ (req.timer_use & wdTimerUseRes) || ++ (req.timer_action & wdTimerActionMask) || ++ (req.expire_flags & wdTimerUseExpMask)) ++ { ++ return IPMI_CC_INVALID_FIELD_REQUEST; ++ } ++ ++ if (req.pretimeout > (req.initial_countdown / 10)) ++ { ++ return IPMI_CC_INVALID_FIELD_REQUEST; ++ } ++ ++ timerLogFlags = req.timer_use & 0x80; ++ timerActions = req.timer_action; ++ + try + { + WatchdogService wd_service; +@@ -221,6 +251,10 @@ ipmi_ret_t ipmi_app_watchdog_set(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + static_cast<IpmiTimerUse>(req.timer_use & wdTimerUseMask); + wd_service.setTimerUse(ipmiTimerUseToWdTimerUse(ipmiTimerUse)); + ++ wd_service.setExpiredTimerUse(WatchdogService::TimerUse::Reserved); ++ ++ timerUseExpirationFlags &= ~req.expire_flags; ++ + // Set the new interval and the time remaining deci -> mill seconds + const uint64_t interval = req.initial_countdown * 100; + wd_service.setInterval(interval); +@@ -339,7 +373,6 @@ static_assert(sizeof(wd_get_res) == 8, "wd_get_res has invalid size."); + static_assert(sizeof(wd_get_res) <= MAX_IPMI_BUFFER, + "wd_get_res can't fit in response buffer."); + +-static constexpr uint8_t wd_dont_log = 0x1 << 7; + static constexpr uint8_t wd_running = 0x1 << 6; + + ipmi_ret_t ipmi_app_watchdog_get(ipmi_netfn_t netfn, ipmi_cmd_t cmd, +@@ -358,20 +391,37 @@ ipmi_ret_t ipmi_app_watchdog_get(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + // Build and return the response + wd_get_res res; +- res.timer_use = wd_dont_log; +- res.timer_action = +- static_cast<uint8_t>(wdActionToIpmiAction(wd_prop.expireAction)); ++ res.timer_use |= timerLogFlags; ++ res.timer_action = timerActions; + + // Interval and timeRemaining need converted from milli -> deci seconds + res.initial_countdown = htole16(wd_prop.interval / 100); ++ ++ if (wd_prop.expiredTimerUse != WatchdogService::TimerUse::Reserved) ++ { ++ timerUseExpirationFlags |= ++ 1 << static_cast<uint8_t>( ++ wdTimerUseToIpmiTimerUse(wd_prop.expiredTimerUse)); ++ } ++ + if (wd_prop.enabled) + { + res.timer_use |= wd_running; + res.present_countdown = htole16(wd_prop.timeRemaining / 100); ++ res.expire_flags = 0; + } + else + { +- res.present_countdown = res.initial_countdown; ++ if (wd_prop.expiredTimerUse == WatchdogService::TimerUse::Reserved) ++ { ++ res.present_countdown = res.initial_countdown; ++ res.expire_flags = 0; ++ } ++ else ++ { ++ res.present_countdown = 0; ++ res.expire_flags = timerUseExpirationFlags; ++ } + } + + res.timer_use |= +@@ -379,7 +429,7 @@ ipmi_ret_t ipmi_app_watchdog_get(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + // TODO: Do something about having pretimeout support + res.pretimeout = 0; +- res.expire_flags = 0; ++ + memcpy(response, &res, sizeof(res)); + *data_len = sizeof(res); + lastCallSuccessful = true; +diff --git a/app/watchdog_service.cpp b/app/watchdog_service.cpp +index e65ea63..8b1aa47 100644 +--- a/app/watchdog_service.cpp ++++ b/app/watchdog_service.cpp +@@ -83,6 +83,9 @@ WatchdogService::Properties WatchdogService::getProperties() + wd_prop.timerUse = Watchdog::convertTimerUseFromString( + get<std::string>(properties.at("CurrentTimerUse"))); + ++ wd_prop.expiredTimerUse = Watchdog::convertTimerUseFromString( ++ get<std::string>(properties.at("ExpiredTimerUse"))); ++ + wd_prop.interval = get<uint64_t>(properties.at("Interval")); + wd_prop.timeRemaining = get<uint64_t>(properties.at("TimeRemaining")); + return wd_prop; +@@ -187,6 +190,11 @@ void WatchdogService::setTimerUse(TimerUse timerUse) + setProperty("CurrentTimerUse", convertForMessage(timerUse)); + } + ++void WatchdogService::setExpiredTimerUse(TimerUse timerUse) ++{ ++ setProperty("ExpiredTimerUse", convertForMessage(timerUse)); ++} ++ + void WatchdogService::setInterval(uint64_t interval) + { + setProperty("Interval", interval); +diff --git a/app/watchdog_service.hpp b/app/watchdog_service.hpp +index 75afc1e..d0cc1a8 100644 +--- a/app/watchdog_service.hpp ++++ b/app/watchdog_service.hpp +@@ -36,6 +36,7 @@ class WatchdogService + bool enabled; + Action expireAction; + TimerUse timerUse; ++ TimerUse expiredTimerUse; + uint64_t interval; + uint64_t timeRemaining; + }; +@@ -79,6 +80,13 @@ class WatchdogService + */ + void setTimerUse(TimerUse timerUse); + ++ /** @brief Sets the value of the ExpiredTimerUse property on the host ++ * watchdog ++ * ++ * @param[in] timerUse - The new timerUse value ++ */ ++ void setExpiredTimerUse(TimerUse timerUse); ++ + /** @brief Sets the value of the interval property on the host watchdog + * + * @param[in] interval - The new interval value +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0058-Add-AC-failed-bit-support-for-get-chassis-status-com.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0058-Add-AC-failed-bit-support-for-get-chassis-status-com.patch new file mode 100644 index 000000000..42bb682c4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0058-Add-AC-failed-bit-support-for-get-chassis-status-com.patch @@ -0,0 +1,76 @@ +From f51bef8f7c5785405ee5c83a921efb1bc05e4947 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Wed, 27 Mar 2019 16:11:25 +0800 +Subject: [PATCH] =?UTF-8?q?Add=20=E2=80=9CAC=20failed=E2=80=9D=20bit=20sup?= + =?UTF-8?q?port=20for=20get=20chassis=20status=20command?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +PFail property is provided by power control service, +ture means the booting is from AC loss. + +Tested: +Remove the AC cable and reconnect it +Ipmitool chassis status to check the status: +Last Power Event : ac-failed + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + chassishandler.cpp | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 7a522ad..40d2018 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -844,6 +844,7 @@ ipmi_ret_t ipmi_get_chassis_status(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + sd_bus_message* reply = NULL; + int r = 0; + int pgood = 0; ++ bool pFail = true; + char* busname = NULL; + ipmi_ret_t rc = IPMI_CC_OK; + ipmi_get_chassis_status_t chassis_status{}; +@@ -904,6 +905,26 @@ ipmi_ret_t ipmi_get_chassis_status(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + goto finish; + } + ++ r = sd_bus_get_property(bus, busname, objname, intf, "PFail", NULL, &reply, ++ "b"); ++ if (r < 0) ++ { ++ log<level::ERR>("Failed to call sd_bus_get_property", ++ entry("PROPERTY=%s", "PFail"), entry("ERRNO=0x%X", -r), ++ entry("BUS=%s", busname), entry("PATH=%s", objname), ++ entry("INTERFACE=%s", intf)); ++ rc = IPMI_CC_UNSPECIFIED_ERROR; ++ goto finish; ++ } ++ ++ r = sd_bus_message_read(reply, "b", &pFail); ++ if (r < 0) ++ { ++ log<level::ERR>("Failed to read PFail:", entry("ERRNO=0x%X", -r)); ++ rc = IPMI_CC_UNSPECIFIED_ERROR; ++ goto finish; ++ } ++ + s = dbusToIpmi.at(powerRestore); + + // Current Power State +@@ -952,6 +973,11 @@ ipmi_ret_t ipmi_get_chassis_status(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + chassis_status.last_power_event = 0; + ++ if (pFail) ++ { ++ chassis_status.last_power_event |= 1; ++ } ++ + // Misc. Chassis State + // [7] – reserved + // [6] – 1b = Chassis Identify command and state info supported (Optional) +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch new file mode 100644 index 000000000..1dc55e2f4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch @@ -0,0 +1,415 @@ +From 1c15df9d82254286d0773086836767f23711c5d9 Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Tue, 2 Apr 2019 00:34:34 +0800 +Subject: [PATCH] Move Set SOL config parameter to host-ipmid + +Move Set SOL config parameter command from net-ipmid to host-ipmid, +so that BIOS in Intel platform can enable or disable SOL through KCS. +Get SOL config parameter command will be moved later. + +Tested by: +With the related change in phospher-ipmi-net and phospher-dbus-interface, +Run commands: +ipmitool raw 0x0c 0x21 0x0e 0x00 0x01 +ipmitool raw 0x0c 0x21 0x0e 0x01 0x00 +ipmitool raw 0x0c 0x21 0x0e 0x02 0x03 +ipmitool raw 0x0c 0x21 0x0e 0x03 0x5 0x03 +ipmitool raw 0x0c 0x21 0x0e 0x04 0x5 0x03 +All these commands have correct response and all dbus interface for +sol command change to same value in above commands. +After reboot BMC, "Progress" property in dbus interface change back +to 0 and other properties will not reset to default value. + +Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com> +--- + host-ipmid-whitelist.conf | 1 + + include/ipmid/api.h | 1 + + transporthandler.cpp | 222 ++++++++++++++++++++++++++++++++++++++ + transporthandler.hpp | 97 +++++++++++++++++ + 4 files changed, 321 insertions(+) + +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index 2a83347..544b766 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -41,6 +41,7 @@ + 0x0A:0x48 //<Storage>:<Get SEL Time> + 0x0A:0x49 //<Storage>:<Set SEL Time> + 0x0C:0x02 //<Transport>:<Get LAN Configuration Parameters> ++0x0C:0x21 //<Transport>:<Set SOL Configuration Parameters> + 0x2C:0x00 //<Group Extension>:<Group Extension Command> + 0x2C:0x01 //<Group Extension>:<Get DCMI Capabilities> + 0x2C:0x02 //<Group Extension>:<Get Power Reading> +diff --git a/include/ipmid/api.h b/include/ipmid/api.h +index f08ee11..2f366b4 100644 +--- a/include/ipmid/api.h ++++ b/include/ipmid/api.h +@@ -113,6 +113,7 @@ enum ipmi_return_codes + IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT = 0x80, + IPMI_WDOG_CC_NOT_INIT = 0x80, + IPMI_CC_SYSTEM_INFO_PARAMETER_NOT_SUPPORTED = 0x80, ++ IPMI_CC_SET_IN_PROGRESS_ACTIVE = 0x81, + IPMI_CC_SYSTEM_INFO_PARAMETER_SET_READ_ONLY = 0x82, + IPMI_CC_BUSY = 0xC0, + IPMI_CC_INVALID = 0xC1, +diff --git a/transporthandler.cpp b/transporthandler.cpp +index 8f18b76..a693279 100644 +--- a/transporthandler.cpp ++++ b/transporthandler.cpp +@@ -36,6 +36,9 @@ static const std::array<std::string, 3> ipAddressEnablesType = { + "xyz.openbmc_project.Network.EthernetInterface.IPAllowed.IPv6Only", + "xyz.openbmc_project.Network.EthernetInterface.IPAllowed.IPv4AndIPv6"}; + ++constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL"; ++constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol"; ++ + std::map<int, std::unique_ptr<struct ChannelConfig_t>> channelConfig; + + using namespace phosphor::logging; +@@ -1633,6 +1636,219 @@ void createNetworkTimer() + } + } + ++static int setSOLParameter(std::string property, const ipmi::Value& value) ++{ ++ auto dbus = getSdBus(); ++ ++ static std::string solService{}; ++ if (solService.empty()) ++ { ++ try ++ { ++ solService = ipmi::getService(*dbus, solInterface, solPath); ++ } ++ catch (const sdbusplus::exception::SdBusError& e) ++ { ++ solService.clear(); ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error: get SOL service failed"); ++ return -1; ++ } ++ } ++ try ++ { ++ ipmi::setDbusProperty(*dbus, solService, solPath, solInterface, ++ property, value); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error setting sol parameter"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int getSOLParameter(std::string property, ipmi::Value& value) ++{ ++ auto dbus = getSdBus(); ++ ++ static std::string solService{}; ++ if (solService.empty()) ++ { ++ try ++ { ++ solService = ipmi::getService(*dbus, solInterface, solPath); ++ } ++ catch (const sdbusplus::exception::SdBusError& e) ++ { ++ solService.clear(); ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error: get SOL service failed"); ++ return -1; ++ } ++ } ++ try ++ { ++ value = ipmi::getDbusProperty(*dbus, solService, solPath, solInterface, ++ property); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error getting sol parameter"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++void initializeSOLInProgress() ++{ ++ if (setSOLParameter("Progress", static_cast<uint8_t>(0)) < 0) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error initialize sol progress"); ++ } ++} ++ ++ipmi_ret_t setConfParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ++ ipmi_request_t request, ipmi_response_t response, ++ ipmi_data_len_t dataLen, ipmi_context_t context) ++{ ++ auto reqData = reinterpret_cast<const SetConfParamsRequest*>(request); ++ ++ // Check request length first ++ switch (static_cast<sol::Parameter>(reqData->paramSelector)) ++ { ++ case sol::Parameter::progress: ++ case sol::Parameter::enable: ++ case sol::Parameter::authentication: ++ { ++ if (*dataLen != sizeof(SetConfParamsRequest) - 1) ++ { ++ *dataLen = 0; ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ break; ++ } ++ case sol::Parameter::accumulate: ++ case sol::Parameter::retry: ++ { ++ if (*dataLen != sizeof(SetConfParamsRequest)) ++ { ++ *dataLen = 0; ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ break; ++ } ++ default: ++ break; ++ } ++ ++ *dataLen = 0; ++ ++ switch (static_cast<sol::Parameter>(reqData->paramSelector)) ++ { ++ case sol::Parameter::progress: ++ { ++ uint8_t progress = reqData->value & progressMask; ++ ipmi::Value currentProgress = 0; ++ if (getSOLParameter("Progress", currentProgress) < 0) ++ { ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ ++ if ((std::get<uint8_t>(currentProgress) == 1) && (progress == 1)) ++ { ++ return IPMI_CC_SET_IN_PROGRESS_ACTIVE; ++ } ++ ++ if (setSOLParameter("Progress", progress) < 0) ++ { ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ break; ++ } ++ case sol::Parameter::enable: ++ { ++ bool enable = reqData->value & enableMask; ++ if (setSOLParameter("Enable", enable) < 0) ++ { ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ break; ++ } ++ case sol::Parameter::authentication: ++ { ++ // if encryption is used authentication must also be used. ++ if (reqData->auth.encrypt && !reqData->auth.auth) ++ { ++ return IPMI_CC_SYSTEM_INFO_PARAMETER_SET_READ_ONLY; ++ } ++ else if (reqData->auth.privilege < ++ static_cast<uint8_t>(sol::Privilege::userPriv) || ++ reqData->auth.privilege > ++ static_cast<uint8_t>(sol::Privilege::oemPriv)) ++ { ++ return IPMI_CC_INVALID_FIELD_REQUEST; ++ } ++ ++ if ((setSOLParameter("Privilege", reqData->auth.privilege) < 0) || ++ (setSOLParameter("ForceEncryption", ++ static_cast<bool>(reqData->auth.encrypt)) < ++ 0) || ++ (setSOLParameter("ForceAuthentication", ++ static_cast<bool>(reqData->auth.auth)) < 0)) ++ { ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ ++ break; ++ } ++ case sol::Parameter::accumulate: ++ { ++ if (reqData->acc.threshold == 0) ++ { ++ return IPMI_CC_INVALID_FIELD_REQUEST; ++ } ++ if (setSOLParameter("AccumulateIntervalMS", reqData->acc.interval) < ++ 0) ++ { ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ if (setSOLParameter("Threshold", reqData->acc.threshold) < 0) ++ { ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ break; ++ } ++ case sol::Parameter::retry: ++ { ++ if ((setSOLParameter("RetryCount", reqData->retry.count) < 0) || ++ (setSOLParameter("RetryIntervalMS", reqData->retry.interval) < ++ 0)) ++ { ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ ++ break; ++ } ++ case sol::Parameter::port: ++ { ++ return IPMI_CC_SYSTEM_INFO_PARAMETER_SET_READ_ONLY; ++ } ++ case sol::Parameter::nvbitrate: ++ case sol::Parameter::vbitrate: ++ case sol::Parameter::channel: ++ default: ++ return IPMI_CC_PARM_NOT_SUPPORTED; ++ } ++ ++ return IPMI_CC_OK; ++} ++ + void register_netfn_transport_functions() + { + // As this timer is only for transport handler +@@ -1650,5 +1866,11 @@ void register_netfn_transport_functions() + ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_GET_LAN, NULL, + ipmi_transport_get_lan, PRIVILEGE_OPERATOR); + ++ ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_SET_SOL_CONF_PARAMS, NULL, ++ setConfParams, PRIVILEGE_ADMIN); ++ ++ // Initialize dbus property progress to 0 every time sol manager restart. ++ initializeSOLInProgress(); ++ + return; + } +diff --git a/transporthandler.hpp b/transporthandler.hpp +index bd23391..3b5e9e1 100644 +--- a/transporthandler.hpp ++++ b/transporthandler.hpp +@@ -8,6 +8,8 @@ enum ipmi_netfn_storage_cmds + // Get capability bits + IPMI_CMD_SET_LAN = 0x01, + IPMI_CMD_GET_LAN = 0x02, ++ IPMI_CMD_SET_SOL_CONF_PARAMS = 0x21, ++ IPMI_CMD_GET_SOL_CONF_PARAMS = 0x22, + }; + + // Command specific completion codes +@@ -186,3 +188,98 @@ void commitNetworkChanges(); + * @param[in] channel: channel number. + */ + void applyChanges(int channel); ++ ++namespace sol ++{ ++enum class Parameter ++{ ++ progress, //!< Set In Progress. ++ enable, //!< SOL Enable. ++ authentication, //!< SOL Authentication. ++ accumulate, //!< Character Accumulate Interval & Send Threshold. ++ retry, //!< SOL Retry. ++ nvbitrate, //!< SOL non-volatile bit rate. ++ vbitrate, //!< SOL volatile bit rate. ++ channel, //!< SOL payload channel. ++ port, //!< SOL payload port. ++}; ++ ++enum class Privilege : uint8_t ++{ ++ highestPriv, ++ callbackPriv, ++ userPriv, ++ operatorPriv, ++ adminPriv, ++ oemPriv, ++}; ++ ++} // namespace sol ++ ++constexpr uint8_t progressMask = 0x03; ++constexpr uint8_t enableMask = 0x01; ++ ++struct Auth ++{ ++#if BYTE_ORDER == LITTLE_ENDIAN ++ uint8_t privilege : 4; //!< SOL privilege level. ++ uint8_t reserved : 2; //!< Reserved. ++ uint8_t auth : 1; //!< Force SOL payload Authentication. ++ uint8_t encrypt : 1; //!< Force SOL payload encryption. ++#endif ++ ++#if BYTE_ORDER == BIG_ENDIAN ++ uint8_t encrypt : 1; //!< Force SOL payload encryption. ++ uint8_t auth : 1; //!< Force SOL payload Authentication. ++ uint8_t reserved : 2; //!< Reserved. ++ uint8_t privilege : 4; //!< SOL privilege level. ++#endif ++} __attribute__((packed)); ++ ++struct Accumulate ++{ ++ uint8_t interval; //!< Character accumulate interval. ++ uint8_t threshold; //!< Character send threshold. ++} __attribute__((packed)); ++ ++struct Retry ++{ ++#if BYTE_ORDER == LITTLE_ENDIAN ++ uint8_t count : 3; //!< SOL retry count. ++ uint8_t reserved : 5; //!< Reserved. ++#endif ++ ++#if BYTE_ORDER == BIG_ENDIAN ++ uint8_t reserved : 5; //!< Reserved. ++ uint8_t count : 3; //!< SOL retry count. ++#endif ++ ++ uint8_t interval; //!< SOL retry interval. ++} __attribute__((packed)); ++ ++struct SetConfParamsRequest ++{ ++#if BYTE_ORDER == LITTLE_ENDIAN ++ uint8_t channelNumber : 4; //!< Channel number. ++ uint8_t reserved : 4; //!< Reserved. ++#endif ++ ++#if BYTE_ORDER == BIG_ENDIAN ++ uint8_t reserved : 4; //!< Reserved. ++ uint8_t channelNumber : 4; //!< Channel number. ++#endif ++ ++ uint8_t paramSelector; //!< Parameter selector. ++ union ++ { ++ uint8_t value; //!< Represents one byte SOL parameters. ++ struct Accumulate acc; //!< Character accumulate values. ++ struct Retry retry; //!< Retry values. ++ struct Auth auth; //!< Authentication parameters. ++ }; ++} __attribute__((packed)); ++ ++struct SetConfParamsResponse ++{ ++ uint8_t completionCode; //!< Completion code. ++} __attribute__((packed)); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch new file mode 100644 index 000000000..49a2c01ba --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch @@ -0,0 +1,248 @@ +From 973865687325c6563fd6b729a3a220661066f635 Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Wed, 3 Apr 2019 15:55:04 +0800 +Subject: [PATCH] Move Get SOL config parameter to host-ipmid + +Move Get SOL config parameter command from net-ipmid to host-ipmid. + +Tested By: +Run command ipmitool sol info +Set in progress : set-complete +Enabled : true +Force Encryption : false +Force Authentication : false +Privilege Level : USER +Character Accumulate Level (ms) : 100 +Character Send Threshold : 1 +Retry Count : 3 +Retry Interval (ms) : 100 +Volatile Bit Rate (kbps) : IPMI-Over-Serial-Setting +Non-Volatile Bit Rate (kbps) : IPMI-Over-Serial-Setting +Payload Channel : 14 (0x0e) +Payload Port : 623 + +Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com> +--- + transporthandler.cpp | 139 ++++++++++++++++++++++++++++++++++++++++++++++++--- + transporthandler.hpp | 26 +++++++++- + 2 files changed, 156 insertions(+), 9 deletions(-) + +diff --git a/transporthandler.cpp b/transporthandler.cpp +index 2111acf..b18f522 100644 +--- a/transporthandler.cpp ++++ b/transporthandler.cpp +@@ -1715,11 +1715,133 @@ void initializeSOLInProgress() + } + } + +-ipmi_ret_t setConfParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd, +- ipmi_request_t request, ipmi_response_t response, +- ipmi_data_len_t dataLen, ipmi_context_t context) ++// For getsetSOLConfParams, there are still three tings TODO: ++// 1. session less channel number request has to return error. ++// 2. convert 0xE channel number. ++// 3. have unique object for every session based channel. ++ipmi_ret_t getSOLConfParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ++ ipmi_request_t request, ipmi_response_t response, ++ ipmi_data_len_t dataLen, ipmi_context_t context) + { +- auto reqData = reinterpret_cast<const SetConfParamsRequest*>(request); ++ auto reqData = reinterpret_cast<const GetSOLConfParamsRequest*>(request); ++ std::vector<uint8_t> outPayload; ++ ++ if (*dataLen < sizeof(GetSOLConfParamsRequest) - 2) ++ { ++ *dataLen = 0; ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ *dataLen = 0; ++ ++ outPayload.push_back(solParameterRevision); ++ if (reqData->getParamRev) ++ { ++ std::copy(outPayload.begin(), outPayload.end(), ++ static_cast<uint8_t*>(response)); ++ *dataLen = outPayload.size(); ++ return IPMI_CC_OK; ++ } ++ ++ ipmi::Value value; ++ switch (static_cast<sol::Parameter>(reqData->paramSelector)) ++ { ++ case sol::Parameter::progress: ++ { ++ if (getSOLParameter("Progress", value) < 0) ++ { ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ outPayload.push_back(std::get<uint8_t>(value)); ++ break; ++ } ++ case sol::Parameter::enable: ++ { ++ if (getSOLParameter("Enable", value) < 0) ++ { ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ outPayload.push_back(static_cast<uint8_t>(std::get<bool>(value))); ++ break; ++ } ++ case sol::Parameter::authentication: ++ { ++ uint8_t authentication = 0; ++ if (getSOLParameter("Privilege", value) < 0) ++ { ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ authentication = (std::get<uint8_t>(value) & 0x0f); ++ ++ if (getSOLParameter("ForceAuthentication", value) < 0) ++ { ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ authentication |= ++ (static_cast<uint8_t>(std::get<bool>(value)) << 6); ++ ++ if (getSOLParameter("ForceEncryption", value) < 0) ++ { ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ authentication |= ++ (static_cast<uint8_t>(std::get<bool>(value)) << 7); ++ outPayload.push_back(authentication); ++ break; ++ } ++ case sol::Parameter::accumulate: ++ { ++ if (getSOLParameter("AccumulateIntervalMS", value) < 0) ++ { ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ outPayload.push_back(std::get<uint8_t>(value)); ++ ++ if (getSOLParameter("Threshold", value) < 0) ++ { ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ outPayload.push_back(std::get<uint8_t>(value)); ++ break; ++ } ++ case sol::Parameter::retry: ++ { ++ if (getSOLParameter("RetryCount", value) < 0) ++ { ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ outPayload.push_back(std::get<uint8_t>(value) & 0x03); ++ ++ if (getSOLParameter("RetryIntervalMS", value) < 0) ++ { ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ outPayload.push_back(std::get<uint8_t>(value)); ++ break; ++ } ++ case sol::Parameter::port: ++ { ++ uint16_t port = htole16(ipmiStdPort); ++ auto buffer = reinterpret_cast<const uint8_t*>(&port); ++ std::copy(buffer, buffer + sizeof(port), ++ std::back_inserter(outPayload)); ++ break; ++ } ++ default: ++ return IPMI_CC_PARM_NOT_SUPPORTED; ++ } ++ std::copy(outPayload.begin(), outPayload.end(), ++ static_cast<uint8_t*>(response)); ++ *dataLen = outPayload.size(); ++ ++ return IPMI_CC_OK; ++} ++ ++ipmi_ret_t setSOLConfParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ++ ipmi_request_t request, ipmi_response_t response, ++ ipmi_data_len_t dataLen, ipmi_context_t context) ++{ ++ auto reqData = reinterpret_cast<const SetSOLConfParamsRequest*>(request); + + // Check request length first + switch (static_cast<sol::Parameter>(reqData->paramSelector)) +@@ -1728,7 +1850,7 @@ ipmi_ret_t setConfParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + case sol::Parameter::enable: + case sol::Parameter::authentication: + { +- if (*dataLen != sizeof(SetConfParamsRequest) - 1) ++ if (*dataLen != sizeof(SetSOLConfParamsRequest) - 1) + { + *dataLen = 0; + return IPMI_CC_REQ_DATA_LEN_INVALID; +@@ -1738,7 +1860,7 @@ ipmi_ret_t setConfParams(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + case sol::Parameter::accumulate: + case sol::Parameter::retry: + { +- if (*dataLen != sizeof(SetConfParamsRequest)) ++ if (*dataLen != sizeof(SetSOLConfParamsRequest)) + { + *dataLen = 0; + return IPMI_CC_REQ_DATA_LEN_INVALID; +@@ -1869,7 +1991,10 @@ void register_netfn_transport_functions() + ipmi_transport_get_lan, PRIVILEGE_OPERATOR); + + ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_SET_SOL_CONF_PARAMS, NULL, +- setConfParams, PRIVILEGE_ADMIN); ++ setSOLConfParams, PRIVILEGE_ADMIN); ++ ++ ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_GET_SOL_CONF_PARAMS, NULL, ++ getSOLConfParams, PRIVILEGE_ADMIN); + + // Initialize dbus property progress to 0 every time sol manager restart. + initializeSOLInProgress(); +diff --git a/transporthandler.hpp b/transporthandler.hpp +index 3b5e9e1..7132cff 100644 +--- a/transporthandler.hpp ++++ b/transporthandler.hpp +@@ -257,7 +257,7 @@ struct Retry + uint8_t interval; //!< SOL retry interval. + } __attribute__((packed)); + +-struct SetConfParamsRequest ++struct SetSOLConfParamsRequest + { + #if BYTE_ORDER == LITTLE_ENDIAN + uint8_t channelNumber : 4; //!< Channel number. +@@ -279,7 +279,29 @@ struct SetConfParamsRequest + }; + } __attribute__((packed)); + +-struct SetConfParamsResponse ++struct SetSOLConfParamsResponse + { + uint8_t completionCode; //!< Completion code. + } __attribute__((packed)); ++ ++struct GetSOLConfParamsRequest ++{ ++#if BYTE_ORDER == LITTLE_ENDIAN ++ uint8_t channelNum : 4; //!< Channel number. ++ uint8_t reserved : 3; //!< Reserved. ++ uint8_t getParamRev : 1; //!< Get parameter or Get parameter revision ++#endif ++ ++#if BYTE_ORDER == BIG_ENDIAN ++ uint8_t getParamRev : 1; //!< Get parameter or Get parameter revision ++ uint8_t reserved : 3; //!< Reserved. ++ uint8_t channelNum : 4; //!< Channel number. ++#endif ++ ++ uint8_t paramSelector; //!< Parameter selector. ++ uint8_t setSelector; //!< Set selector. ++ uint8_t blockSelector; //!< Block selector. ++} __attribute__((packed)); ++ ++static constexpr uint16_t ipmiStdPort = 623; ++static constexpr uint8_t solParameterRevision = 0x11; +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service new file mode 100644 index 000000000..d855eaa5b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service @@ -0,0 +1,26 @@ +[Unit] +Description=Phosphor Inband IPMI +# TODO openbmc/openbmc#2059 - The wants/after below should be based on providers +Wants=mapper-wait@-xyz-openbmc_project-control-host0-boot.service +After=mapper-wait@-xyz-openbmc_project-control-host0-boot.service +Wants=mapper-wait@-xyz-openbmc_project-control-host0-boot-one_time.service +After=mapper-wait@-xyz-openbmc_project-control-host0-boot-one_time.service +Wants=mapper-wait@-xyz-openbmc_project-control-host0-power_restore_policy.service +After=mapper-wait@-xyz-openbmc_project-control-host0-power_restore_policy.service +Wants=mapper-wait@-xyz-openbmc_project-control-host0-restriction_mode.service +After=mapper-wait@-xyz-openbmc_project-control-host0-restriction_mode.service +Wants=clear-once.service +After=clear-once.service + +[Service] +Restart=always +RestartSec=5 +StartLimitBurst=10 +ExecStart=/usr/bin/env ipmid +SyslogIdentifier=ipmid +RuntimeDirectory = ipmi +RuntimeDirectoryPreserve = yes +StateDirectory = ipmi + +[Install] +WantedBy={SYSTEMD_DEFAULT_TARGET} |