xref: /openbmc/kcsbridge/src/cmd.cpp (revision c0c95be197cc6f863b0c11ca7726f8e34b74f370)
103e6defcSWilliam A. Kennington III #include "cmd.hpp"
203e6defcSWilliam A. Kennington III 
303e6defcSWilliam A. Kennington III #include <sdbusplus/bus.hpp>
403e6defcSWilliam A. Kennington III #include <sdbusplus/exception.hpp>
503e6defcSWilliam A. Kennington III #include <sdbusplus/message.hpp>
603e6defcSWilliam A. Kennington III #include <sdbusplus/slot.hpp>
703e6defcSWilliam A. Kennington III #include <stdplus/exception.hpp>
803e6defcSWilliam A. Kennington III #include <stdplus/fd/ops.hpp>
9*c0c95be1SPatrick Williams #include <stdplus/print.hpp>
1003e6defcSWilliam A. Kennington III 
1103e6defcSWilliam A. Kennington III #include <array>
12e0602aafSPatrick Williams #include <cstdio>
13e0602aafSPatrick Williams #include <format>
1403e6defcSWilliam A. Kennington III #include <map>
1508041c67SPatrick Williams #include <span>
1603e6defcSWilliam A. Kennington III #include <stdexcept>
1703e6defcSWilliam A. Kennington III #include <tuple>
1803e6defcSWilliam A. Kennington III #include <utility>
1903e6defcSWilliam A. Kennington III #include <variant>
2003e6defcSWilliam A. Kennington III #include <vector>
2103e6defcSWilliam A. Kennington III 
2203e6defcSWilliam A. Kennington III namespace kcsbridge
2303e6defcSWilliam A. Kennington III {
2403e6defcSWilliam A. Kennington III 
250efeb17fSPatrick Williams using sdbusplus::bus_t;
260efeb17fSPatrick Williams using sdbusplus::message_t;
270efeb17fSPatrick Williams using sdbusplus::slot_t;
2803e6defcSWilliam A. Kennington III 
write(stdplus::Fd & kcs,message_t && m)290efeb17fSPatrick Williams void write(stdplus::Fd& kcs, message_t&& m)
3003e6defcSWilliam A. Kennington III {
3103e6defcSWilliam A. Kennington III     std::array<uint8_t, 1024> buffer;
3208041c67SPatrick Williams     std::span<uint8_t> out(buffer.begin(), 3);
3303e6defcSWilliam A. Kennington III     try
3403e6defcSWilliam A. Kennington III     {
3503e6defcSWilliam A. Kennington III         if (m.is_method_error())
3603e6defcSWilliam A. Kennington III         {
3703e6defcSWilliam A. Kennington III             // Extra copy to workaround lack of `const sd_bus_error` constructor
3803e6defcSWilliam A. Kennington III             auto error = *m.get_error();
3903e6defcSWilliam A. Kennington III             throw sdbusplus::exception::SdBusError(&error, "ipmid response");
4003e6defcSWilliam A. Kennington III         }
4103e6defcSWilliam A. Kennington III         std::tuple<uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
4203e6defcSWilliam A. Kennington III             ret;
4303e6defcSWilliam A. Kennington III         m.read(ret);
4403e6defcSWilliam A. Kennington III         const auto& [netfn, lun, cmd, cc, data] = ret;
4503e6defcSWilliam A. Kennington III         // Based on the IPMI KCS spec Figure 9-2
4603e6defcSWilliam A. Kennington III         // netfn needs to be changed to odd in KCS responses
4703e6defcSWilliam A. Kennington III         if (data.size() + 3 > buffer.size())
4803e6defcSWilliam A. Kennington III         {
49e0602aafSPatrick Williams             throw std::runtime_error(std::format(
5003e6defcSWilliam A. Kennington III                 "too large {} > {}", data.size() + 3, buffer.size()));
5103e6defcSWilliam A. Kennington III         }
5203e6defcSWilliam A. Kennington III         buffer[0] = (netfn | 1) << 2;
5303e6defcSWilliam A. Kennington III         buffer[0] |= lun;
5403e6defcSWilliam A. Kennington III         buffer[1] = cmd;
5503e6defcSWilliam A. Kennington III         buffer[2] = cc;
5603e6defcSWilliam A. Kennington III         memcpy(&buffer[3], data.data(), data.size());
5708041c67SPatrick Williams         out = std::span<uint8_t>(buffer.begin(), data.size() + 3);
5803e6defcSWilliam A. Kennington III     }
5903e6defcSWilliam A. Kennington III     catch (const std::exception& e)
6003e6defcSWilliam A. Kennington III     {
61*c0c95be1SPatrick Williams         stdplus::print(stderr, "IPMI response failure: {}\n", e.what());
6203e6defcSWilliam A. Kennington III         buffer[0] |= 1 << 2;
6303e6defcSWilliam A. Kennington III         buffer[2] = 0xff;
6403e6defcSWilliam A. Kennington III     }
6503e6defcSWilliam A. Kennington III     stdplus::fd::writeExact(kcs, out);
6603e6defcSWilliam A. Kennington III }
6703e6defcSWilliam A. Kennington III 
read(stdplus::Fd & kcs,bus_t & bus,slot_t & outstanding)680efeb17fSPatrick Williams void read(stdplus::Fd& kcs, bus_t& bus, slot_t& outstanding)
6903e6defcSWilliam A. Kennington III {
7003e6defcSWilliam A. Kennington III     std::array<uint8_t, 1024> buffer;
7103e6defcSWilliam A. Kennington III     auto in = stdplus::fd::read(kcs, buffer);
7203e6defcSWilliam A. Kennington III     if (in.empty())
7303e6defcSWilliam A. Kennington III     {
7403e6defcSWilliam A. Kennington III         return;
7503e6defcSWilliam A. Kennington III     }
7603e6defcSWilliam A. Kennington III     if (outstanding)
7703e6defcSWilliam A. Kennington III     {
78*c0c95be1SPatrick Williams         stdplus::print(stderr, "Canceling outstanding request\n");
790efeb17fSPatrick Williams         outstanding = slot_t(nullptr);
8003e6defcSWilliam A. Kennington III     }
8103e6defcSWilliam A. Kennington III     if (in.size() < 2)
8203e6defcSWilliam A. Kennington III     {
83*c0c95be1SPatrick Williams         stdplus::print(stderr, "Read too small, ignoring\n");
8403e6defcSWilliam A. Kennington III         return;
8503e6defcSWilliam A. Kennington III     }
8603e6defcSWilliam A. Kennington III     auto m = bus.new_method_call("xyz.openbmc_project.Ipmi.Host",
8703e6defcSWilliam A. Kennington III                                  "/xyz/openbmc_project/Ipmi",
8803e6defcSWilliam A. Kennington III                                  "xyz.openbmc_project.Ipmi.Server", "execute");
8903e6defcSWilliam A. Kennington III     std::map<std::string, std::variant<int>> options;
9003e6defcSWilliam A. Kennington III     // Based on the IPMI KCS spec Figure 9-1
9103e6defcSWilliam A. Kennington III     uint8_t netfn = in[0] >> 2, lun = in[0] & 3, cmd = in[1];
9203e6defcSWilliam A. Kennington III     m.append(netfn, lun, cmd, in.subspan(2), options);
9303e6defcSWilliam A. Kennington III     outstanding = m.call_async(
940efeb17fSPatrick Williams         stdplus::exception::ignore([&outstanding, &kcs](message_t&& m) {
950efeb17fSPatrick Williams             outstanding = slot_t(nullptr);
9603e6defcSWilliam A. Kennington III             write(kcs, std::move(m));
9703e6defcSWilliam A. Kennington III         }));
9803e6defcSWilliam A. Kennington III }
9903e6defcSWilliam A. Kennington III 
10003e6defcSWilliam A. Kennington III } // namespace kcsbridge
101