1 #include "dump_utils.hpp"
2 
3 #include <phosphor-logging/elog-errors.hpp>
4 #include <phosphor-logging/elog.hpp>
5 #include <phosphor-logging/lg2.hpp>
6 #include <phosphor-logging/log.hpp>
7 #include <xyz/openbmc_project/Common/File/error.hpp>
8 
9 #include <format>
10 #include <fstream>
11 #include <string>
12 
13 namespace openpower::dump::util
14 {
15 using namespace phosphor::logging;
16 
17 static void monitorDumpCreation(const std::string& path, const uint32_t timeout)
18 {
19     bool inProgress = true;
20     auto bus = sdbusplus::bus::new_system();
21     auto match = sdbusplus::bus::match_t(
22         bus,
23         sdbusplus::bus::match::rules::propertiesChanged(
24             path, "xyz.openbmc_project.Common.Progress"),
25         [&](sdbusplus::message_t& msg) {
26             std::string interface;
27             std::map<std::string, std::variant<std::string, uint8_t>> property;
28             msg.read(interface, property);
29 
30             const auto dumpStatus = property.find("Status");
31             if (dumpStatus != property.end())
32             {
33                 const std::string* status =
34                     std::get_if<std::string>(&(dumpStatus->second));
35                 if (status &&
36                     *status !=
37                         "xyz.openbmc_project.Common.Progress.OperationStatus.InProgress")
38                 {
39                     lg2::info("Dump status({STATUS}) : path={PATH}", "STATUS",
40                               status->c_str(), "PATH", path.c_str());
41                     inProgress = false;
42                 }
43             }
44         });
45 
46     // Timeout management
47     for (uint32_t secondsCount = 0; inProgress && secondsCount < timeout;
48          ++secondsCount)
49     {
50         bus.wait(std::chrono::seconds(1));
51         bus.process_discard();
52     }
53 
54     if (inProgress)
55     {
56         lg2::error("Dump progress timeout; dump may not be complete.");
57     }
58 }
59 
60 void requestSBEDump(const uint32_t failingUnit, const uint32_t eid,
61                     SBETypes sbeType)
62 {
63     lg2::info(
64         "Requesting Dump PEL({EID}) chip({CHIPTYPE}) position({FAILINGUNIT})",
65         "EID", eid, "CHIPTYPE", sbeTypeAttributes.at(sbeType).chipName,
66         "FAILINGUNIT", failingUnit);
67 
68     constexpr auto path = "/xyz/openbmc_project/dump/system";
69     auto dumpRequestType = sbeTypeAttributes.at(sbeType).dumpType;
70     constexpr auto interface = "xyz.openbmc_project.Dump.Create";
71     constexpr auto function = "CreateDump";
72 
73     try
74     {
75         auto bus = sdbusplus::bus::new_default();
76         auto service = getService(bus, interface, path);
77         auto method =
78             bus.new_method_call(service.c_str(), path, interface, function);
79 
80         std::unordered_map<std::string, std::variant<std::string, uint64_t>>
81             createParams = {
82                 {"com.ibm.Dump.Create.CreateParameters.DumpType",
83                  dumpRequestType},
84                 {"com.ibm.Dump.Create.CreateParameters.ErrorLogId",
85                  uint64_t(eid)},
86                 {"com.ibm.Dump.Create.CreateParameters.FailingUnitId",
87                  uint64_t(failingUnit)}};
88 
89         method.append(createParams);
90         sdbusplus::message::object_path reply;
91         bus.call(method).read(reply);
92 
93         monitorDumpCreation(reply.str, SBE_DUMP_TIMEOUT);
94     }
95     catch (const sdbusplus::exception_t& e)
96     {
97         lg2::error("D-Bus call createDump exception OBJPATH={OBJPATH}, "
98                    "INTERFACE={INTERFACE}, EXCEPTION={ERROR}",
99                    "OBJPATH", path, "INTERFACE", interface, "ERROR", e);
100         constexpr auto ERROR_DUMP_DISABLED =
101             "xyz.openbmc_project.Dump.Create.Error.Disabled";
102         if (e.name() == ERROR_DUMP_DISABLED)
103         {
104             // Dump is disabled, Skip the dump collection.
105             lg2::info("Dump is disabled unit({FAILINGUNIT}), "
106                       "skipping dump collection",
107                       "FAILINGUNIT", failingUnit);
108         }
109         else
110         {
111             throw;
112         }
113     }
114     catch (const std::exception& e)
115     {
116         throw e;
117     }
118 }
119 
120 std::string getService(sdbusplus::bus_t& bus, const std::string& intf,
121                        const std::string& path)
122 {
123     constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
124     constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
125     constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
126     try
127     {
128         auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
129                                           MAPPER_INTERFACE, "GetObject");
130 
131         mapper.append(path, std::vector<std::string>({intf}));
132 
133         auto mapperResponseMsg = bus.call(mapper);
134         std::map<std::string, std::vector<std::string>> mapperResponse;
135         mapperResponseMsg.read(mapperResponse);
136 
137         if (mapperResponse.empty())
138         {
139             lg2::error(
140                 "Empty mapper response for GetObject interface({INTERFACE}), "
141                 "path({PATH})",
142                 "INTERFACE", intf, "PATH", path);
143 
144             throw std::runtime_error("Empty mapper response for GetObject");
145         }
146         return mapperResponse.begin()->first;
147     }
148     catch (const sdbusplus::exception_t& ex)
149     {
150         lg2::error(
151             "Mapper call failed for GetObject errorMsg({ERROR}), path({PATH}),"
152             "interface({INTERFACE})",
153             "ERROR", ex, "PATH", path, "INTERFACE", intf);
154 
155         throw;
156     }
157 }
158 
159 } // namespace openpower::dump::util
160