blob: a3c9d3f6dfa935b327490f157c3b0a85a52f5bcd [file] [log] [blame]
William A. Kennington III03e6def2021-05-11 15:23:15 -07001#include "cmd.hpp"
2
Patrick Williamse0602aa2023-07-17 11:20:00 -05003#include "print.hpp"
William A. Kennington III03e6def2021-05-11 15:23:15 -07004
5#include <sdbusplus/bus.hpp>
6#include <sdbusplus/exception.hpp>
7#include <sdbusplus/message.hpp>
8#include <sdbusplus/slot.hpp>
9#include <stdplus/exception.hpp>
10#include <stdplus/fd/ops.hpp>
William A. Kennington III03e6def2021-05-11 15:23:15 -070011
12#include <array>
Patrick Williamse0602aa2023-07-17 11:20:00 -050013#include <cstdio>
14#include <format>
William A. Kennington III03e6def2021-05-11 15:23:15 -070015#include <map>
Patrick Williams08041c62021-10-06 11:08:34 -050016#include <span>
William A. Kennington III03e6def2021-05-11 15:23:15 -070017#include <stdexcept>
18#include <tuple>
19#include <utility>
20#include <variant>
21#include <vector>
22
23namespace kcsbridge
24{
25
Patrick Williams0efeb172022-07-22 19:26:56 -050026using sdbusplus::bus_t;
27using sdbusplus::message_t;
28using sdbusplus::slot_t;
William A. Kennington III03e6def2021-05-11 15:23:15 -070029
Patrick Williams0efeb172022-07-22 19:26:56 -050030void write(stdplus::Fd& kcs, message_t&& m)
William A. Kennington III03e6def2021-05-11 15:23:15 -070031{
32 std::array<uint8_t, 1024> buffer;
Patrick Williams08041c62021-10-06 11:08:34 -050033 std::span<uint8_t> out(buffer.begin(), 3);
William A. Kennington III03e6def2021-05-11 15:23:15 -070034 try
35 {
36 if (m.is_method_error())
37 {
38 // Extra copy to workaround lack of `const sd_bus_error` constructor
39 auto error = *m.get_error();
40 throw sdbusplus::exception::SdBusError(&error, "ipmid response");
41 }
42 std::tuple<uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
43 ret;
44 m.read(ret);
45 const auto& [netfn, lun, cmd, cc, data] = ret;
46 // Based on the IPMI KCS spec Figure 9-2
47 // netfn needs to be changed to odd in KCS responses
48 if (data.size() + 3 > buffer.size())
49 {
Patrick Williamse0602aa2023-07-17 11:20:00 -050050 throw std::runtime_error(std::format(
William A. Kennington III03e6def2021-05-11 15:23:15 -070051 "too large {} > {}", data.size() + 3, buffer.size()));
52 }
53 buffer[0] = (netfn | 1) << 2;
54 buffer[0] |= lun;
55 buffer[1] = cmd;
56 buffer[2] = cc;
57 memcpy(&buffer[3], data.data(), data.size());
Patrick Williams08041c62021-10-06 11:08:34 -050058 out = std::span<uint8_t>(buffer.begin(), data.size() + 3);
William A. Kennington III03e6def2021-05-11 15:23:15 -070059 }
60 catch (const std::exception& e)
61 {
Patrick Williamse0602aa2023-07-17 11:20:00 -050062 std::print(stderr, "IPMI response failure: {}\n", e.what());
William A. Kennington III03e6def2021-05-11 15:23:15 -070063 buffer[0] |= 1 << 2;
64 buffer[2] = 0xff;
65 }
66 stdplus::fd::writeExact(kcs, out);
67}
68
Patrick Williams0efeb172022-07-22 19:26:56 -050069void read(stdplus::Fd& kcs, bus_t& bus, slot_t& outstanding)
William A. Kennington III03e6def2021-05-11 15:23:15 -070070{
71 std::array<uint8_t, 1024> buffer;
72 auto in = stdplus::fd::read(kcs, buffer);
73 if (in.empty())
74 {
75 return;
76 }
77 if (outstanding)
78 {
Patrick Williamse0602aa2023-07-17 11:20:00 -050079 std::print(stderr, "Canceling outstanding request\n");
Patrick Williams0efeb172022-07-22 19:26:56 -050080 outstanding = slot_t(nullptr);
William A. Kennington III03e6def2021-05-11 15:23:15 -070081 }
82 if (in.size() < 2)
83 {
Patrick Williamse0602aa2023-07-17 11:20:00 -050084 std::print(stderr, "Read too small, ignoring\n");
William A. Kennington III03e6def2021-05-11 15:23:15 -070085 return;
86 }
87 auto m = bus.new_method_call("xyz.openbmc_project.Ipmi.Host",
88 "/xyz/openbmc_project/Ipmi",
89 "xyz.openbmc_project.Ipmi.Server", "execute");
90 std::map<std::string, std::variant<int>> options;
91 // Based on the IPMI KCS spec Figure 9-1
92 uint8_t netfn = in[0] >> 2, lun = in[0] & 3, cmd = in[1];
93 m.append(netfn, lun, cmd, in.subspan(2), options);
94 outstanding = m.call_async(
Patrick Williams0efeb172022-07-22 19:26:56 -050095 stdplus::exception::ignore([&outstanding, &kcs](message_t&& m) {
Patrick Williamsbe4d9e72023-10-20 11:19:24 -050096 outstanding = slot_t(nullptr);
97 write(kcs, std::move(m));
98 }));
William A. Kennington III03e6def2021-05-11 15:23:15 -070099}
100
101} // namespace kcsbridge