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