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