Move commands from ipmi-providers

Many commands were in ipmi-providers and need to be moved into the
active development library (intel-ipmi-oem). This copies wholesale
those commands, even though many need to be rewritten to use the new
ipmi providers API.

Tested-by: build and see that the commands are still present even when
           the ipmi-providers library is removed

Change-Id: If326f5d7844adeed7da2d3b7a2f1d3eeeea43b29
Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
diff --git a/src/manufacturingcommands.cpp b/src/manufacturingcommands.cpp
new file mode 100644
index 0000000..7bbb970
--- /dev/null
+++ b/src/manufacturingcommands.cpp
@@ -0,0 +1,628 @@
+/*
+// Copyright (c) 2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <boost/process/child.hpp>
+#include <ipmid/api.hpp>
+#include <manufacturingcommands.hpp>
+#include <oemcommands.hpp>
+
+namespace ipmi
+{
+
+Manufacturing mtm;
+
+static auto revertTimeOut =
+    std::chrono::duration_cast<std::chrono::microseconds>(
+        std::chrono::seconds(60)); // 1 minute timeout
+
+static constexpr const char* idButtonPath =
+    "/xyz/openbmc_project/Chassis/Buttons/ID0";
+static constexpr const char* idButtonInterface =
+    "xyz.openbmc_project.Chassis.Buttons.ID";
+static constexpr const char* idButtonMemberPressed = "Pressed";
+
+static constexpr const char* callbackMgrService =
+    "xyz.openbmc_project.CallbackManager";
+static constexpr const char* callbackMgrIntf =
+    "xyz.openbmc_project.CallbackManager";
+static constexpr const char* callbackMgrObjPath =
+    "/xyz/openbmc_project/CallbackManager";
+static constexpr const char* retriggerLedUpdate = "RetriggerLEDUpdate";
+
+const static constexpr char* systemDService = "org.freedesktop.systemd1";
+const static constexpr char* systemDObjPath = "/org/freedesktop/systemd1";
+const static constexpr char* systemDMgrIntf =
+    "org.freedesktop.systemd1.Manager";
+const static constexpr char* pidControlService = "phosphor-pid-control.service";
+
+// TODO: Temporary place to test the working code. Will be moved to
+// gpio daemon
+constexpr const char* passthroughPath = "/usr/bin/set-passthrough.sh";
+void disablePassthrough(bool value)
+{
+    boost::process::child c(passthroughPath, value ? "0" : "1");
+    c.wait();
+}
+
+ipmi_ret_t ledStoreAndSet(SmSignalSet signal, std::string setState)
+{
+    LedProperty* ledProp = mtm.findLedProperty(signal);
+    if (ledProp == nullptr)
+    {
+        return IPMI_CC_INVALID_FIELD_REQUEST;
+    }
+
+    std::string ledName = ledProp->getName();
+    std::string ledService = ledServicePrefix + ledName;
+    std::string ledPath = ledPathPrefix + ledName;
+    ipmi::Value presentState;
+
+    if (false == ledProp->getLock())
+    {
+        if (mtm.getProperty(ledService.c_str(), ledPath.c_str(), ledIntf,
+                            "State", &presentState) != 0)
+        {
+            return IPMI_CC_UNSPECIFIED_ERROR;
+        }
+        ledProp->setPrevState(std::get<std::string>(presentState));
+        ledProp->setLock(true);
+        if (signal == SmSignalSet::smPowerFaultLed ||
+            signal == SmSignalSet::smSystemReadyLed)
+        {
+            mtm.revertLedCallback = true;
+        }
+    }
+    if (mtm.setProperty(ledService.c_str(), ledPath.c_str(), ledIntf, "State",
+                        ledStateStr + setState) != 0)
+    {
+        return IPMI_CC_UNSPECIFIED_ERROR;
+    }
+    return IPMI_CC_OK;
+}
+
+ipmi_ret_t ledRevert(SmSignalSet signal)
+{
+    LedProperty* ledProp = mtm.findLedProperty(signal);
+    if (ledProp == nullptr)
+    {
+        return IPMI_CC_INVALID_FIELD_REQUEST;
+    }
+    if (true == ledProp->getLock())
+    {
+        ledProp->setLock(false);
+        if (signal == SmSignalSet::smPowerFaultLed ||
+            signal == SmSignalSet::smSystemReadyLed)
+        {
+            try
+            {
+                ipmi::method_no_args::callDbusMethod(
+                    *getSdBus(), callbackMgrService, callbackMgrObjPath,
+                    callbackMgrIntf, retriggerLedUpdate);
+            }
+            catch (sdbusplus::exception_t& e)
+            {
+                return IPMI_CC_UNSPECIFIED_ERROR;
+            }
+            mtm.revertLedCallback = false;
+        }
+        else
+        {
+            std::string ledName = ledProp->getName();
+            std::string ledService = ledServicePrefix + ledName;
+            std::string ledPath = ledPathPrefix + ledName;
+            if (mtm.setProperty(ledService.c_str(), ledPath.c_str(), ledIntf,
+                                "State", ledProp->getPrevState()) != 0)
+            {
+                return IPMI_CC_UNSPECIFIED_ERROR;
+            }
+        }
+    }
+    return IPMI_CC_OK;
+}
+
+void Manufacturing::initData()
+{
+    gpioPaths[(uint8_t)SmSignalGet::smPowerButton] = "Power_Button";
+    gpioPaths[(uint8_t)SmSignalGet::smResetButton] = "Reset_Button";
+    gpioPaths[(uint8_t)SmSignalGet::smIdentifyButton] = "ID_Button";
+    gpioPaths[(uint8_t)SmSignalGet::smFpLcpEnterButton] = "Lcp_Enter_Button";
+    gpioPaths[(uint8_t)SmSignalGet::smFpLcpLeftButton] = "Lcp_Left_Button";
+    gpioPaths[(uint8_t)SmSignalGet::smFpLcpRightButton] = "Lcp_Right_Button";
+    gpioPaths[(uint8_t)SmSignalGet::smNmiButton] = "Nmi_Button";
+
+    ledPropertyList.push_back(
+        LedProperty(SmSignalSet::smPowerFaultLed, "status_amber"));
+    ledPropertyList.push_back(
+        LedProperty(SmSignalSet::smSystemReadyLed, "status_green"));
+    ledPropertyList.push_back(
+        LedProperty(SmSignalSet::smIdentifyLed, "identify"));
+}
+
+void Manufacturing::revertTimerHandler()
+{
+    for (const auto& signal : revertSmSignalGetVector)
+    {
+        mtm.setProperty(gpioService,
+                        mtm.getGpioPathForSmSignal((uint8_t)signal), gpioIntf,
+                        "Ignore", false);
+    }
+    revertSmSignalGetVector.clear();
+    disablePassthrough(false);
+    if (revertFanPWM)
+    {
+        revertFanPWM = false;
+        disablePidControlService(false);
+    }
+
+    for (const auto& ledProperty : ledPropertyList)
+    {
+        const std::string& ledName = ledProperty.getName();
+        ledRevert(ledProperty.getSignal());
+    }
+}
+
+Manufacturing::Manufacturing() :
+    revertTimer([&](void) { revertTimerHandler(); })
+{
+    initData();
+}
+
+int8_t Manufacturing::getProperty(const char* service, std::string path,
+                                  const char* interface,
+                                  std::string propertyName, ipmi::Value* reply)
+{
+    try
+    {
+        *reply = ipmi::getDbusProperty(*getSdBus(), service, path.c_str(),
+                                       interface, propertyName);
+    }
+    catch (const sdbusplus::exception::SdBusError& e)
+    {
+        phosphor::logging::log<phosphor::logging::level::INFO>(
+            "ERROR: getProperty");
+        return -1;
+    }
+
+    return 0;
+}
+
+int8_t Manufacturing::setProperty(const char* service, std::string path,
+                                  const char* interface,
+                                  std::string propertyName, ipmi::Value value)
+{
+    try
+    {
+        ipmi::setDbusProperty(*getSdBus(), service, path.c_str(), interface,
+                              propertyName, value);
+    }
+    catch (const sdbusplus::exception::SdBusError& e)
+    {
+        phosphor::logging::log<phosphor::logging::level::INFO>(
+            "ERROR: setProperty");
+        return -1;
+    }
+
+    return 0;
+}
+
+int8_t Manufacturing::disablePidControlService(const bool disable)
+{
+    try
+    {
+        auto dbus = getSdBus();
+        auto method = dbus->new_method_call(systemDService, systemDObjPath,
+                                            systemDMgrIntf,
+                                            disable ? "StopUnit" : "StartUnit");
+        method.append(pidControlService, "replace");
+        auto reply = dbus->call(method);
+    }
+    catch (const sdbusplus::exception::SdBusError& e)
+    {
+        phosphor::logging::log<phosphor::logging::level::INFO>(
+            "ERROR: phosphor-pid-control service start or stop failed");
+        return -1;
+    }
+    return 0;
+}
+
+std::tuple<uint8_t, ipmi_ret_t, uint8_t>
+    Manufacturing::proccessSignal(SmSignalGet signal, SmActionGet action)
+{
+    int8_t ret = 0;
+    uint8_t retCode = 0;
+    uint8_t dataLen = 0;
+    uint8_t value = 0;
+    ipmi::Value reply;
+
+    switch (action)
+    {
+        case SmActionGet::sample:
+            phosphor::logging::log<phosphor::logging::level::INFO>(
+                "case SmActionGet::sample");
+            break;
+        case SmActionGet::ignore:
+        {
+            phosphor::logging::log<phosphor::logging::level::INFO>(
+                "case SmActionGet::ignore");
+            if (std::find(revertSmSignalGetVector.begin(),
+                          revertSmSignalGetVector.end(),
+                          signal) == revertSmSignalGetVector.end())
+            {
+                // Todo: Needs to be replaced with pass-through of particular
+                // pin
+                disablePassthrough(true);
+                ret = mtm.setProperty(
+                    gpioService, mtm.getGpioPathForSmSignal((uint8_t)signal),
+                    gpioIntf, "Ignore", true);
+                if (ret < 0)
+                {
+                    dataLen = 0;
+                    retCode = IPMI_CC_INVALID_FIELD_REQUEST;
+                }
+                revertSmSignalGetVector.push_back(signal);
+                revertTimer.start(revertTimeOut);
+            }
+        }
+        break;
+        case SmActionGet::revert:
+        {
+            phosphor::logging::log<phosphor::logging::level::INFO>(
+                "case SmActionGet::revert");
+            auto iter = std::find(revertSmSignalGetVector.begin(),
+                                  revertSmSignalGetVector.end(), signal);
+            if (iter != revertSmSignalGetVector.end())
+            {
+                ret = mtm.setProperty(
+                    gpioService, mtm.getGpioPathForSmSignal((uint8_t)signal),
+                    gpioIntf, "Ignore", false);
+                if (ret < 0)
+                {
+                    dataLen = 0;
+                    retCode = IPMI_CC_INVALID_FIELD_REQUEST;
+                }
+                revertSmSignalGetVector.erase(iter);
+                // Todo: Needs to be replaced with pass-through of particular
+                // pin
+                disablePassthrough(true);
+                if (revertSmSignalGetVector.size() == 0)
+                {
+                    revertTimer.stop();
+                }
+            }
+        }
+        break;
+
+        default:
+            dataLen = 0;
+            retCode = IPMI_CC_INVALID_FIELD_REQUEST;
+            break;
+    }
+
+    if (ret == 0) // No error happend, cmd will return with gpio value
+    {
+        ret = mtm.getProperty(gpioService,
+                              mtm.getGpioPathForSmSignal((uint8_t)signal),
+                              gpioIntf, "SampledValue", &reply);
+        if (ret < 0)
+        {
+            dataLen = 0;
+            retCode = IPMI_CC_INVALID_FIELD_REQUEST;
+        }
+        else
+        {
+            dataLen = 1;
+            value = std::get<bool>(reply);
+        }
+    }
+
+    return std::make_tuple(dataLen, retCode, value);
+}
+
+ipmi_ret_t ipmi_app_mtm_get_signal(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 retCode = IPMI_CC_OK;
+    int8_t ret = 0;
+    GetSmSignalReq* pReq = NULL;
+    GetSmSignalRsp* pRsp = NULL;
+
+    pReq = static_cast<GetSmSignalReq*>(request);
+    pRsp = static_cast<GetSmSignalRsp*>(response);
+
+    ipmi::Value reply;
+
+    if ((*data_len == sizeof(*pReq)) &&
+        (mtm.getAccessLvl() >= MtmLvl::mtmAvailable))
+    {
+        switch (pReq->Signal)
+        {
+            case SmSignalGet::smFanPwmGet:
+            {
+                std::string fullPath =
+                    fanPwmPath + std::to_string(pReq->Instance);
+                ret = mtm.getProperty(fanService, fullPath, fanIntf, "Value",
+                                      &reply);
+                if (ret < 0)
+                {
+                    *data_len = 0;
+                    retCode = IPMI_CC_INVALID_FIELD_REQUEST;
+                    break;
+                }
+                *data_len = 1;
+                pRsp->SigVal = std::get<double>(reply);
+            }
+            break;
+            case SmSignalGet::smFanTachometerGet:
+            {
+                // Full path calculation pattern:
+                // Instance 1 path is
+                // /xyz/openbmc_project/sensors/fan_tach/Fan_1a Instance 2 path
+                // is /xyz/openbmc_project/sensors/fan_tach/Fan_1b Instance 3
+                // path is /xyz/openbmc_project/sensors/fan_tach/Fan_2a
+                // and so on...
+                std::string fullPath = fanTachPathPrefix;
+                std::string fanAb = (pReq->Instance % 2) == 0 ? "b" : "a";
+                if (0 == pReq->Instance)
+                {
+                    *data_len = 0;
+                    retCode = IPMI_CC_INVALID_FIELD_REQUEST;
+                    break;
+                }
+                else if (0 == pReq->Instance / 2)
+                {
+                    fullPath += std::string("1") + fanAb;
+                }
+                else
+                {
+                    fullPath += std::to_string(pReq->Instance / 2) + fanAb;
+                }
+
+                ret = mtm.getProperty(fanService, fullPath, fanIntf, "Value",
+                                      &reply);
+                if (ret < 0)
+                {
+                    *data_len = 0;
+                    retCode = IPMI_CC_INVALID_FIELD_REQUEST;
+                    break;
+                }
+
+                uint16_t value = std::get<double>(reply);
+                *data_len = sizeof(*pRsp);
+
+                pRsp->SigVal = FAN_PRESENT | FAN_SENSOR_PRESENT;
+                pRsp->SigVal1 = value & 0x00FF;
+                pRsp->SigVal2 = (value >> 8) & 0xFF;
+            }
+            break;
+            case SmSignalGet::smResetButton:      // gpio32
+            case SmSignalGet::smPowerButton:      // gpio34
+            case SmSignalGet::smFpLcpEnterButton: // gpio51
+            case SmSignalGet::smFpLcpLeftButton:  // gpio52
+            case SmSignalGet::smFpLcpRightButton: // gpio53
+            case SmSignalGet::smNmiButton:        // gpio217
+            case SmSignalGet::smIdentifyButton:   // gpio218
+                std::tie(*data_len, retCode, pRsp->SigVal) =
+                    mtm.proccessSignal(pReq->Signal, pReq->Action);
+                *data_len = sizeof(pRsp->SigVal);
+                break;
+            default:
+                *data_len = 0;
+                retCode = IPMI_CC_INVALID_FIELD_REQUEST;
+                break;
+        }
+    }
+    else
+    {
+        *data_len = 0;
+        retCode = IPMI_CC_REQ_DATA_LEN_INVALID;
+    }
+
+    return retCode;
+}
+
+ipmi_ret_t ipmi_app_mtm_set_signal(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)
+{
+    uint8_t ret = 0;
+    ipmi_ret_t retCode = IPMI_CC_OK;
+    SetSmSignalReq* pReq = static_cast<SetSmSignalReq*>(request);
+    std::string ledName;
+    ///////////////////  Signal to led configuration ////////////////
+    //        {SM_SYSTEM_READY_LED, STAT_GRN_LED},    GPIOS4  gpio148
+    //        {SM_POWER_FAULT_LED, STAT_AMB_LED},     GPIOS5  gpio149
+    //        {SM_IDENTIFY_LED, IDENTIFY_LED},        GPIOS6  gpio150
+    //        {SM_SPEAKER, SPEAKER},                  GPIOAB0 gpio216
+    /////////////////////////////////////////////////////////////////
+    if ((*data_len == sizeof(*pReq)) &&
+        (mtm.getAccessLvl() >= MtmLvl::mtmAvailable))
+    {
+        switch (pReq->Signal)
+        {
+            case SmSignalSet::smPowerFaultLed:
+            case SmSignalSet::smSystemReadyLed:
+            case SmSignalSet::smIdentifyLed:
+                switch (pReq->Action)
+                {
+                    case SmActionSet::forceDeasserted:
+                    {
+                        phosphor::logging::log<phosphor::logging::level::INFO>(
+                            "case SmActionSet::forceDeasserted");
+
+                        retCode =
+                            ledStoreAndSet(pReq->Signal, std::string("Off"));
+                        if (retCode != IPMI_CC_OK)
+                        {
+                            break;
+                        }
+                        mtm.revertTimer.start(revertTimeOut);
+                    }
+                    break;
+                    case SmActionSet::forceAsserted:
+                    {
+                        phosphor::logging::log<phosphor::logging::level::INFO>(
+                            "case SmActionSet::forceAsserted");
+
+                        retCode =
+                            ledStoreAndSet(pReq->Signal, std::string("On"));
+                        if (retCode != IPMI_CC_OK)
+                        {
+                            break;
+                        }
+                        mtm.revertTimer.start(revertTimeOut);
+                        if (SmSignalSet::smPowerFaultLed == pReq->Signal)
+                        {
+                            // Deassert "system ready"
+                            retCode =
+                                ledStoreAndSet(SmSignalSet::smSystemReadyLed,
+                                               std::string("Off"));
+                            if (retCode != IPMI_CC_OK)
+                            {
+                                break;
+                            }
+                        }
+                        else if (SmSignalSet::smSystemReadyLed == pReq->Signal)
+                        {
+                            // Deassert "fault led"
+                            retCode =
+                                ledStoreAndSet(SmSignalSet::smPowerFaultLed,
+                                               std::string("Off"));
+                            if (retCode != IPMI_CC_OK)
+                            {
+                                break;
+                            }
+                        }
+                    }
+                    break;
+                    case SmActionSet::revert:
+                    {
+                        phosphor::logging::log<phosphor::logging::level::INFO>(
+                            "case SmActionSet::revert");
+                        retCode = ledRevert(pReq->Signal);
+                        if (retCode != IPMI_CC_OK)
+                        {
+                            break;
+                        }
+                    }
+                    break;
+                    default:
+                    {
+                        retCode = IPMI_CC_INVALID_FIELD_REQUEST;
+                    }
+                    break;
+                }
+                break;
+            case SmSignalSet::smFanPowerSpeed:
+            {
+                if (((pReq->Action == SmActionSet::forceAsserted) &&
+                     (*data_len != sizeof(*pReq)) && (pReq->Value > 100)) ||
+                    pReq->Instance == 0)
+                {
+                    retCode = IPMI_CC_INVALID_FIELD_REQUEST;
+                    break;
+                }
+                uint8_t pwmValue = 0;
+                switch (pReq->Action)
+                {
+                    case SmActionSet::revert:
+                    {
+                        if (mtm.revertFanPWM)
+                        {
+                            ret = mtm.disablePidControlService(false);
+                            if (ret < 0)
+                            {
+                                retCode = IPMI_CC_UNSPECIFIED_ERROR;
+                                break;
+                            }
+                            mtm.revertFanPWM = false;
+                        }
+                    }
+                    break;
+                    case SmActionSet::forceAsserted:
+                    {
+                        pwmValue = pReq->Value;
+                    } // fall-through
+                    case SmActionSet::forceDeasserted:
+                    {
+                        if (!mtm.revertFanPWM)
+                        {
+                            ret = mtm.disablePidControlService(true);
+                            if (ret < 0)
+                            {
+                                retCode = IPMI_CC_UNSPECIFIED_ERROR;
+                                break;
+                            }
+                            mtm.revertFanPWM = true;
+                        }
+                        mtm.revertTimer.start(revertTimeOut);
+                        std::string fanPwmInstancePath =
+                            fanPwmPath + std::to_string(pReq->Instance);
+
+                        ret = mtm.setProperty(
+                            fanService, fanPwmInstancePath.c_str(), fanIntf,
+                            "Value", static_cast<double>(pwmValue));
+                        if (ret < 0)
+                        {
+                            retCode = IPMI_CC_UNSPECIFIED_ERROR;
+                        }
+                    }
+                    break;
+                    default:
+                    {
+                        retCode = IPMI_CC_INVALID_FIELD_REQUEST;
+                    }
+                    break;
+                }
+            }
+            break;
+            default:
+            {
+                retCode = IPMI_CC_INVALID_FIELD_REQUEST;
+            }
+            break;
+        }
+    }
+    else
+    {
+        retCode = IPMI_CC_ILLEGAL_COMMAND;
+    }
+
+    *data_len = 0; // Only CC is return for SetSmSignal cmd
+    return retCode;
+}
+
+} // namespace ipmi
+
+void register_mtm_commands() __attribute__((constructor));
+void register_mtm_commands()
+{
+    ipmi_register_callback(
+        netfnIntcOEMGeneral,
+        static_cast<ipmi_cmd_t>(IPMINetFnIntelOemGeneralCmds::GetSmSignal),
+        NULL, ipmi::ipmi_app_mtm_get_signal, PRIVILEGE_USER);
+
+    ipmi_register_callback(
+        netfnIntcOEMGeneral,
+        static_cast<ipmi_cmd_t>(IPMINetFnIntelOemGeneralCmds::SetSmSignal),
+        NULL, ipmi::ipmi_app_mtm_set_signal, PRIVILEGE_USER);
+
+    return;
+}