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