blob: 119fdff29b59f09a65a891bba2e44f2f16435174 [file] [log] [blame]
Dhruvaraj Subhashchandran858d1aa2021-10-27 03:26:06 -05001extern "C"
2{
3#include <libpdbg.h>
4#include <libpdbg_sbe.h>
5}
6
7#include "sbe_consts.hpp"
8#include "sbe_dump_collector.hpp"
9
10#include <libphal.H>
11#include <sys/wait.h>
12#include <unistd.h>
13
Dhruvaraj Subhashchandrana699e312021-10-27 07:20:34 -050014#include <phosphor-logging/elog-errors.hpp>
Dhruvaraj Subhashchandran858d1aa2021-10-27 03:26:06 -050015#include <phosphor-logging/lg2.hpp>
16#include <phosphor-logging/log.hpp>
Dhruvaraj Subhashchandrana699e312021-10-27 07:20:34 -050017#include <sbe_consts.hpp>
18#include <xyz/openbmc_project/Common/File/error.hpp>
19#include <xyz/openbmc_project/Common/error.hpp>
Dhruvaraj Subhashchandran858d1aa2021-10-27 03:26:06 -050020
Dhruvaraj Subhashchandrana699e312021-10-27 07:20:34 -050021#include <cstdint>
22#include <filesystem>
Dhruvaraj Subhashchandran858d1aa2021-10-27 03:26:06 -050023#include <format>
Dhruvaraj Subhashchandrana699e312021-10-27 07:20:34 -050024#include <fstream>
Dhruvaraj Subhashchandran858d1aa2021-10-27 03:26:06 -050025#include <stdexcept>
26
27namespace openpower::dump::sbe_chipop
28{
29
30using namespace phosphor::logging;
31using namespace openpower::dump::SBE;
32
33void SbeDumpCollector::collectDump(uint8_t type, uint32_t id,
34 uint64_t failingUnit,
35 const std::filesystem::path& path)
36{
37 lg2::error("Starting dump collection: type:{TYPE} id:{ID} "
38 "failingUnit:{FAILINGUNIT}, path:{PATH}",
39 "TYPE", type, "ID", id, "FAILINGUNIT", failingUnit, "PATH",
40 path.string());
41
42 initializePdbg();
43
44 std::vector<struct pdbg_target*> targets;
45
46 struct pdbg_target* target = nullptr;
47 pdbg_for_each_class_target("proc", target)
48 {
49 if (pdbg_target_probe(target) != PDBG_TARGET_ENABLED ||
50 !openpower::phal::pdbg::isTgtFunctional(target))
51 {
52 continue;
53 }
54
55 targets.push_back(target);
56 }
57
58 std::vector<uint8_t> clockStates = {SBE_CLOCK_ON, SBE_CLOCK_OFF};
59 for (auto cstate : clockStates)
60 {
61 auto futures = spawnDumpCollectionProcesses(type, id, path, failingUnit,
62 cstate, targets);
63
64 // Wait for all asynchronous tasks to complete
65 for (auto& future : futures)
66 {
Dhruvaraj Subhashchandrana699e312021-10-27 07:20:34 -050067 try
68 {
69 future.wait();
70 }
71 catch (const std::exception& e)
72 {
73 lg2::error("Failed to collect dump from SBE ErrorMsg({ERROR})",
74 "ERROR", e);
75 }
Dhruvaraj Subhashchandran858d1aa2021-10-27 03:26:06 -050076 }
77 lg2::info(
78 "Dump collection completed for clock state({CSTATE}): type({TYPE}) "
79 "id({ID}) failingUnit({FAILINGUNIT}), path({PATH})",
80 "CSTATE", cstate, "TYPE", type, "ID", id, "FAILINGUNIT",
81 failingUnit, "PATH", path.string());
82 }
Dhruvaraj Subhashchandrana699e312021-10-27 07:20:34 -050083 if (std::filesystem::is_empty(path))
84 {
85 lg2::error("Failed to collect the dump");
86 throw std::runtime_error("Failed to collect the dump");
87 }
Dhruvaraj Subhashchandran858d1aa2021-10-27 03:26:06 -050088 lg2::info("Dump collection completed");
89}
90
91void SbeDumpCollector::initializePdbg()
92{
93 openpower::phal::pdbg::init();
94}
95
96std::vector<std::future<void>> SbeDumpCollector::spawnDumpCollectionProcesses(
97 uint8_t type, uint32_t id, const std::filesystem::path& path,
98 uint64_t failingUnit, uint8_t cstate,
99 const std::vector<struct pdbg_target*>& targets)
100{
101 std::vector<std::future<void>> futures;
102
103 for (auto target : targets)
104 {
105 if (pdbg_target_probe(target) != PDBG_TARGET_ENABLED ||
106 !openpower::phal::pdbg::isTgtFunctional(target))
107 {
108 continue;
109 }
110
Dhruvaraj Subhashchandran858d1aa2021-10-27 03:26:06 -0500111 auto future =
112 std::async(std::launch::async,
113 [this, target, path, id, type, cstate, failingUnit]() {
Dhruvaraj Subhashchandrana699e312021-10-27 07:20:34 -0500114 try
115 {
116 this->collectDumpFromSBE(target, path, id, type, cstate,
117 failingUnit);
118 }
119 catch (const std::exception& e)
120 {
121 lg2::error(
122 "Failed to collect dump from SBE on Proc-({PROCINDEX})",
123 "PROCINDEX", pdbg_target_index(target));
124 }
Dhruvaraj Subhashchandran858d1aa2021-10-27 03:26:06 -0500125 });
126
127 futures.push_back(std::move(future));
128 }
129
130 return futures;
131}
132
133void SbeDumpCollector::collectDumpFromSBE(struct pdbg_target* chip,
134 const std::filesystem::path& path,
135 uint32_t id, uint8_t type,
136 uint8_t clockState,
137 uint64_t failingUnit)
138{
139 auto chipPos = pdbg_target_index(chip);
140 lg2::info(
141 "Collecting dump from proc({PROC}): path({PATH}) id({ID}) "
142 "type({TYPE}) clockState({CLOCKSTATE}) failingUnit({FAILINGUNIT})",
143 "PROC", chipPos, "PATH", path.string(), "ID", id, "TYPE", type,
144 "CLOCKSTATE", clockState, "FAILINGUNIT", failingUnit);
Dhruvaraj Subhashchandrana699e312021-10-27 07:20:34 -0500145
146 util::DumpDataPtr dataPtr;
147 uint32_t len = 0;
148 uint8_t collectFastArray =
149 checkFastarrayCollectionNeeded(clockState, type, failingUnit, chipPos);
150
151 try
152 {
153 openpower::phal::sbe::getDump(chip, type, clockState, collectFastArray,
154 dataPtr.getPtr(), &len);
155 }
156 catch (const openpower::phal::sbeError_t& sbeError)
157 {
158 if (sbeError.errType() ==
159 openpower::phal::exception::SBE_CHIPOP_NOT_ALLOWED)
160 {
161 // SBE is not ready to accept chip-ops,
162 // Skip the request, no additional error handling required.
163 lg2::info("Collect dump: Skipping ({ERROR}) dump({TYPE}) "
164 "on proc({PROC}) clock state({CLOCKSTATE})",
165 "ERROR", sbeError, "TYPE", type, "PROC", chipPos,
166 "CLOCKSTATE", clockState);
167 return;
168 }
169
170 lg2::error("Error in collecting dump dump type({TYPE}), "
171 "clockstate({CLOCKSTATE}), proc position({PROC}), "
172 "collectFastArray({COLLECTFASTARRAY}) error({ERROR})",
173 "TYPE", type, "CLOCKSTATE", clockState, "PROC", chipPos,
174 "COLLECTFASTARRAY", collectFastArray, "ERROR", sbeError);
175
176 return;
177 }
178 writeDumpFile(path, id, clockState, 0, "proc", chipPos, dataPtr, len);
179}
180
181void SbeDumpCollector::writeDumpFile(
182 const std::filesystem::path& path, const uint32_t id,
183 const uint8_t clockState, const uint8_t nodeNum, std::string chipName,
184 const uint8_t chipPos, util::DumpDataPtr& dataPtr, const uint32_t len)
185{
186 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
187 namespace fileError = sdbusplus::xyz::openbmc_project::Common::File::Error;
188
189 // Construct the filename
190 std::ostringstream filenameBuilder;
191 filenameBuilder << std::setw(8) << std::setfill('0') << id
192 << ".SbeDataClocks"
193 << (clockState == SBE_CLOCK_ON ? "On" : "Off") << ".node"
194 << static_cast<int>(nodeNum) << "." << chipName
195 << static_cast<int>(chipPos);
196
197 auto dumpPath = path / filenameBuilder.str();
198
199 // Attempt to open the file
200 std::ofstream outfile(dumpPath, std::ios::out | std::ios::binary);
201 if (!outfile)
202 {
203 using namespace sdbusplus::xyz::openbmc_project::Common::File::Error;
204 using metadata = xyz::openbmc_project::Common::File::Open;
205 // Unable to open the file for writing
206 auto err = errno;
207 lg2::error("Error opening file to write dump, "
208 "errno({ERRNO}), filepath({FILEPATH})",
209 "ERRNO", err, "FILEPATH", dumpPath.string());
210
211 report<Open>(metadata::ERRNO(err), metadata::PATH(dumpPath.c_str()));
212 // Just return here, so that the dumps collected from other
213 // SBEs can be packaged.
214 return;
215 }
216
217 // Write to the file
218 try
219 {
220 outfile.write(reinterpret_cast<const char*>(dataPtr.getData()), len);
221
222 lg2::info("Successfully wrote dump file "
223 "path=({PATH}) size=({SIZE})",
224 "PATH", dumpPath.string(), "SIZE", len);
225 }
226 catch (const std::ofstream::failure& oe)
227 {
228 using namespace sdbusplus::xyz::openbmc_project::Common::File::Error;
229 using metadata = xyz::openbmc_project::Common::File::Write;
230
231 lg2::error(
232 "Failed to write to dump file, "
233 "errorMsg({ERROR}), error({ERRORCODE}), filepath({FILEPATH})",
234 "ERROR", oe, "ERRORCODE", oe.code().value(), "FILEPATH",
235 dumpPath.string());
236 report<Write>(metadata::ERRNO(oe.code().value()),
237 metadata::PATH(dumpPath.c_str()));
238 // Just return here so dumps collected from other SBEs can be
239 // packaged.
240 }
Dhruvaraj Subhashchandran858d1aa2021-10-27 03:26:06 -0500241}
242
243} // namespace openpower::dump::sbe_chipop