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