1 #include <attn/attention.hpp>
2 #include <attn/attn_common.hpp>
3 #include <attn/attn_dump.hpp>
4 #include <attn/attn_handler.hpp>
5 #include <attn/attn_logging.hpp>
6 #include <sdbusplus/bus.hpp>
7 #include <util/dbus.hpp>
8 #include <util/pdbg.hpp>
9 #include <util/pldm.hpp>
10 #include <util/trace.hpp>
11 
12 namespace attn
13 {
14 /*
15  * @brief Request SBE hreset and try to clear sbe attentions
16  *
17  * @param[in] sbeInstance - sbe instance to hreset (0 based)
18  *
19  * @return true if hreset is successful and attentions cleared
20  */
21 bool attemptSbeRecovery(int sbeInstance)
22 {
23     // attempt sbe hreset and attention interrupt clear
24     if (!util::pldm::hresetSbe(sbeInstance))
25     {
26         return false;
27     }
28 
29     trace::inf("hreset completed");
30 
31     // try to clear attention interrupts
32     clearAttnInterrupts();
33 
34     // loop through processors checking attention interrupts
35     bool recovered = true;
36     pdbg_target* procTarget;
37     pdbg_for_each_class_target("proc", procTarget)
38     {
39         // active processors only
40         if (PDBG_TARGET_ENABLED !=
41             pdbg_target_probe(util::pdbg::getPibTrgt(procTarget)))
42         {
43             continue;
44         }
45 
46         // get cfam is an fsi read
47         pdbg_target* fsiTarget = util::pdbg::getFsiTrgt(procTarget);
48         uint32_t int_val;
49 
50         // get attention interrupts on processor
51         if (RC_SUCCESS == fsi_read(fsiTarget, 0x100b, &int_val))
52         {
53             if (int_val & SBE_ATTN)
54             {
55                 trace::err("sbe attention did not clear");
56                 recovered = false;
57                 break;
58             }
59         }
60         else
61         {
62             // log cfam read error
63             trace::err("cfam read error");
64             recovered = false;
65             break;
66         }
67     }
68 
69     if (recovered)
70     {
71         trace::inf("sbe attention cleared");
72     }
73 
74     return recovered;
75 }
76 
77 /**
78  * @brief Check for active checkstop attention
79  *
80  * @param procInstance - proc to check for attentions
81  *
82  * @pre pdbg target associated with proc instance is enabled for fsi access
83  *
84  * @return true if checkstop acive false otherwise
85  * */
86 bool checkstopActive(int procInstance)
87 {
88     // get fsi target
89     char path[16];
90     sprintf(path, "/proc%d/fsi", procInstance);
91     pdbg_target* fsiTarget = pdbg_target_from_path(nullptr, path);
92     if (nullptr == fsiTarget)
93     {
94         trace::inf("fsi path or target not found");
95         return false;
96     }
97 
98     // check for active checkstop attention
99     int r;
100     uint32_t isr_val, isr_mask;
101 
102     isr_val = 0xffffffff;
103     r       = fsi_read(fsiTarget, 0x1007, &isr_val);
104     if ((RC_SUCCESS != r) || (0xffffffff == isr_val))
105     {
106         trace::err("cfam 1007 read error");
107         return false;
108     }
109 
110     isr_mask = 0xffffffff;
111     r        = fsi_read(fsiTarget, 0x100d, &isr_mask);
112     if ((RC_SUCCESS != r) || (0xffffffff == isr_mask))
113     {
114         trace::err("cfam 100d read error");
115         return false;
116     }
117 
118     return activeAttn(isr_val, isr_mask, CHECKSTOP_ATTN);
119 }
120 
121 /**
122  * @brief Handle SBE vital attention
123  *
124  * @param i_attention - attention object
125  *
126  * @return non-zero if attention was not successfully handled
127  */
128 int handleVital(Attention* i_attention)
129 {
130     trace::inf("vital handler started");
131 
132     // if vital handling disabled
133     if (false == (i_attention->getConfig()->getFlag(enVital)))
134     {
135         trace::inf("vital handling disabled");
136         return RC_NOT_HANDLED;
137     }
138 
139     // if power fault then we don't do anything
140     sleepSeconds(POWER_FAULT_WAIT);
141     if (util::dbus::powerFault())
142     {
143         trace::inf("power fault was reported");
144         return RC_SUCCESS;
145     }
146 
147     // if no checkstop and host is running
148     int instance =
149         pdbg_target_index(i_attention->getTarget()); // get processor number
150 
151     if (!checkstopActive(instance) &&
152         util::dbus::HostRunningState::Started == util::dbus::hostRunningState())
153     {
154         // attempt to recover the sbe
155         if (attemptSbeRecovery(instance))
156         {
157             eventVital(levelPelInfo);
158             return RC_SUCCESS;
159         }
160     }
161 
162     // host not running, checkstop active or recovery failed
163     auto pelId = eventVital(levelPelError);
164     requestDump(pelId, DumpParameters{0, DumpType::SBE});
165     util::dbus::transitionHost(util::dbus::HostState::Quiesce);
166 
167     return RC_SUCCESS;
168 }
169 
170 } // namespace attn
171