blob: 6113f5d5be22fbc60ba71a26a2e009139ad5e461 [file] [log] [blame]
Steve Foreman4f0d1de2021-09-20 14:06:32 -07001// Copyright 2022 Google LLC
Willy Tua2056e92021-10-10 13:36:16 -07002//
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.
Patrick Venturef085d912019-03-15 08:50:00 -070014
15#include "handler.hpp"
16
Patrick Ventured2037c62019-03-15 10:29:47 -070017#include "errors.hpp"
Patrick Venturec87de552020-05-20 20:25:39 -070018#include "handler_impl.hpp"
Patrick Ventureab650002019-03-16 09:08:47 -070019#include "util.hpp"
Patrick Ventured2037c62019-03-15 10:29:47 -070020
Willy Tu3b1b4272021-03-02 17:58:10 -080021#include <fcntl.h>
Patrick Ventured2037c62019-03-15 10:29:47 -070022#include <ipmid/api.h>
Willy Tu3b1b4272021-03-02 17:58:10 -080023#include <mtd/mtd-abi.h>
24#include <mtd/mtd-user.h>
25#include <sys/ioctl.h>
26#include <unistd.h>
Patrick Ventured2037c62019-03-15 10:29:47 -070027
Patrick Venturebb90d4f2019-03-15 13:42:06 -070028#include <cinttypes>
Patrick Ventured2037c62019-03-15 10:29:47 -070029#include <cstdio>
30#include <filesystem>
31#include <fstream>
Patrick Venture07f85152019-03-15 21:36:56 -070032#include <map>
33#include <nlohmann/json.hpp>
34#include <phosphor-logging/elog-errors.hpp>
Patrick Ventureaa374122019-03-15 15:09:10 -070035#include <phosphor-logging/log.hpp>
36#include <sdbusplus/bus.hpp>
Patrick Ventured2037c62019-03-15 10:29:47 -070037#include <sstream>
38#include <string>
William A. Kennington III29f35bc2020-11-03 23:30:31 -080039#include <string_view>
Patrick Ventured2037c62019-03-15 10:29:47 -070040#include <tuple>
Steve Foreman4f0d1de2021-09-20 14:06:32 -070041#include <variant>
Patrick Venture07f85152019-03-15 21:36:56 -070042#include <xyz/openbmc_project/Common/error.hpp>
Patrick Ventured2037c62019-03-15 10:29:47 -070043
Patrick Venturef085d912019-03-15 08:50:00 -070044#ifndef NCSI_IF_NAME
45#define NCSI_IF_NAME eth0
46#endif
47
48// To deal with receiving a string without quotes.
49#define QUOTE(name) #name
50#define STR(macro) QUOTE(macro)
51#define NCSI_IF_NAME_STR STR(NCSI_IF_NAME)
52
William A. Kennington III8d3d46a2021-07-13 12:35:35 -070053namespace ipmi
54{
55std::uint8_t getChannelByName(const std::string& chName);
56}
57
Patrick Venturef085d912019-03-15 08:50:00 -070058namespace google
59{
60namespace ipmi
61{
Patrick Ventured2037c62019-03-15 10:29:47 -070062namespace fs = std::filesystem;
Patrick Venture07f85152019-03-15 21:36:56 -070063using Json = nlohmann::json;
64using namespace phosphor::logging;
65using InternalFailure =
66 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Patrick Venturef085d912019-03-15 08:50:00 -070067
William A. Kennington IIIb69209b2021-07-13 13:22:24 -070068std::tuple<std::uint8_t, std::string>
69 Handler::getEthDetails(std::string intf) const
Patrick Venturef085d912019-03-15 08:50:00 -070070{
William A. Kennington IIIb69209b2021-07-13 13:22:24 -070071 if (intf.empty())
72 {
73 intf = NCSI_IF_NAME_STR;
74 }
75 return std::make_tuple(::ipmi::getChannelByName(intf), std::move(intf));
Patrick Venturef085d912019-03-15 08:50:00 -070076}
77
Patrick Ventured2037c62019-03-15 10:29:47 -070078std::int64_t Handler::getRxPackets(const std::string& name) const
79{
80 std::ostringstream opath;
81 opath << "/sys/class/net/" << name << "/statistics/rx_packets";
82 std::string path = opath.str();
83
84 // Minor sanity & security check (of course, I'm less certain if unicode
85 // comes into play here.
86 //
87 // Basically you can't easily inject ../ or /../ into the path below.
88 if (name.find("/") != std::string::npos)
89 {
90 std::fprintf(stderr, "Invalid or illegal name: '%s'\n", name.c_str());
Michael Shene5a06672022-06-20 05:08:32 +000091 throw IpmiException(::ipmi::ccInvalidFieldRequest);
Patrick Ventured2037c62019-03-15 10:29:47 -070092 }
93
94 std::error_code ec;
95 if (!fs::exists(path, ec))
96 {
97 std::fprintf(stderr, "Path: '%s' doesn't exist.\n", path.c_str());
Michael Shene5a06672022-06-20 05:08:32 +000098 throw IpmiException(::ipmi::ccInvalidFieldRequest);
Patrick Ventured2037c62019-03-15 10:29:47 -070099 }
100 // We're uninterested in the state of ec.
101
102 int64_t count = 0;
103 std::ifstream ifs;
104 ifs.exceptions(std::ifstream::failbit);
105 try
106 {
107 ifs.open(path);
108 ifs >> count;
109 }
110 catch (std::ios_base::failure& fail)
111 {
Michael Shene5a06672022-06-20 05:08:32 +0000112 throw IpmiException(::ipmi::ccUnspecifiedError);
Patrick Ventured2037c62019-03-15 10:29:47 -0700113 }
114
115 return count;
116}
117
Patrick Venturebb90d4f2019-03-15 13:42:06 -0700118VersionTuple Handler::getCpldVersion(unsigned int id) const
119{
120 std::ostringstream opath;
121 opath << "/run/cpld" << id << ".version";
122 // Check for file
123
124 std::error_code ec;
125 if (!fs::exists(opath.str(), ec))
126 {
127 std::fprintf(stderr, "Path: '%s' doesn't exist.\n",
128 opath.str().c_str());
Michael Shene5a06672022-06-20 05:08:32 +0000129 throw IpmiException(::ipmi::ccInvalidFieldRequest);
Patrick Venturebb90d4f2019-03-15 13:42:06 -0700130 }
131 // We're uninterested in the state of ec.
132
133 // If file exists, read.
134 std::ifstream ifs;
135 ifs.exceptions(std::ifstream::failbit);
136 std::string value;
137 try
138 {
139 ifs.open(opath.str());
140 ifs >> value;
141 }
142 catch (std::ios_base::failure& fail)
143 {
Michael Shene5a06672022-06-20 05:08:32 +0000144 throw IpmiException(::ipmi::ccUnspecifiedError);
Patrick Venturebb90d4f2019-03-15 13:42:06 -0700145 }
146
147 // If value parses as expected, return version.
148 VersionTuple version = std::make_tuple(0, 0, 0, 0);
149
150 int num_fields =
151 std::sscanf(value.c_str(), "%" SCNu8 ".%" SCNu8 ".%" SCNu8 ".%" SCNu8,
152 &std::get<0>(version), &std::get<1>(version),
153 &std::get<2>(version), &std::get<3>(version));
154 if (num_fields == 0)
155 {
156 std::fprintf(stderr, "Invalid version.\n");
Michael Shene5a06672022-06-20 05:08:32 +0000157 throw IpmiException(::ipmi::ccUnspecifiedError);
Patrick Venturebb90d4f2019-03-15 13:42:06 -0700158 }
159
160 return version;
161}
162
Patrick Ventureaa374122019-03-15 15:09:10 -0700163static constexpr auto TIME_DELAY_FILENAME = "/run/psu_timedelay";
164static constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
165static constexpr auto SYSTEMD_ROOT = "/org/freedesktop/systemd1";
166static constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
167static constexpr auto PSU_HARDRESET_TARGET = "gbmc-psu-hardreset.target";
168
169void Handler::psuResetDelay(std::uint32_t delay) const
170{
Patrick Ventureaa374122019-03-15 15:09:10 -0700171 std::ofstream ofs;
172 ofs.open(TIME_DELAY_FILENAME, std::ofstream::out);
173 if (!ofs.good())
174 {
175 std::fprintf(stderr, "Unable to open file for output.\n");
Michael Shene5a06672022-06-20 05:08:32 +0000176 throw IpmiException(::ipmi::ccUnspecifiedError);
Patrick Ventureaa374122019-03-15 15:09:10 -0700177 }
178
179 ofs << "PSU_HARDRESET_DELAY=" << delay << std::endl;
180 if (ofs.fail())
181 {
182 std::fprintf(stderr, "Write failed\n");
183 ofs.close();
Michael Shene5a06672022-06-20 05:08:32 +0000184 throw IpmiException(::ipmi::ccUnspecifiedError);
Patrick Ventureaa374122019-03-15 15:09:10 -0700185 }
186
187 // Write succeeded, please continue.
188 ofs.flush();
189 ofs.close();
190
191 auto bus = sdbusplus::bus::new_default();
192 auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT,
193 SYSTEMD_INTERFACE, "StartUnit");
194
195 method.append(PSU_HARDRESET_TARGET);
196 method.append("replace");
197
198 try
199 {
200 bus.call_noreply(method);
201 }
202 catch (const sdbusplus::exception::SdBusError& ex)
203 {
204 log<level::ERR>("Failed to call PSU hard reset");
Michael Shene5a06672022-06-20 05:08:32 +0000205 throw IpmiException(::ipmi::ccUnspecifiedError);
Patrick Ventureaa374122019-03-15 15:09:10 -0700206 }
207}
208
Shounak Mitraac4a16f2021-02-02 11:11:44 -0800209static constexpr auto RESET_ON_SHUTDOWN_FILENAME = "/run/powercycle_on_s5";
210
211void Handler::psuResetOnShutdown() const
212{
213 std::ofstream ofs;
214 ofs.open(RESET_ON_SHUTDOWN_FILENAME, std::ofstream::out);
215 if (!ofs.good())
216 {
217 std::fprintf(stderr, "Unable to open file for output.\n");
Michael Shene5a06672022-06-20 05:08:32 +0000218 throw IpmiException(::ipmi::ccUnspecifiedError);
Shounak Mitraac4a16f2021-02-02 11:11:44 -0800219 }
220 ofs.close();
221}
222
Willy Tu3b1b4272021-03-02 17:58:10 -0800223uint32_t Handler::getFlashSize()
224{
225 mtd_info_t info;
226 int fd = open("/dev/mtd0", O_RDONLY);
227 int err = ioctl(fd, MEMGETINFO, &info);
228 close(fd);
229
230 if (err)
231 {
Michael Shene5a06672022-06-20 05:08:32 +0000232 throw IpmiException(::ipmi::ccUnspecifiedError);
Willy Tu3b1b4272021-03-02 17:58:10 -0800233 }
234 return info.size;
235}
236
Patrick Ventureab650002019-03-16 09:08:47 -0700237std::string Handler::getEntityName(std::uint8_t id, std::uint8_t instance)
Patrick Venture07f85152019-03-15 21:36:56 -0700238{
Patrick Ventureab650002019-03-16 09:08:47 -0700239 // Check if we support this Entity ID.
240 auto it = _entityIdToName.find(id);
241 if (it == _entityIdToName.end())
Patrick Venture07f85152019-03-15 21:36:56 -0700242 {
Patrick Ventureab650002019-03-16 09:08:47 -0700243 log<level::ERR>("Unknown Entity ID", entry("ENTITY_ID=%d", id));
Michael Shene5a06672022-06-20 05:08:32 +0000244 throw IpmiException(::ipmi::ccInvalidFieldRequest);
Patrick Venture07f85152019-03-15 21:36:56 -0700245 }
246
Patrick Ventureab650002019-03-16 09:08:47 -0700247 std::string entityName;
248 try
Patrick Venture07f85152019-03-15 21:36:56 -0700249 {
Patrick Ventureab650002019-03-16 09:08:47 -0700250 // Parse the JSON config file.
251 if (!_entityConfigParsed)
252 {
253 _entityConfig = parseConfig(_configFile);
254 _entityConfigParsed = true;
255 }
256
257 // Find the "entity id:entity instance" mapping to entity name.
258 entityName = readNameFromConfig(it->second, instance, _entityConfig);
259 if (entityName.empty())
260 {
Michael Shene5a06672022-06-20 05:08:32 +0000261 throw IpmiException(::ipmi::ccInvalidFieldRequest);
Patrick Ventureab650002019-03-16 09:08:47 -0700262 }
263 }
264 catch (InternalFailure& e)
265 {
Michael Shene5a06672022-06-20 05:08:32 +0000266 throw IpmiException(::ipmi::ccUnspecifiedError);
Patrick Venture07f85152019-03-15 21:36:56 -0700267 }
268
Patrick Ventureab650002019-03-16 09:08:47 -0700269 return entityName;
Patrick Venture07f85152019-03-15 21:36:56 -0700270}
271
William A. Kennington III29f35bc2020-11-03 23:30:31 -0800272std::string Handler::getMachineName()
273{
274 const char* path = "/etc/os-release";
275 std::ifstream ifs(path);
276 if (ifs.fail())
277 {
278 std::fprintf(stderr, "Failed to open: %s\n", path);
Michael Shene5a06672022-06-20 05:08:32 +0000279 throw IpmiException(::ipmi::ccUnspecifiedError);
William A. Kennington III29f35bc2020-11-03 23:30:31 -0800280 }
281
282 std::string line;
283 while (true)
284 {
285 std::getline(ifs, line);
286 if (ifs.eof())
287 {
288 std::fprintf(stderr, "Failed to find OPENBMC_TARGET_MACHINE: %s\n",
289 path);
Michael Shene5a06672022-06-20 05:08:32 +0000290 throw IpmiException(::ipmi::ccInvalidCommand);
William A. Kennington III29f35bc2020-11-03 23:30:31 -0800291 }
292 if (ifs.fail())
293 {
294 std::fprintf(stderr, "Failed to read: %s\n", path);
Michael Shene5a06672022-06-20 05:08:32 +0000295 throw IpmiException(::ipmi::ccUnspecifiedError);
William A. Kennington III29f35bc2020-11-03 23:30:31 -0800296 }
297 std::string_view lineView(line);
298 constexpr std::string_view prefix = "OPENBMC_TARGET_MACHINE=";
299 if (lineView.substr(0, prefix.size()) != prefix)
300 {
301 continue;
302 }
303 lineView.remove_prefix(prefix.size());
304 lineView.remove_prefix(
305 std::min(lineView.find_first_not_of('"'), lineView.size()));
306 lineView.remove_suffix(
307 lineView.size() - 1 -
308 std::min(lineView.find_last_not_of('"'), lineView.size() - 1));
309 return std::string(lineView);
310 }
311}
312
linyuny8cfa4c42021-06-16 13:53:08 -0700313static constexpr auto HOST_TIME_DELAY_FILENAME = "/run/host_poweroff_delay";
314static constexpr auto HOST_POWEROFF_TARGET = "gbmc-host-poweroff.target";
315
316void Handler::hostPowerOffDelay(std::uint32_t delay) const
317{
318 // Set time delay
319 std::ofstream ofs;
320 ofs.open(HOST_TIME_DELAY_FILENAME, std::ofstream::out);
321 if (!ofs.good())
322 {
323 std::fprintf(stderr, "Unable to open file for output.\n");
Michael Shene5a06672022-06-20 05:08:32 +0000324 throw IpmiException(::ipmi::ccUnspecifiedError);
linyuny8cfa4c42021-06-16 13:53:08 -0700325 }
326
327 ofs << "HOST_POWEROFF_DELAY=" << delay << std::endl;
328 ofs.close();
329 if (ofs.fail())
330 {
331 std::fprintf(stderr, "Write failed\n");
Michael Shene5a06672022-06-20 05:08:32 +0000332 throw IpmiException(::ipmi::ccUnspecifiedError);
linyuny8cfa4c42021-06-16 13:53:08 -0700333 }
334
335 // Write succeeded, please continue.
336 auto bus = sdbusplus::bus::new_default();
337 auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT,
338 SYSTEMD_INTERFACE, "StartUnit");
339
340 method.append(HOST_POWEROFF_TARGET);
341 method.append("replace");
342
343 try
344 {
345 bus.call_noreply(method);
346 }
347 catch (const sdbusplus::exception::SdBusError& ex)
348 {
349 log<level::ERR>("Failed to call Power Off",
350 entry("WHAT=%s", ex.what()));
Michael Shene5a06672022-06-20 05:08:32 +0000351 throw IpmiException(::ipmi::ccUnspecifiedError);
linyuny8cfa4c42021-06-16 13:53:08 -0700352 }
353}
354
Patrick Ventureab650002019-03-16 09:08:47 -0700355std::string readNameFromConfig(const std::string& type, uint8_t instance,
356 const Json& config)
Patrick Venture07f85152019-03-15 21:36:56 -0700357{
358 static const std::vector<Json> empty{};
359 std::vector<Json> readings = config.value(type, empty);
360 std::string name = "";
Patrick Ventureab650002019-03-16 09:08:47 -0700361
Patrick Venture07f85152019-03-15 21:36:56 -0700362 for (const auto& j : readings)
363 {
364 uint8_t instanceNum = j.value("instance", 0);
365 // Not the instance we're interested in
366 if (instanceNum != instance)
367 {
368 continue;
369 }
370
371 // Found the instance we're interested in
372 name = j.value("name", "");
373
374 break;
375 }
Patrick Ventureab650002019-03-16 09:08:47 -0700376
Patrick Venture07f85152019-03-15 21:36:56 -0700377 return name;
378}
379
Patrick Venture49f23ad2019-03-16 11:59:55 -0700380void Handler::buildI2cPcieMapping()
381{
382 _pcie_i2c_map = buildPcieMap();
383}
384
385size_t Handler::getI2cPcieMappingSize() const
386{
387 return _pcie_i2c_map.size();
388}
389
390std::tuple<std::uint32_t, std::string>
391 Handler::getI2cEntry(unsigned int entry) const
392{
393 return _pcie_i2c_map[entry];
394}
395
Steve Foreman4f0d1de2021-09-20 14:06:32 -0700396namespace
397{
398
399static constexpr std::string_view ACCEL_OOB_ROOT = "/com/google/customAccel/";
400static constexpr char ACCEL_OOB_SERVICE[] = "com.google.custom_accel";
401static constexpr char ACCEL_OOB_INTERFACE[] = "com.google.custom_accel.BAR";
402
403// C type for "a{oa{sa{sv}}}" from DBus.ObjectManager::GetManagedObjects()
404using AnyType = std::variant<std::string, uint8_t, uint32_t, uint64_t>;
405using AnyTypeList = std::vector<std::pair<std::string, AnyType>>;
406using NamedArrayOfAnyTypeLists =
407 std::vector<std::pair<std::string, AnyTypeList>>;
408using ArrayOfObjectPathsAndTieredAnyTypeLists = std::vector<
409 std::pair<sdbusplus::message::object_path, NamedArrayOfAnyTypeLists>>;
410
411} // namespace
412
Michael Shen0e928ac2022-06-20 05:21:52 +0000413sdbusplus::bus::bus Handler::getDbus() const
Steve Foreman4f0d1de2021-09-20 14:06:32 -0700414{
415 return sdbusplus::bus::new_default();
416}
417
418uint32_t Handler::accelOobDeviceCount() const
419{
420 ArrayOfObjectPathsAndTieredAnyTypeLists data;
421
422 try
423 {
Michael Shen0e928ac2022-06-20 05:21:52 +0000424 auto bus = getDbus();
Steve Foreman4f0d1de2021-09-20 14:06:32 -0700425 auto method = bus.new_method_call(ACCEL_OOB_SERVICE, "/",
426 "org.freedesktop.DBus.ObjectManager",
427 "GetManagedObjects");
428 bus.call(method).read(data);
429 }
430 catch (const sdbusplus::exception::SdBusError& ex)
431 {
432 log<level::ERR>(
433 "Failed to call GetManagedObjects on com.google.custom_accel",
434 entry("WHAT=%s", ex.what()));
Michael Shene5a06672022-06-20 05:08:32 +0000435 throw IpmiException(::ipmi::ccUnspecifiedError);
Steve Foreman4f0d1de2021-09-20 14:06:32 -0700436 }
437
438 return data.size();
439}
440
441std::string Handler::accelOobDeviceName(size_t index) const
442{
443 ArrayOfObjectPathsAndTieredAnyTypeLists data;
444
445 try
446 {
Michael Shen0e928ac2022-06-20 05:21:52 +0000447 auto bus = getDbus();
Steve Foreman4f0d1de2021-09-20 14:06:32 -0700448 auto method = bus.new_method_call(ACCEL_OOB_SERVICE, "/",
449 "org.freedesktop.DBus.ObjectManager",
450 "GetManagedObjects");
451 bus.call(method).read(data);
452 }
453 catch (const sdbusplus::exception::SdBusError& ex)
454 {
455 log<level::ERR>(
456 "Failed to call GetManagedObjects on com.google.custom_accel",
457 entry("WHAT=%s", ex.what()));
Michael Shene5a06672022-06-20 05:08:32 +0000458 throw IpmiException(::ipmi::ccUnspecifiedError);
Steve Foreman4f0d1de2021-09-20 14:06:32 -0700459 }
460
461 if (index >= data.size())
462 {
463 log<level::WARNING>(
464 "Requested index is larger than the number of entries.",
465 entry("INDEX=%zu", index), entry("NUM_NAMES=%zu", data.size()));
Michael Shene5a06672022-06-20 05:08:32 +0000466 throw IpmiException(::ipmi::ccParmOutOfRange);
Steve Foreman4f0d1de2021-09-20 14:06:32 -0700467 }
468
469 std::string_view name(data[index].first.str);
470 if (!name.starts_with(ACCEL_OOB_ROOT))
471 {
Michael Shene5a06672022-06-20 05:08:32 +0000472 throw IpmiException(::ipmi::ccInvalidCommand);
Steve Foreman4f0d1de2021-09-20 14:06:32 -0700473 }
474 name.remove_prefix(ACCEL_OOB_ROOT.length());
475 return std::string(name);
476}
477
478uint64_t Handler::accelOobRead(std::string_view name, uint64_t address,
479 uint8_t num_bytes) const
480{
481 static constexpr char ACCEL_OOB_METHOD[] = "Read";
482
483 std::string object_name(ACCEL_OOB_ROOT);
484 object_name.append(name);
485
Michael Shen0e928ac2022-06-20 05:21:52 +0000486 auto bus = getDbus();
Steve Foreman4f0d1de2021-09-20 14:06:32 -0700487 auto method = bus.new_method_call(ACCEL_OOB_SERVICE, object_name.c_str(),
488 ACCEL_OOB_INTERFACE, ACCEL_OOB_METHOD);
489 method.append(address, static_cast<uint64_t>(num_bytes));
490
491 std::vector<uint8_t> bytes;
492
493 try
494 {
495 bus.call(method).read(bytes);
496 }
497 catch (const sdbusplus::exception::SdBusError& ex)
498 {
499 log<level::ERR>("Failed to call Read on com.google.custom_accel",
500 entry("WHAT=%s", ex.what()),
501 entry("DBUS_SERVICE=%s", ACCEL_OOB_SERVICE),
502 entry("DBUS_OBJECT=%s", object_name.c_str()),
503 entry("DBUS_INTERFACE=%s", ACCEL_OOB_INTERFACE),
504 entry("DBUS_METHOD=%s", ACCEL_OOB_METHOD),
505 entry("DBUS_ARG_ADDRESS=%016llx", address),
506 entry("DBUS_ARG_NUM_BYTES=%zu", (size_t)num_bytes));
Michael Shene5a06672022-06-20 05:08:32 +0000507 throw IpmiException(::ipmi::ccUnspecifiedError);
Steve Foreman4f0d1de2021-09-20 14:06:32 -0700508 }
509
510 if (bytes.size() < num_bytes)
511 {
512 log<level::ERR>(
513 "Call to Read on com.google.custom_accel didn't return the expected"
514 " number of bytes.",
515 entry("DBUS_SERVICE=%s", ACCEL_OOB_SERVICE),
516 entry("DBUS_OBJECT=%s", object_name.c_str()),
517 entry("DBUS_INTERFACE=%s", ACCEL_OOB_INTERFACE),
518 entry("DBUS_METHOD=%s", ACCEL_OOB_METHOD),
519 entry("DBUS_ARG_ADDRESS=%016llx", address),
520 entry("DBUS_ARG_NUM_BYTES=%zu", (size_t)num_bytes),
521 entry("DBUS_RETURN_SIZE=%zu", bytes.size()));
Michael Shene5a06672022-06-20 05:08:32 +0000522 throw IpmiException(::ipmi::ccUnspecifiedError);
Steve Foreman4f0d1de2021-09-20 14:06:32 -0700523 }
524
525 if (bytes.size() > sizeof(uint64_t))
526 {
527 log<level::ERR>(
528 "Call to Read on com.google.custom_accel returned more than 8B.",
529 entry("DBUS_SERVICE=%s", ACCEL_OOB_SERVICE),
530 entry("DBUS_OBJECT=%s", object_name.c_str()),
531 entry("DBUS_INTERFACE=%s", ACCEL_OOB_INTERFACE),
532 entry("DBUS_METHOD=%s", ACCEL_OOB_METHOD),
533 entry("DBUS_ARG_ADDRESS=%016llx", address),
534 entry("DBUS_ARG_NUM_BYTES=%zu", (size_t)num_bytes),
535 entry("DBUS_RETURN_SIZE=%zu", bytes.size()));
Michael Shene5a06672022-06-20 05:08:32 +0000536 throw IpmiException(::ipmi::ccReqDataTruncated);
Steve Foreman4f0d1de2021-09-20 14:06:32 -0700537 }
538
539 uint64_t data = 0;
540 for (size_t i = 0; i < num_bytes; ++i)
541 {
542 data = (data << 8) | bytes[i];
543 }
544
545 return data;
546}
547
548void Handler::accelOobWrite(std::string_view name, uint64_t address,
549 uint8_t num_bytes, uint64_t data) const
550{
551 static constexpr std::string_view ACCEL_OOB_METHOD = "Write";
552
553 std::string object_name(ACCEL_OOB_ROOT);
554 object_name.append(name);
555
556 if (num_bytes > sizeof(data))
557 {
558 log<level::ERR>(
559 "Call to Write on com.google.custom_accel requested more than 8B.",
560 entry("DBUS_SERVICE=%s", ACCEL_OOB_SERVICE),
561 entry("DBUS_OBJECT=%s", object_name.c_str()),
562 entry("DBUS_INTERFACE=%s", ACCEL_OOB_INTERFACE),
563 entry("DBUS_METHOD=%s", ACCEL_OOB_METHOD.data()),
564 entry("DBUS_ARG_ADDRESS=%016llx", address),
565 entry("DBUS_ARG_NUM_BYTES=%zu", (size_t)num_bytes),
566 entry("DBUS_ARG_DATA=%016llx", data));
Michael Shene5a06672022-06-20 05:08:32 +0000567 throw IpmiException(::ipmi::ccParmOutOfRange);
Steve Foreman4f0d1de2021-09-20 14:06:32 -0700568 }
569
570 std::vector<uint8_t> bytes;
571 bytes.reserve(num_bytes);
572 for (size_t i = 0; i < num_bytes; ++i)
573 {
574 bytes.emplace_back(data & 0xff);
575 data >>= 8;
576 }
577
578 try
579 {
Michael Shen0e928ac2022-06-20 05:21:52 +0000580 auto bus = getDbus();
Steve Foreman4f0d1de2021-09-20 14:06:32 -0700581 auto method =
582 bus.new_method_call(ACCEL_OOB_SERVICE, object_name.c_str(),
583 ACCEL_OOB_INTERFACE, ACCEL_OOB_METHOD.data());
584 method.append(address, bytes);
585 bus.call_noreply(method);
586 }
587 catch (const sdbusplus::exception::SdBusError& ex)
588 {
589 log<level::ERR>("Failed to call Write on com.google.custom_accel",
590 entry("WHAT=%s", ex.what()),
591 entry("DBUS_SERVICE=%s", ACCEL_OOB_SERVICE),
592 entry("DBUS_OBJECT=%s", object_name.c_str()),
593 entry("DBUS_INTERFACE=%s", ACCEL_OOB_INTERFACE),
594 entry("DBUS_METHOD=%s", ACCEL_OOB_METHOD.data()),
595 entry("DBUS_ARG_ADDRESS=%016llx", address),
596 entry("DBUS_ARG_NUM_BYTES=%zu", (size_t)num_bytes),
597 entry("DBUS_ARG_DATA=%016llx", data));
Michael Shene5a06672022-06-20 05:08:32 +0000598 throw IpmiException(::ipmi::ccUnspecifiedError);
Steve Foreman4f0d1de2021-09-20 14:06:32 -0700599 }
600}
601
Willy Tu6c71b0f2021-10-10 13:34:41 -0700602std::vector<uint8_t> Handler::pcieBifurcation(uint8_t index)
603{
604 return bifurcationHelper.get().getBifurcation(index).value_or(
605 std::vector<uint8_t>{});
606}
607
Patrick Venturef085d912019-03-15 08:50:00 -0700608} // namespace ipmi
609} // namespace google