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