xref: /openbmc/google-ipmi-sys/pcie_i2c.cpp (revision 72e1a882)
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 <string>
25 #include <tuple>
26 #include <vector>
27 
28 namespace google
29 {
30 namespace ipmi
31 {
32 
33 namespace
34 {
35 
36 #ifndef MAX_IPMI_BUFFER
37 #define MAX_IPMI_BUFFER 64
38 #endif
39 
40 std::vector<std::tuple<uint32_t, std::string>> pcie_i2c_map;
41 
42 } // namespace
43 
44 struct PcieSlotCountRequest
45 {
46     uint8_t subcommand;
47 } __attribute__((packed));
48 
49 struct PcieSlotCountReply
50 {
51     uint8_t subcommand;
52     uint8_t value;
53 } __attribute__((packed));
54 
55 struct PcieSlotI2cBusMappingRequest
56 {
57     uint8_t subcommand;
58     uint8_t entry;
59 } __attribute__((packed));
60 
61 struct PcieSlotI2cBusMappingReply
62 {
63     uint8_t subcommand;
64     uint8_t i2c_bus_number;
65     uint8_t pcie_slot_name_len;
66     uint8_t pcie_slot_name[0];
67 } __attribute__((packed));
68 
69 ipmi_ret_t PcieSlotCount(const uint8_t* reqBuf, uint8_t* replyBuf,
70                          size_t* dataLen)
71 {
72     if ((*dataLen) < sizeof(struct PcieSlotCountRequest))
73     {
74         std::fprintf(stderr, "Invalid command length: %u\n",
75                      static_cast<uint32_t>(*dataLen));
76         return IPMI_CC_REQ_DATA_LEN_INVALID;
77     }
78 
79     // If there are already entries in the vector, clear them.
80     pcie_i2c_map = buildPcieMap();
81 
82     struct PcieSlotCountReply reply;
83     reply.subcommand = SysPcieSlotCount;
84     // Fill the pcie slot count as the number of entries in the vector.
85     reply.value = pcie_i2c_map.size();
86 
87     std::memcpy(&replyBuf[0], &reply, sizeof(reply));
88 
89     // Return the subcommand and the result.
90     (*dataLen) = sizeof(reply);
91 
92     return IPMI_CC_OK;
93 }
94 
95 ipmi_ret_t PcieSlotI2cBusMapping(const uint8_t* reqBuf, uint8_t* replyBuf,
96                                  size_t* dataLen)
97 {
98     struct PcieSlotI2cBusMappingRequest request;
99 
100     if ((*dataLen) < sizeof(request))
101     {
102         std::fprintf(stderr, "Invalid command length: %u\n",
103                      static_cast<uint32_t>(*dataLen));
104         return IPMI_CC_REQ_DATA_LEN_INVALID;
105     }
106 
107     // If there are no entries in the vector return error.
108     if (pcie_i2c_map.empty())
109     {
110         return IPMI_CC_INVALID_RESERVATION_ID;
111     }
112 
113     std::memcpy(&request, &reqBuf[0], sizeof(request));
114 
115     // The valid entries range from 0 to N - 1, N being the total number of
116     // entries in the vector.
117     if (request.entry >= pcie_i2c_map.size())
118     {
119         return IPMI_CC_PARM_OUT_OF_RANGE;
120     }
121 
122     // Get the i2c bus number and the pcie slot name from the vector.
123     uint32_t i2c_bus_number = std::get<0>(pcie_i2c_map[request.entry]);
124     std::string pcie_slot_name = std::get<1>(pcie_i2c_map[request.entry]);
125 
126     int length =
127         sizeof(struct PcieSlotI2cBusMappingReply) + pcie_slot_name.length();
128 
129     // TODO (jaghu) : Add a way to dynamically receive the MAX_IPMI_BUFFER
130     // value and change error to IPMI_CC_REQUESTED_TOO_MANY_BYTES.
131     if (length > MAX_IPMI_BUFFER)
132     {
133         std::fprintf(stderr, "Response would overflow response buffer\n");
134         return IPMI_CC_INVALID;
135     }
136 
137     auto reply =
138         reinterpret_cast<struct PcieSlotI2cBusMappingReply*>(&replyBuf[0]);
139     reply->subcommand = SysPcieSlotI2cBusMapping;
140     // Copy the i2c bus number and the pcie slot name to the reply struct.
141     reply->i2c_bus_number = i2c_bus_number;
142     reply->pcie_slot_name_len = pcie_slot_name.length();
143     std::memcpy(reply->pcie_slot_name, pcie_slot_name.c_str(),
144                 pcie_slot_name.length());
145 
146     // Return the subcommand and the result.
147     (*dataLen) = length;
148     return IPMI_CC_OK;
149 }
150 } // namespace ipmi
151 } // namespace google
152