| /* Copyright 2018 Intel |
| * |
| * 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 "ipmbdefines.hpp" |
| |
| #include <boost/container/flat_set.hpp> |
| #include <optional> |
| #include <sdbusplus/asio/object_server.hpp> |
| #include <sdbusplus/message.hpp> |
| #include <vector> |
| |
| #ifndef IPMBBRIDGED_HPP |
| #define IPMBBRIDGED_HPP |
| |
| /** |
| * @brief Ipmb return status codes (sendRequest API call) |
| */ |
| enum class ipmbResponseStatus |
| { |
| success = 0, |
| error = 1, |
| invalid_param = 2, |
| busy = 3, |
| timeout = 4, |
| }; |
| |
| /** |
| * @brief Ipmb outstanding requests defines |
| */ |
| constexpr int ipmbMaxOutstandingRequestsCount = 64; |
| constexpr int ipmbNumberOfTries = 6; |
| constexpr uint64_t ipmbRequestRetryTimeout = 250; // ms |
| |
| /** |
| * @brief Ipmb I2C communication |
| */ |
| constexpr uint8_t ipmbI2cNumberOfRetries = 2; |
| |
| /** |
| * @brief Ipmb defines |
| */ |
| constexpr size_t ipmbMaxDataSize = 256; |
| constexpr size_t ipmbConnectionHeaderLength = 3; |
| constexpr size_t ipmbResponseDataHeaderLength = 4; |
| constexpr size_t ipmbRequestDataHeaderLength = 3; |
| constexpr size_t ipmbAddressSize = 1; |
| constexpr size_t ipmbChecksumSize = 1; |
| constexpr size_t ipmbChecksum2StartOffset = 3; |
| constexpr size_t ipmbMinFrameLength = 7; |
| constexpr size_t ipmbMaxFrameLength = ipmbConnectionHeaderLength + |
| ipmbResponseDataHeaderLength + |
| ipmbChecksumSize + ipmbMaxDataSize; |
| |
| /** |
| * @brief Ipmb misc |
| */ |
| constexpr uint8_t ipmbNetFnResponseMask = 0x01; |
| constexpr uint8_t ipmbLunMask = 0x03; |
| constexpr uint8_t ipmbSeqMask = 0x3F; |
| constexpr uint8_t ipmbRsLun = 0x0; |
| |
| /** |
| * @brief Ipmb setters |
| */ |
| constexpr uint8_t ipmbNetFnLunSet(uint8_t netFn, uint8_t lun) |
| { |
| return ((netFn << 2) | (lun & ipmbLunMask)); |
| } |
| |
| constexpr uint8_t ipmbSeqLunSet(uint8_t seq, uint8_t lun) |
| { |
| return ((seq << 2) | (lun & ipmbLunMask)); |
| } |
| |
| constexpr uint8_t ipmbAddressTo7BitSet(uint8_t address) |
| { |
| return address >> 1; |
| } |
| |
| constexpr uint8_t ipmbRespNetFn(uint8_t netFn) |
| { |
| return netFn |= 1; |
| } |
| |
| /** |
| * @brief Ipmb getters |
| */ |
| constexpr uint8_t ipmbNetFnGet(uint8_t netFnLun) |
| { |
| return netFnLun >> 2; |
| } |
| |
| constexpr uint8_t ipmbLunFromNetFnLunGet(uint8_t netFnLun) |
| { |
| return netFnLun & ipmbLunMask; |
| } |
| |
| constexpr uint8_t ipmbSeqGet(uint8_t seqNumLun) |
| { |
| return seqNumLun >> 2; |
| } |
| |
| constexpr uint8_t ipmbLunFromSeqLunGet(uint8_t seqNumLun) |
| { |
| return seqNumLun & ipmbLunMask; |
| } |
| |
| /** |
| * @brief Ipmb checkers |
| */ |
| constexpr bool ipmbIsResponse(IPMB_HEADER *ipmbHeader) |
| { |
| return ipmbNetFnGet(ipmbHeader->Header.Resp.rqNetFnLUN) & |
| ipmbNetFnResponseMask; |
| } |
| |
| /** |
| * @brief Ipmb request state |
| */ |
| enum class ipmbRequestState |
| { |
| invalid, |
| valid, |
| matched, |
| }; |
| |
| /** |
| * @brief Channel types |
| */ |
| enum class ipmbChannelType |
| { |
| ipmb = 0, |
| me = 1 |
| }; |
| |
| /** |
| * @brief IpmbResponse declaration |
| */ |
| struct IpmbResponse |
| { |
| uint8_t address; |
| uint8_t netFn; |
| uint8_t rqLun; |
| uint8_t rsSA; |
| uint8_t seq; |
| uint8_t rsLun; |
| uint8_t cmd; |
| uint8_t completionCode; |
| std::vector<uint8_t> data; |
| |
| IpmbResponse(); |
| |
| IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun, uint8_t rsSA, |
| uint8_t seq, uint8_t rsLun, uint8_t cmd, |
| uint8_t completionCode, const std::vector<uint8_t> &inputData); |
| |
| void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength); |
| |
| std::shared_ptr<std::vector<uint8_t>> ipmbToi2cConstruct(); |
| }; |
| |
| /** |
| * @brief IpmbRequest declaration |
| */ |
| struct IpmbRequest |
| { |
| uint8_t address; |
| uint8_t netFn; |
| uint8_t rsLun; |
| uint8_t rqSA; |
| uint8_t seq; |
| uint8_t rqLun; |
| uint8_t cmd; |
| std::vector<uint8_t> data; |
| |
| size_t dataLength; |
| ipmbRequestState state; |
| std::optional<boost::asio::steady_timer> timer; |
| std::unique_ptr<IpmbResponse> matchedResponse; |
| |
| // creates empty request with empty timer object |
| IpmbRequest(); |
| |
| IpmbRequest(uint8_t address, uint8_t netFn, uint8_t rsLun, uint8_t rqSA, |
| uint8_t seq, uint8_t rqLun, uint8_t cmd, |
| const std::vector<uint8_t> &inputData); |
| |
| IpmbRequest(const IpmbRequest &) = delete; |
| IpmbRequest &operator=(IpmbRequest const &) = delete; |
| |
| std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>> |
| returnMatchedResponse(); |
| |
| std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>> |
| returnStatusResponse(int status); |
| |
| void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength); |
| |
| int ipmbToi2cConstruct(std::vector<uint8_t> &buffer); |
| }; |
| |
| /** |
| * @brief Command filtering class declaration |
| * |
| * This feature provides simple mechanism for filtering out commands - which are |
| * not implemented in IPMI - on IPMB level, in order to reduce DBus traffic |
| */ |
| class IpmbCommandFilter |
| { |
| public: |
| // function checking if netFn & cmd combination exist in blocked command |
| // list |
| bool isBlocked(const uint8_t reqNetFn, const uint8_t cmd); |
| // function adding netfFn & cmd combination to the blocked command list |
| void addFilter(const uint8_t reqNetFn, const uint8_t cmd); |
| |
| private: |
| boost::container::flat_set<std::pair<uint8_t, uint8_t>> unhandledCommands; |
| }; |
| |
| /** |
| * @brief Command filtering defines |
| */ |
| |
| constexpr uint8_t ipmbIpmiInvalidCmd = 0xC1; |
| constexpr uint8_t ipmbIpmiCmdRespNotProvided = 0xCE; |
| |
| constexpr uint8_t ipmbReqNetFnFromRespNetFn(uint8_t reqNetFn) |
| { |
| return reqNetFn & ~ipmbNetFnResponseMask; |
| } |
| |
| /** |
| * @brief IpmbChannel class declaration |
| */ |
| class IpmbChannel |
| { |
| public: |
| IpmbChannel(boost::asio::io_service &io, uint8_t ipmbBmcSlaveAddress, |
| uint8_t ipmbRqSlaveAddress, ipmbChannelType type, |
| std::shared_ptr<IpmbCommandFilter> commandFilter); |
| |
| IpmbChannel(const IpmbChannel &) = delete; |
| IpmbChannel &operator=(IpmbChannel const &) = delete; |
| |
| int ipmbChannelInit(const char *ipmbI2cSlave, const char *ipmbI2cMaster); |
| |
| int ipmbChannelUpdateSlaveAddress(const uint8_t newBmcSlaveAddr); |
| |
| bool seqNumGet(uint8_t &seq); |
| |
| ipmbChannelType getChannelType(); |
| |
| uint8_t getBusId(); |
| |
| uint8_t getBmcSlaveAddress(); |
| |
| uint8_t getRqSlaveAddress(); |
| |
| void addFilter(const uint8_t respNetFn, const uint8_t cmd); |
| |
| void processI2cEvent(); |
| |
| void ipmbResponseSend(std::shared_ptr<std::vector<uint8_t>> buffer, |
| size_t retriesAttempted); |
| |
| std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>> |
| requestAdd(boost::asio::yield_context &yield, |
| std::shared_ptr<IpmbRequest> requestToSend); |
| |
| private: |
| boost::asio::ip::tcp::socket i2cSlaveSocket; |
| boost::asio::posix::stream_descriptor i2cMasterSocket; |
| |
| int ipmbi2cMasterFd; |
| int ipmbi2cSlaveFd; |
| |
| uint8_t ipmbBmcSlaveAddress; |
| uint8_t ipmbRqSlaveAddress; |
| uint8_t ipmbBusId; |
| |
| ipmbChannelType type; |
| |
| std::shared_ptr<IpmbCommandFilter> commandFilter; |
| |
| // array storing outstanding requests |
| std::array<std::shared_ptr<IpmbRequest>, ipmbMaxOutstandingRequestsCount> |
| outstandingRequests; |
| |
| void requestTimerCallback(std::shared_ptr<IpmbRequest> request, |
| std::shared_ptr<std::vector<uint8_t>> buffer); |
| |
| void responseMatch(std::unique_ptr<IpmbResponse> &response); |
| |
| void makeRequestInvalid(IpmbRequest &request); |
| |
| void makeRequestValid(std::shared_ptr<IpmbRequest> request); |
| }; |
| |
| #endif |