1a642a948SDawid Frycki /* Copyright 2018 Intel 2a642a948SDawid Frycki * 3a642a948SDawid Frycki * Licensed under the Apache License, Version 2.0 (the "License"); 4a642a948SDawid Frycki * you may not use this file except in compliance with the License. 5a642a948SDawid Frycki * You may obtain a copy of the License at 6a642a948SDawid Frycki * 7a642a948SDawid Frycki * http://www.apache.org/licenses/LICENSE-2.0 8a642a948SDawid Frycki * 9a642a948SDawid Frycki * Unless required by applicable law or agreed to in writing, software 10a642a948SDawid Frycki * distributed under the License is distributed on an "AS IS" BASIS, 11a642a948SDawid Frycki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12a642a948SDawid Frycki * See the License for the specific language governing permissions and 13a642a948SDawid Frycki * limitations under the License. 14a642a948SDawid Frycki */ 15a642a948SDawid Frycki 16a642a948SDawid Frycki #include "ipmbdefines.hpp" 17a642a948SDawid Frycki 18a642a948SDawid Frycki #include <boost/container/flat_set.hpp> 19a642a948SDawid Frycki #include <optional> 20a642a948SDawid Frycki #include <sdbusplus/asio/object_server.hpp> 21a642a948SDawid Frycki #include <sdbusplus/message.hpp> 22a642a948SDawid Frycki #include <vector> 23a642a948SDawid Frycki 24bbfd00abSQiang XU extern "C" { 25bbfd00abSQiang XU #include <i2c/smbus.h> 26bbfd00abSQiang XU #include <linux/i2c-dev.h> 27bbfd00abSQiang XU } 28bbfd00abSQiang XU 29a642a948SDawid Frycki #ifndef IPMBBRIDGED_HPP 30a642a948SDawid Frycki #define IPMBBRIDGED_HPP 31a642a948SDawid Frycki 32a642a948SDawid Frycki /** 33a642a948SDawid Frycki * @brief Ipmb return status codes (sendRequest API call) 34a642a948SDawid Frycki */ 35a642a948SDawid Frycki enum class ipmbResponseStatus 36a642a948SDawid Frycki { 37a642a948SDawid Frycki success = 0, 38a642a948SDawid Frycki error = 1, 39a642a948SDawid Frycki invalid_param = 2, 40a642a948SDawid Frycki busy = 3, 41a642a948SDawid Frycki timeout = 4, 42a642a948SDawid Frycki }; 43a642a948SDawid Frycki 44a642a948SDawid Frycki /** 45a642a948SDawid Frycki * @brief Ipmb outstanding requests defines 46a642a948SDawid Frycki */ 47a642a948SDawid Frycki constexpr int ipmbMaxOutstandingRequestsCount = 64; 48a642a948SDawid Frycki constexpr int ipmbNumberOfTries = 6; 49a642a948SDawid Frycki constexpr uint64_t ipmbRequestRetryTimeout = 250; // ms 50a642a948SDawid Frycki 51a642a948SDawid Frycki /** 52a642a948SDawid Frycki * @brief Ipmb I2C communication 53a642a948SDawid Frycki */ 54a642a948SDawid Frycki constexpr uint8_t ipmbI2cNumberOfRetries = 2; 55a642a948SDawid Frycki 56a642a948SDawid Frycki /** 57bbfd00abSQiang XU * @brief Ipmb boardcast address 58bbfd00abSQiang XU */ 59bbfd00abSQiang XU constexpr uint8_t broadcastAddress = 0x0; 60bbfd00abSQiang XU 61bbfd00abSQiang XU /** 62a642a948SDawid Frycki * @brief Ipmb defines 63a642a948SDawid Frycki */ 64a642a948SDawid Frycki constexpr size_t ipmbMaxDataSize = 256; 65a642a948SDawid Frycki constexpr size_t ipmbConnectionHeaderLength = 3; 66a642a948SDawid Frycki constexpr size_t ipmbResponseDataHeaderLength = 4; 67a642a948SDawid Frycki constexpr size_t ipmbRequestDataHeaderLength = 3; 68a642a948SDawid Frycki constexpr size_t ipmbAddressSize = 1; 69*37a7eaceSVijay Khemka constexpr size_t ipmbPktLenSize = 1; 70a642a948SDawid Frycki constexpr size_t ipmbChecksumSize = 1; 71a642a948SDawid Frycki constexpr size_t ipmbChecksum2StartOffset = 3; 72a642a948SDawid Frycki constexpr size_t ipmbMinFrameLength = 7; 73*37a7eaceSVijay Khemka constexpr size_t ipmbMaxFrameLength = 74*37a7eaceSVijay Khemka ipmbPktLenSize + ipmbConnectionHeaderLength + ipmbResponseDataHeaderLength + 75a642a948SDawid Frycki ipmbChecksumSize + ipmbMaxDataSize; 76a642a948SDawid Frycki 77a642a948SDawid Frycki /** 78a642a948SDawid Frycki * @brief Ipmb misc 79a642a948SDawid Frycki */ 80a642a948SDawid Frycki constexpr uint8_t ipmbNetFnResponseMask = 0x01; 81a642a948SDawid Frycki constexpr uint8_t ipmbLunMask = 0x03; 82a642a948SDawid Frycki constexpr uint8_t ipmbSeqMask = 0x3F; 83a642a948SDawid Frycki constexpr uint8_t ipmbRsLun = 0x0; 84a642a948SDawid Frycki 85a642a948SDawid Frycki /** 86a642a948SDawid Frycki * @brief Ipmb setters 87a642a948SDawid Frycki */ 88a642a948SDawid Frycki constexpr uint8_t ipmbNetFnLunSet(uint8_t netFn, uint8_t lun) 89a642a948SDawid Frycki { 90a642a948SDawid Frycki return ((netFn << 2) | (lun & ipmbLunMask)); 91a642a948SDawid Frycki } 92a642a948SDawid Frycki 93a642a948SDawid Frycki constexpr uint8_t ipmbSeqLunSet(uint8_t seq, uint8_t lun) 94a642a948SDawid Frycki { 95a642a948SDawid Frycki return ((seq << 2) | (lun & ipmbLunMask)); 96a642a948SDawid Frycki } 97a642a948SDawid Frycki 98a642a948SDawid Frycki constexpr uint8_t ipmbAddressTo7BitSet(uint8_t address) 99a642a948SDawid Frycki { 100a642a948SDawid Frycki return address >> 1; 101a642a948SDawid Frycki } 102a642a948SDawid Frycki 103a642a948SDawid Frycki constexpr uint8_t ipmbRespNetFn(uint8_t netFn) 104a642a948SDawid Frycki { 105a642a948SDawid Frycki return netFn |= 1; 106a642a948SDawid Frycki } 107a642a948SDawid Frycki 108a642a948SDawid Frycki /** 109a642a948SDawid Frycki * @brief Ipmb getters 110a642a948SDawid Frycki */ 111a642a948SDawid Frycki constexpr uint8_t ipmbNetFnGet(uint8_t netFnLun) 112a642a948SDawid Frycki { 113a642a948SDawid Frycki return netFnLun >> 2; 114a642a948SDawid Frycki } 115a642a948SDawid Frycki 116a642a948SDawid Frycki constexpr uint8_t ipmbLunFromNetFnLunGet(uint8_t netFnLun) 117a642a948SDawid Frycki { 118a642a948SDawid Frycki return netFnLun & ipmbLunMask; 119a642a948SDawid Frycki } 120a642a948SDawid Frycki 121a642a948SDawid Frycki constexpr uint8_t ipmbSeqGet(uint8_t seqNumLun) 122a642a948SDawid Frycki { 123a642a948SDawid Frycki return seqNumLun >> 2; 124a642a948SDawid Frycki } 125a642a948SDawid Frycki 126a642a948SDawid Frycki constexpr uint8_t ipmbLunFromSeqLunGet(uint8_t seqNumLun) 127a642a948SDawid Frycki { 128a642a948SDawid Frycki return seqNumLun & ipmbLunMask; 129a642a948SDawid Frycki } 130a642a948SDawid Frycki 131a642a948SDawid Frycki /** 132a642a948SDawid Frycki * @brief Ipmb checkers 133a642a948SDawid Frycki */ 134a642a948SDawid Frycki constexpr bool ipmbIsResponse(IPMB_HEADER *ipmbHeader) 135a642a948SDawid Frycki { 136a642a948SDawid Frycki return ipmbNetFnGet(ipmbHeader->Header.Resp.rqNetFnLUN) & 137a642a948SDawid Frycki ipmbNetFnResponseMask; 138a642a948SDawid Frycki } 139a642a948SDawid Frycki 140a642a948SDawid Frycki /** 141a642a948SDawid Frycki * @brief Ipmb request state 142a642a948SDawid Frycki */ 143a642a948SDawid Frycki enum class ipmbRequestState 144a642a948SDawid Frycki { 145a642a948SDawid Frycki invalid, 146a642a948SDawid Frycki valid, 147a642a948SDawid Frycki matched, 148a642a948SDawid Frycki }; 149a642a948SDawid Frycki 150a642a948SDawid Frycki /** 151a642a948SDawid Frycki * @brief Channel types 152a642a948SDawid Frycki */ 153a642a948SDawid Frycki enum class ipmbChannelType 154a642a948SDawid Frycki { 155a642a948SDawid Frycki ipmb = 0, 156a642a948SDawid Frycki me = 1 157a642a948SDawid Frycki }; 158a642a948SDawid Frycki 159a642a948SDawid Frycki /** 160a642a948SDawid Frycki * @brief IpmbResponse declaration 161a642a948SDawid Frycki */ 162a642a948SDawid Frycki struct IpmbResponse 163a642a948SDawid Frycki { 164a642a948SDawid Frycki uint8_t address; 165a642a948SDawid Frycki uint8_t netFn; 166a642a948SDawid Frycki uint8_t rqLun; 167a642a948SDawid Frycki uint8_t rsSA; 168a642a948SDawid Frycki uint8_t seq; 169a642a948SDawid Frycki uint8_t rsLun; 170a642a948SDawid Frycki uint8_t cmd; 171a642a948SDawid Frycki uint8_t completionCode; 172a642a948SDawid Frycki std::vector<uint8_t> data; 173a642a948SDawid Frycki 174a642a948SDawid Frycki IpmbResponse(); 175a642a948SDawid Frycki 176a642a948SDawid Frycki IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun, uint8_t rsSA, 177a642a948SDawid Frycki uint8_t seq, uint8_t rsLun, uint8_t cmd, 1788188d765SDawid Frycki uint8_t completionCode, const std::vector<uint8_t> &inputData); 179a642a948SDawid Frycki 180a642a948SDawid Frycki void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength); 181a642a948SDawid Frycki 1828188d765SDawid Frycki std::shared_ptr<std::vector<uint8_t>> ipmbToi2cConstruct(); 183a642a948SDawid Frycki }; 184a642a948SDawid Frycki 185a642a948SDawid Frycki /** 186a642a948SDawid Frycki * @brief IpmbRequest declaration 187a642a948SDawid Frycki */ 188a642a948SDawid Frycki struct IpmbRequest 189a642a948SDawid Frycki { 190a642a948SDawid Frycki uint8_t address; 191a642a948SDawid Frycki uint8_t netFn; 192a642a948SDawid Frycki uint8_t rsLun; 193a642a948SDawid Frycki uint8_t rqSA; 194a642a948SDawid Frycki uint8_t seq; 195a642a948SDawid Frycki uint8_t rqLun; 196a642a948SDawid Frycki uint8_t cmd; 197a642a948SDawid Frycki std::vector<uint8_t> data; 198a642a948SDawid Frycki 199a642a948SDawid Frycki size_t dataLength; 200a642a948SDawid Frycki ipmbRequestState state; 201a642a948SDawid Frycki std::optional<boost::asio::steady_timer> timer; 202a642a948SDawid Frycki std::unique_ptr<IpmbResponse> matchedResponse; 203a642a948SDawid Frycki 204a642a948SDawid Frycki // creates empty request with empty timer object 205a642a948SDawid Frycki IpmbRequest(); 206a642a948SDawid Frycki 207a642a948SDawid Frycki IpmbRequest(uint8_t address, uint8_t netFn, uint8_t rsLun, uint8_t rqSA, 208a642a948SDawid Frycki uint8_t seq, uint8_t rqLun, uint8_t cmd, 2098188d765SDawid Frycki const std::vector<uint8_t> &inputData); 210a642a948SDawid Frycki 211a642a948SDawid Frycki IpmbRequest(const IpmbRequest &) = delete; 212a642a948SDawid Frycki IpmbRequest &operator=(IpmbRequest const &) = delete; 213a642a948SDawid Frycki 214a642a948SDawid Frycki std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>> 215a642a948SDawid Frycki returnMatchedResponse(); 216a642a948SDawid Frycki 217a642a948SDawid Frycki std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>> 218a642a948SDawid Frycki returnStatusResponse(int status); 219a642a948SDawid Frycki 220a642a948SDawid Frycki void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength); 221a642a948SDawid Frycki 222a642a948SDawid Frycki int ipmbToi2cConstruct(std::vector<uint8_t> &buffer); 223a642a948SDawid Frycki }; 224a642a948SDawid Frycki 225a642a948SDawid Frycki /** 226a642a948SDawid Frycki * @brief Command filtering class declaration 227a642a948SDawid Frycki * 228a642a948SDawid Frycki * This feature provides simple mechanism for filtering out commands - which are 229a642a948SDawid Frycki * not implemented in IPMI - on IPMB level, in order to reduce DBus traffic 230a642a948SDawid Frycki */ 231a642a948SDawid Frycki class IpmbCommandFilter 232a642a948SDawid Frycki { 233a642a948SDawid Frycki public: 234a642a948SDawid Frycki // function checking if netFn & cmd combination exist in blocked command 235a642a948SDawid Frycki // list 236a642a948SDawid Frycki bool isBlocked(const uint8_t reqNetFn, const uint8_t cmd); 237a642a948SDawid Frycki // function adding netfFn & cmd combination to the blocked command list 238a642a948SDawid Frycki void addFilter(const uint8_t reqNetFn, const uint8_t cmd); 239a642a948SDawid Frycki 240a642a948SDawid Frycki private: 241a642a948SDawid Frycki boost::container::flat_set<std::pair<uint8_t, uint8_t>> unhandledCommands; 242a642a948SDawid Frycki }; 243a642a948SDawid Frycki 244a642a948SDawid Frycki /** 245a642a948SDawid Frycki * @brief Command filtering defines 246a642a948SDawid Frycki */ 247a642a948SDawid Frycki 2488188d765SDawid Frycki constexpr uint8_t ipmbIpmiInvalidCmd = 0xC1; 2498188d765SDawid Frycki constexpr uint8_t ipmbIpmiCmdRespNotProvided = 0xCE; 250a642a948SDawid Frycki 251a642a948SDawid Frycki constexpr uint8_t ipmbReqNetFnFromRespNetFn(uint8_t reqNetFn) 252a642a948SDawid Frycki { 253a642a948SDawid Frycki return reqNetFn & ~ipmbNetFnResponseMask; 254a642a948SDawid Frycki } 255a642a948SDawid Frycki 256a642a948SDawid Frycki /** 257a642a948SDawid Frycki * @brief IpmbChannel class declaration 258a642a948SDawid Frycki */ 259a642a948SDawid Frycki class IpmbChannel 260a642a948SDawid Frycki { 261a642a948SDawid Frycki public: 262a642a948SDawid Frycki IpmbChannel(boost::asio::io_service &io, uint8_t ipmbBmcSlaveAddress, 263a642a948SDawid Frycki uint8_t ipmbRqSlaveAddress, ipmbChannelType type, 264a642a948SDawid Frycki std::shared_ptr<IpmbCommandFilter> commandFilter); 265a642a948SDawid Frycki 266a642a948SDawid Frycki IpmbChannel(const IpmbChannel &) = delete; 267a642a948SDawid Frycki IpmbChannel &operator=(IpmbChannel const &) = delete; 268a642a948SDawid Frycki 269*37a7eaceSVijay Khemka int ipmbChannelInit(const char *ipmbI2cSlave); 270a642a948SDawid Frycki 2718edcf1a0SQiang XU int ipmbChannelUpdateSlaveAddress(const uint8_t newBmcSlaveAddr); 2728edcf1a0SQiang XU 273a642a948SDawid Frycki bool seqNumGet(uint8_t &seq); 274a642a948SDawid Frycki 275a642a948SDawid Frycki ipmbChannelType getChannelType(); 276a642a948SDawid Frycki 2778edcf1a0SQiang XU uint8_t getBusId(); 2788edcf1a0SQiang XU 279a642a948SDawid Frycki uint8_t getBmcSlaveAddress(); 280a642a948SDawid Frycki 281a642a948SDawid Frycki uint8_t getRqSlaveAddress(); 282a642a948SDawid Frycki 283a642a948SDawid Frycki void addFilter(const uint8_t respNetFn, const uint8_t cmd); 284a642a948SDawid Frycki 285a642a948SDawid Frycki void processI2cEvent(); 286a642a948SDawid Frycki 287bbfd00abSQiang XU void ipmbSendI2cFrame(std::shared_ptr<std::vector<uint8_t>> buffer, 288a642a948SDawid Frycki size_t retriesAttempted); 289a642a948SDawid Frycki 290a642a948SDawid Frycki std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>> 291a642a948SDawid Frycki requestAdd(boost::asio::yield_context &yield, 292a642a948SDawid Frycki std::shared_ptr<IpmbRequest> requestToSend); 293a642a948SDawid Frycki 294a642a948SDawid Frycki private: 295*37a7eaceSVijay Khemka boost::asio::posix::stream_descriptor i2cSlaveDescriptor; 296a642a948SDawid Frycki 297a642a948SDawid Frycki int ipmbi2cSlaveFd; 298a642a948SDawid Frycki 299a642a948SDawid Frycki uint8_t ipmbBmcSlaveAddress; 300a642a948SDawid Frycki uint8_t ipmbRqSlaveAddress; 3018edcf1a0SQiang XU uint8_t ipmbBusId; 302a642a948SDawid Frycki 303a642a948SDawid Frycki ipmbChannelType type; 304a642a948SDawid Frycki 305a642a948SDawid Frycki std::shared_ptr<IpmbCommandFilter> commandFilter; 306a642a948SDawid Frycki 307a642a948SDawid Frycki // array storing outstanding requests 308a642a948SDawid Frycki std::array<std::shared_ptr<IpmbRequest>, ipmbMaxOutstandingRequestsCount> 309a642a948SDawid Frycki outstandingRequests; 310a642a948SDawid Frycki 311a642a948SDawid Frycki void requestTimerCallback(std::shared_ptr<IpmbRequest> request, 312a642a948SDawid Frycki std::shared_ptr<std::vector<uint8_t>> buffer); 313a642a948SDawid Frycki 314a642a948SDawid Frycki void responseMatch(std::unique_ptr<IpmbResponse> &response); 315a642a948SDawid Frycki 316a642a948SDawid Frycki void makeRequestInvalid(IpmbRequest &request); 317a642a948SDawid Frycki 318a642a948SDawid Frycki void makeRequestValid(std::shared_ptr<IpmbRequest> request); 319a642a948SDawid Frycki }; 320a642a948SDawid Frycki 321bbfd00abSQiang XU /** 322bbfd00abSQiang XU * @brief ioWrite class declaration 323bbfd00abSQiang XU */ 324bbfd00abSQiang XU class ioWrite 325bbfd00abSQiang XU { 326bbfd00abSQiang XU public: 327bbfd00abSQiang XU ioWrite(std::vector<uint8_t> &buffer) 328bbfd00abSQiang XU { 329bbfd00abSQiang XU i2cmsg[0].addr = ipmbAddressTo7BitSet(buffer[0]); 330bbfd00abSQiang XU i2cmsg[0].len = buffer.size() - ipmbAddressSize; 331bbfd00abSQiang XU i2cmsg[0].buf = buffer.data() + ipmbAddressSize; 332bbfd00abSQiang XU 333bbfd00abSQiang XU msgRdwr.msgs = i2cmsg; 334bbfd00abSQiang XU msgRdwr.nmsgs = 1; 335bbfd00abSQiang XU }; 336bbfd00abSQiang XU 337bbfd00abSQiang XU int name() 338bbfd00abSQiang XU { 339bbfd00abSQiang XU return static_cast<int>(I2C_RDWR); 340bbfd00abSQiang XU } 341bbfd00abSQiang XU 342bbfd00abSQiang XU void *data() 343bbfd00abSQiang XU { 344bbfd00abSQiang XU return &msgRdwr; 345bbfd00abSQiang XU } 346bbfd00abSQiang XU 347bbfd00abSQiang XU private: 348bbfd00abSQiang XU int myname; 349bbfd00abSQiang XU i2c_rdwr_ioctl_data msgRdwr = {0}; 350bbfd00abSQiang XU i2c_msg i2cmsg[1] = {0}; 351bbfd00abSQiang XU }; 352bbfd00abSQiang XU 353a642a948SDawid Frycki #endif 354