xref: /openbmc/google-ipmi-sys/pcie_i2c.cpp (revision 3fb74294)
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