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