1 // Copyright 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "config.h"
16 
17 #include "pcie_bifurcation.hpp"
18 
19 #include "commands.hpp"
20 #include "errors.hpp"
21 #include "handler.hpp"
22 
23 #include <fmt/format.h>
24 
25 #include <ipmid/api-types.hpp>
26 #include <span>
27 #include <vector>
28 
29 namespace google
30 {
31 namespace ipmi
32 {
33 
34 namespace
35 {
36 #ifndef MAX_IPMI_BUFFER
37 #define MAX_IPMI_BUFFER 64
38 #endif
39 } // namespace
40 
41 struct PcieBifurcationRequest
42 {
43     uint8_t pcieIndex;
44 } __attribute__((packed));
45 
46 Resp pcieBifurcation(std::span<const uint8_t> data, HandlerInterface* handler)
47 {
48     if (data.size() < sizeof(struct PcieBifurcationRequest))
49     {
50         fmt::print(stderr, "Invalid command length: {}\n",
51                    static_cast<uint32_t>(data.size()));
52         return ::ipmi::responseReqDataLenInvalid();
53     }
54 
55     auto bifurcation = handler->pcieBifurcation(/*index=*/data[0]);
56 
57     int length = sizeof(struct PcieBifurcationReply) + bifurcation.size();
58 
59     if (length > MAX_IPMI_BUFFER)
60     {
61         std::fprintf(stderr, "Response would overflow response buffer\n");
62         return ::ipmi::responseInvalidCommand();
63     }
64 
65     std::vector<std::uint8_t> reply;
66     reply.reserve(bifurcation.size() + sizeof(struct PcieBifurcationReply));
67     reply.emplace_back(bifurcation.size()); /* bifurcationLength */
68     reply.insert(reply.end(), bifurcation.begin(),
69                  bifurcation.end());        /* bifurcation */
70 
71     return ::ipmi::responseSuccess(SysOEMCommands::SysPCIeSlotBifurcation,
72                                    reply);
73 }
74 } // namespace ipmi
75 } // namespace google
76