blob: 88eb66c57ab51bf3eb1dd42a55e08e2c7d109383 [file] [log] [blame]
Jaghathiswari Rankappagounder Natarajan2d4836d2018-11-29 14:16:39 -08001/*
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"
Patrick Venture8d5c9ce2019-03-16 11:20:12 -070020#include "util.hpp"
Jaghathiswari Rankappagounder Natarajan2d4836d2018-11-29 14:16:39 -080021
22#include <cstdint>
23#include <cstring>
Patrick Venture07886992019-03-08 12:53:57 -080024#include <filesystem>
Jaghathiswari Rankappagounder Natarajan2d4836d2018-11-29 14:16:39 -080025#include <fstream>
26#include <regex>
27#include <sstream>
28#include <string>
29#include <system_error>
30#include <unordered_map>
31
32namespace google
33{
34namespace ipmi
35{
Patrick Venture07886992019-03-08 12:53:57 -080036namespace fs = std::filesystem;
Jaghathiswari Rankappagounder Natarajan2d4836d2018-11-29 14:16:39 -080037
38namespace
39{
40
41#ifndef MAX_IPMI_BUFFER
42#define MAX_IPMI_BUFFER 64
43#endif
44
45std::vector<std::tuple<uint32_t, std::string>> pcie_i2c_map;
46
Jaghathiswari Rankappagounder Natarajan2d4836d2018-11-29 14:16:39 -080047} // namespace
48
49struct PcieSlotCountRequest
50{
51 uint8_t subcommand;
52} __attribute__((packed));
53
54struct PcieSlotCountReply
55{
56 uint8_t subcommand;
57 uint8_t value;
58} __attribute__((packed));
59
60struct PcieSlotI2cBusMappingRequest
61{
62 uint8_t subcommand;
63 uint8_t entry;
64} __attribute__((packed));
65
66struct PcieSlotI2cBusMappingReply
67{
68 uint8_t subcommand;
69 uint8_t i2c_bus_number;
70 uint8_t pcie_slot_name_len;
71 uint8_t pcie_slot_name[0];
72} __attribute__((packed));
73
74ipmi_ret_t PcieSlotCount(const uint8_t* reqBuf, uint8_t* replyBuf,
75 size_t* dataLen)
76{
77 if ((*dataLen) < sizeof(struct PcieSlotCountRequest))
78 {
79 std::fprintf(stderr, "Invalid command length: %u\n",
80 static_cast<uint32_t>(*dataLen));
81 return IPMI_CC_REQ_DATA_LEN_INVALID;
82 }
83
84 // If there are already entries in the vector, clear them.
85 if (!pcie_i2c_map.empty())
86 pcie_i2c_map.clear();
87
88 // Build a vector with i2c bus to pcie slot mapping.
89 // Iterate through all the devices under "/sys/bus/i2c/devices".
90 for (auto& i2c_dev : fs::directory_iterator("/sys/bus/i2c/devices"))
91 {
92 std::string i2c_dev_path = i2c_dev.path();
93 std::smatch i2c_dev_string_number;
94 std::regex e("(i2c-)(\\d+)");
95 // Check if the device has "i2c-" in its path.
96 if (std::regex_search(i2c_dev_path, i2c_dev_string_number, e))
97 {
98 // Check if the i2c device has "pcie-slot" file under "of-node" dir.
99 std::string pcie_slot_path = i2c_dev_path + "/of_node/pcie-slot";
100 std::string pcie_slot;
101 // Read the "pcie-slot" name from the "pcie-slot" file.
Patrick Venture8d5c9ce2019-03-16 11:20:12 -0700102 pcie_slot = readPropertyFile(pcie_slot_path);
Jaghathiswari Rankappagounder Natarajan2d4836d2018-11-29 14:16:39 -0800103 if (pcie_slot.empty())
104 {
105 continue;
106 }
107 std::string pcie_slot_name;
108 std::string pcie_slot_full_path;
109 // Append the "pcie-slot" name to dts base.
110 pcie_slot_full_path.append("/proc/device-tree");
111 pcie_slot_full_path.append(pcie_slot);
112 // Read the "label" which contains the pcie slot name.
113 pcie_slot_full_path.append("/label");
Patrick Venture8d5c9ce2019-03-16 11:20:12 -0700114 pcie_slot_name = readPropertyFile(pcie_slot_full_path);
Jaghathiswari Rankappagounder Natarajan2d4836d2018-11-29 14:16:39 -0800115 if (pcie_slot_name.empty())
116 {
117 continue;
118 }
119 // Get the i2c bus number from the i2c device path.
120 uint32_t i2c_bus_number = i2c_dev_string_number[2].matched
121 ? std::stoi(i2c_dev_string_number[2])
122 : 0;
123 // Store the i2c bus number and the pcie slot name in the vector.
124 pcie_i2c_map.push_back(
125 std::make_tuple(i2c_bus_number, pcie_slot_name));
126 }
127 }
128
129 struct PcieSlotCountReply reply;
130 reply.subcommand = SysPcieSlotCount;
131 // Fill the pcie slot count as the number of entries in the vector.
132 reply.value = pcie_i2c_map.size();
133
134 std::memcpy(&replyBuf[0], &reply, sizeof(reply));
135
136 // Return the subcommand and the result.
137 (*dataLen) = sizeof(reply);
138
139 return IPMI_CC_OK;
140}
141
142ipmi_ret_t PcieSlotI2cBusMapping(const uint8_t* reqBuf, uint8_t* replyBuf,
143 size_t* dataLen)
144{
145 struct PcieSlotI2cBusMappingRequest request;
146
147 if ((*dataLen) < sizeof(request))
148 {
149 std::fprintf(stderr, "Invalid command length: %u\n",
150 static_cast<uint32_t>(*dataLen));
151 return IPMI_CC_REQ_DATA_LEN_INVALID;
152 }
153
154 // If there are no entries in the vector return error.
155 if (pcie_i2c_map.empty())
156 {
157 return IPMI_CC_INVALID_RESERVATION_ID;
158 }
159
160 std::memcpy(&request, &reqBuf[0], sizeof(request));
161
162 // The valid entries range from 0 to N - 1, N being the total number of
163 // entries in the vector.
164 if (request.entry >= pcie_i2c_map.size())
165 {
166 return IPMI_CC_PARM_OUT_OF_RANGE;
167 }
168
169 // Get the i2c bus number and the pcie slot name from the vector.
170 uint32_t i2c_bus_number = std::get<0>(pcie_i2c_map[request.entry]);
171 std::string pcie_slot_name = std::get<1>(pcie_i2c_map[request.entry]);
172
173 int length =
174 sizeof(struct PcieSlotI2cBusMappingReply) + pcie_slot_name.length();
175
176 // TODO (jaghu) : Add a way to dynamically receive the MAX_IPMI_BUFFER
177 // value and change error to IPMI_CC_REQUESTED_TOO_MANY_BYTES.
178 if (length > MAX_IPMI_BUFFER)
179 {
180 std::fprintf(stderr, "Response would overflow response buffer\n");
181 return IPMI_CC_INVALID;
182 }
183
184 auto reply =
185 reinterpret_cast<struct PcieSlotI2cBusMappingReply*>(&replyBuf[0]);
186 reply->subcommand = SysPcieSlotI2cBusMapping;
187 // Copy the i2c bus number and the pcie slot name to the reply struct.
188 reply->i2c_bus_number = i2c_bus_number;
189 reply->pcie_slot_name_len = pcie_slot_name.length();
190 std::memcpy(reply->pcie_slot_name, pcie_slot_name.c_str(),
191 pcie_slot_name.length());
192
193 // Return the subcommand and the result.
194 (*dataLen) = length;
195 return IPMI_CC_OK;
196}
197} // namespace ipmi
198} // namespace google