1 /* 2 * Copyright 2018 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "pcie_i2c.hpp" 18 19 #include "main.hpp" 20 #include "util.hpp" 21 22 #include <cstdint> 23 #include <cstring> 24 #include <sstream> 25 #include <string> 26 #include <system_error> 27 #include <unordered_map> 28 29 namespace google 30 { 31 namespace ipmi 32 { 33 34 namespace 35 { 36 37 #ifndef MAX_IPMI_BUFFER 38 #define MAX_IPMI_BUFFER 64 39 #endif 40 41 std::vector<std::tuple<uint32_t, std::string>> pcie_i2c_map; 42 43 } // namespace 44 45 struct PcieSlotCountRequest 46 { 47 uint8_t subcommand; 48 } __attribute__((packed)); 49 50 struct PcieSlotCountReply 51 { 52 uint8_t subcommand; 53 uint8_t value; 54 } __attribute__((packed)); 55 56 struct PcieSlotI2cBusMappingRequest 57 { 58 uint8_t subcommand; 59 uint8_t entry; 60 } __attribute__((packed)); 61 62 struct PcieSlotI2cBusMappingReply 63 { 64 uint8_t subcommand; 65 uint8_t i2c_bus_number; 66 uint8_t pcie_slot_name_len; 67 uint8_t pcie_slot_name[0]; 68 } __attribute__((packed)); 69 70 ipmi_ret_t PcieSlotCount(const uint8_t* reqBuf, uint8_t* replyBuf, 71 size_t* dataLen) 72 { 73 if ((*dataLen) < sizeof(struct PcieSlotCountRequest)) 74 { 75 std::fprintf(stderr, "Invalid command length: %u\n", 76 static_cast<uint32_t>(*dataLen)); 77 return IPMI_CC_REQ_DATA_LEN_INVALID; 78 } 79 80 // If there are already entries in the vector, clear them. 81 pcie_i2c_map = buildPcieMap(); 82 83 struct PcieSlotCountReply reply; 84 reply.subcommand = SysPcieSlotCount; 85 // Fill the pcie slot count as the number of entries in the vector. 86 reply.value = pcie_i2c_map.size(); 87 88 std::memcpy(&replyBuf[0], &reply, sizeof(reply)); 89 90 // Return the subcommand and the result. 91 (*dataLen) = sizeof(reply); 92 93 return IPMI_CC_OK; 94 } 95 96 ipmi_ret_t PcieSlotI2cBusMapping(const uint8_t* reqBuf, uint8_t* replyBuf, 97 size_t* dataLen) 98 { 99 struct PcieSlotI2cBusMappingRequest request; 100 101 if ((*dataLen) < sizeof(request)) 102 { 103 std::fprintf(stderr, "Invalid command length: %u\n", 104 static_cast<uint32_t>(*dataLen)); 105 return IPMI_CC_REQ_DATA_LEN_INVALID; 106 } 107 108 // If there are no entries in the vector return error. 109 if (pcie_i2c_map.empty()) 110 { 111 return IPMI_CC_INVALID_RESERVATION_ID; 112 } 113 114 std::memcpy(&request, &reqBuf[0], sizeof(request)); 115 116 // The valid entries range from 0 to N - 1, N being the total number of 117 // entries in the vector. 118 if (request.entry >= pcie_i2c_map.size()) 119 { 120 return IPMI_CC_PARM_OUT_OF_RANGE; 121 } 122 123 // Get the i2c bus number and the pcie slot name from the vector. 124 uint32_t i2c_bus_number = std::get<0>(pcie_i2c_map[request.entry]); 125 std::string pcie_slot_name = std::get<1>(pcie_i2c_map[request.entry]); 126 127 int length = 128 sizeof(struct PcieSlotI2cBusMappingReply) + pcie_slot_name.length(); 129 130 // TODO (jaghu) : Add a way to dynamically receive the MAX_IPMI_BUFFER 131 // value and change error to IPMI_CC_REQUESTED_TOO_MANY_BYTES. 132 if (length > MAX_IPMI_BUFFER) 133 { 134 std::fprintf(stderr, "Response would overflow response buffer\n"); 135 return IPMI_CC_INVALID; 136 } 137 138 auto reply = 139 reinterpret_cast<struct PcieSlotI2cBusMappingReply*>(&replyBuf[0]); 140 reply->subcommand = SysPcieSlotI2cBusMapping; 141 // Copy the i2c bus number and the pcie slot name to the reply struct. 142 reply->i2c_bus_number = i2c_bus_number; 143 reply->pcie_slot_name_len = pcie_slot_name.length(); 144 std::memcpy(reply->pcie_slot_name, pcie_slot_name.c_str(), 145 pcie_slot_name.length()); 146 147 // Return the subcommand and the result. 148 (*dataLen) = length; 149 return IPMI_CC_OK; 150 } 151 } // namespace ipmi 152 } // namespace google 153