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 ipmbPktLenSize = 1; 70 constexpr size_t ipmbChecksumSize = 1; 71 constexpr size_t ipmbChecksum2StartOffset = 3; 72 constexpr size_t ipmbMinFrameLength = 7; 73 constexpr size_t ipmbMaxFrameLength = 74 ipmbPktLenSize + ipmbConnectionHeaderLength + ipmbResponseDataHeaderLength + 75 ipmbChecksumSize + ipmbMaxDataSize; 76 77 /** 78 * @brief Ipmb misc 79 */ 80 constexpr uint8_t ipmbNetFnResponseMask = 0x01; 81 constexpr uint8_t ipmbLunMask = 0x03; 82 constexpr uint8_t ipmbSeqMask = 0x3F; 83 constexpr uint8_t ipmbRsLun = 0x0; 84 85 /** 86 * @brief Ipmb setters 87 */ 88 constexpr uint8_t ipmbNetFnLunSet(uint8_t netFn, uint8_t lun) 89 { 90 return ((netFn << 2) | (lun & ipmbLunMask)); 91 } 92 93 constexpr uint8_t ipmbSeqLunSet(uint8_t seq, uint8_t lun) 94 { 95 return ((seq << 2) | (lun & ipmbLunMask)); 96 } 97 98 constexpr uint8_t ipmbAddressTo7BitSet(uint8_t address) 99 { 100 return address >> 1; 101 } 102 103 constexpr uint8_t ipmbRespNetFn(uint8_t netFn) 104 { 105 return netFn |= 1; 106 } 107 108 /** 109 * @brief Ipmb getters 110 */ 111 constexpr uint8_t ipmbNetFnGet(uint8_t netFnLun) 112 { 113 return netFnLun >> 2; 114 } 115 116 constexpr uint8_t ipmbLunFromNetFnLunGet(uint8_t netFnLun) 117 { 118 return netFnLun & ipmbLunMask; 119 } 120 121 constexpr uint8_t ipmbSeqGet(uint8_t seqNumLun) 122 { 123 return seqNumLun >> 2; 124 } 125 126 constexpr uint8_t ipmbLunFromSeqLunGet(uint8_t seqNumLun) 127 { 128 return seqNumLun & ipmbLunMask; 129 } 130 131 /** 132 * @brief Ipmb checkers 133 */ 134 constexpr bool ipmbIsResponse(IPMB_HEADER *ipmbHeader) 135 { 136 return ipmbNetFnGet(ipmbHeader->Header.Resp.rqNetFnLUN) & 137 ipmbNetFnResponseMask; 138 } 139 140 /** 141 * @brief Ipmb request state 142 */ 143 enum class ipmbRequestState 144 { 145 invalid, 146 valid, 147 matched, 148 }; 149 150 /** 151 * @brief Channel types 152 */ 153 enum class ipmbChannelType 154 { 155 ipmb = 0, 156 me = 1 157 }; 158 159 /** 160 * @brief IpmbResponse declaration 161 */ 162 struct IpmbResponse 163 { 164 uint8_t address; 165 uint8_t netFn; 166 uint8_t rqLun; 167 uint8_t rsSA; 168 uint8_t seq; 169 uint8_t rsLun; 170 uint8_t cmd; 171 uint8_t completionCode; 172 std::vector<uint8_t> data; 173 174 IpmbResponse(); 175 176 IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun, uint8_t rsSA, 177 uint8_t seq, uint8_t rsLun, uint8_t cmd, 178 uint8_t completionCode, const std::vector<uint8_t> &inputData); 179 180 void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength); 181 182 std::shared_ptr<std::vector<uint8_t>> ipmbToi2cConstruct(); 183 }; 184 185 /** 186 * @brief IpmbRequest declaration 187 */ 188 struct IpmbRequest 189 { 190 uint8_t address; 191 uint8_t netFn; 192 uint8_t rsLun; 193 uint8_t rqSA; 194 uint8_t seq; 195 uint8_t rqLun; 196 uint8_t cmd; 197 std::vector<uint8_t> data; 198 199 size_t dataLength; 200 ipmbRequestState state; 201 std::optional<boost::asio::steady_timer> timer; 202 std::unique_ptr<IpmbResponse> matchedResponse; 203 204 // creates empty request with empty timer object 205 IpmbRequest(); 206 207 IpmbRequest(uint8_t address, uint8_t netFn, uint8_t rsLun, uint8_t rqSA, 208 uint8_t seq, uint8_t rqLun, uint8_t cmd, 209 const std::vector<uint8_t> &inputData); 210 211 IpmbRequest(const IpmbRequest &) = delete; 212 IpmbRequest &operator=(IpmbRequest const &) = delete; 213 214 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>> 215 returnMatchedResponse(); 216 217 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>> 218 returnStatusResponse(int status); 219 220 void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength); 221 222 int ipmbToi2cConstruct(std::vector<uint8_t> &buffer); 223 }; 224 225 /** 226 * @brief Command filtering class declaration 227 * 228 * This feature provides simple mechanism for filtering out commands - which are 229 * not implemented in IPMI - on IPMB level, in order to reduce DBus traffic 230 */ 231 class IpmbCommandFilter 232 { 233 public: 234 // function checking if netFn & cmd combination exist in blocked command 235 // list 236 bool isBlocked(const uint8_t reqNetFn, const uint8_t cmd); 237 // function adding netfFn & cmd combination to the blocked command list 238 void addFilter(const uint8_t reqNetFn, const uint8_t cmd); 239 240 private: 241 boost::container::flat_set<std::pair<uint8_t, uint8_t>> unhandledCommands; 242 }; 243 244 /** 245 * @brief Command filtering defines 246 */ 247 248 constexpr uint8_t ipmbIpmiInvalidCmd = 0xC1; 249 constexpr uint8_t ipmbIpmiCmdRespNotProvided = 0xCE; 250 251 constexpr uint8_t ipmbReqNetFnFromRespNetFn(uint8_t reqNetFn) 252 { 253 return reqNetFn & ~ipmbNetFnResponseMask; 254 } 255 256 /** 257 * @brief IpmbChannel class declaration 258 */ 259 class IpmbChannel 260 { 261 public: 262 IpmbChannel(boost::asio::io_service &io, uint8_t ipmbBmcSlaveAddress, 263 uint8_t ipmbRqSlaveAddress, ipmbChannelType type, 264 std::shared_ptr<IpmbCommandFilter> commandFilter); 265 266 IpmbChannel(const IpmbChannel &) = delete; 267 IpmbChannel &operator=(IpmbChannel const &) = delete; 268 269 int ipmbChannelInit(const char *ipmbI2cSlave); 270 271 int ipmbChannelUpdateSlaveAddress(const uint8_t newBmcSlaveAddr); 272 273 bool seqNumGet(uint8_t &seq); 274 275 ipmbChannelType getChannelType(); 276 277 uint8_t getBusId(); 278 279 uint8_t getBmcSlaveAddress(); 280 281 uint8_t getRqSlaveAddress(); 282 283 void addFilter(const uint8_t respNetFn, const uint8_t cmd); 284 285 void processI2cEvent(); 286 287 void ipmbSendI2cFrame(std::shared_ptr<std::vector<uint8_t>> buffer, 288 size_t retriesAttempted); 289 290 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>> 291 requestAdd(boost::asio::yield_context &yield, 292 std::shared_ptr<IpmbRequest> requestToSend); 293 294 private: 295 boost::asio::posix::stream_descriptor i2cSlaveDescriptor; 296 297 int ipmbi2cSlaveFd; 298 299 uint8_t ipmbBmcSlaveAddress; 300 uint8_t ipmbRqSlaveAddress; 301 uint8_t ipmbBusId; 302 303 ipmbChannelType type; 304 305 std::shared_ptr<IpmbCommandFilter> commandFilter; 306 307 // array storing outstanding requests 308 std::array<std::shared_ptr<IpmbRequest>, ipmbMaxOutstandingRequestsCount> 309 outstandingRequests; 310 311 void requestTimerCallback(std::shared_ptr<IpmbRequest> request, 312 std::shared_ptr<std::vector<uint8_t>> buffer); 313 314 void responseMatch(std::unique_ptr<IpmbResponse> &response); 315 316 void makeRequestInvalid(IpmbRequest &request); 317 318 void makeRequestValid(std::shared_ptr<IpmbRequest> request); 319 }; 320 321 /** 322 * @brief ioWrite class declaration 323 */ 324 class ioWrite 325 { 326 public: 327 ioWrite(std::vector<uint8_t> &buffer) 328 { 329 i2cmsg[0].addr = ipmbAddressTo7BitSet(buffer[0]); 330 i2cmsg[0].len = buffer.size() - ipmbAddressSize; 331 i2cmsg[0].buf = buffer.data() + ipmbAddressSize; 332 333 msgRdwr.msgs = i2cmsg; 334 msgRdwr.nmsgs = 1; 335 }; 336 337 int name() 338 { 339 return static_cast<int>(I2C_RDWR); 340 } 341 342 void *data() 343 { 344 return &msgRdwr; 345 } 346 347 private: 348 int myname; 349 i2c_rdwr_ioctl_data msgRdwr = {0}; 350 i2c_msg i2cmsg[1] = {0}; 351 }; 352 353 #endif 354