summaryrefslogtreecommitdiffstats
path: root/src/usr/scom/runtime/rt_scom.C
blob: eafc14790f3856bcdbce63d449079ed1bc8ae730 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/scom/runtime/rt_scom.C $                              */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2013,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

#include <devicefw/driverif.H>
#include <errl/errlentry.H>
#include <errl/errlmanager.H>
#include <scom/scomreasoncodes.H>
#include <scom/scomif.H>
#include <scom/runtime/rt_scomif.H>
#include <runtime/interface.h>
#include <runtime/rt_targeting.H>
#include <xscom/piberror.H>
#include <runtime/hbrt_utilities.H>

// Trace definition
extern trace_desc_t* g_trac_scom;

namespace SCOM
{

struct RcPibErrMap
{
    PIB::PibError        iv_Piberr;
    int                  iv_Common;
    int                  iv_Opal; // note : opal values taken from opal-api.h
};


const RcPibErrMap pibErrTbl[] =
{
        // 001
        PIB::PIB_RESOURCE_OCCUPIED,
        HBRT_RC_PIBERR_001_BUSY,
        -12,     // OPAL_XSCOM_BUSY

        // 002
        PIB::PIB_CHIPLET_OFFLINE,
        HBRT_RC_PIBERR_010_OFFLINE,
        -14,    // OPAL_XSCOM_CHIPLET_OFF

        // 003
        PIB::PIB_PARTIAL_GOOD,
        HBRT_RC_PIBERR_011_PGOOD,
        -25,    // OPAL_XSCOM_PARTIAL_GOOD

        // 004
        PIB::PIB_INVALID_ADDRESS,
        HBRT_RC_PIBERR_100_INVALIDADDR,
        -26,    // OPAL_XSCOM_ADDR_ERROR

        // 005
        PIB::PIB_CLOCK_ERROR,
        HBRT_RC_PIBERR_101_CLOCKERR,
        -27,    // OPAL_XSCOM_CLOCK_ERROR

        // 006
        PIB::PIB_PARITY_ERROR,
        HBRT_RC_PIBERR_110_PARITYERR,
        -28,    // OPAL_XSCOM_PARITY_ERROR

        // 007
        PIB::PIB_TIMEOUT,
        HBRT_RC_PIBERR_111_TIMEOUT,
        -29     // OPAL_XSCOM_TIMEOUT
};


/**
 * @brief Internal routine that translates a HBRT return code to a
 * PIB error code
 *
 * @param[in]   i_rc           HBRT return code,
 * @return      PibError,  PIB::PIB_NO_ERROR if not translatable
 *
 */
PIB::PibError HbrtScomRcToPibErr( int i_rc )
{
    int l_entryCnt = sizeof(pibErrTbl) / sizeof(RcPibErrMap);
    PIB::PibError l_rv = PIB::PIB_NO_ERROR;

    for // loop thru the xlate table
      ( int i = 0;
        i < l_entryCnt;
        i++ )
    {
        if // matching entry found
          ( pibErrTbl[i].iv_Common == i_rc )
        {
            // extract translation value
            l_rv = pibErrTbl[i].iv_Piberr;
            break;
        }
    }

    return( l_rv );
}


/**
 * @brief Internal routine that translates an OPAL return code to a
 * PIB error code
 *
 * @param[in]   i_rc           OPAL return code
 * @return      PibError,  PIB::PIB_NO_ERROR if not translatable
 */
PIB::PibError OpalRcToPibErr( int i_rc )
{
    int l_entryCnt = sizeof(pibErrTbl) / sizeof(RcPibErrMap);
    PIB::PibError l_rv = PIB::PIB_NO_ERROR;

    for // loop thru the xlate table
      ( int i = 0;
        i < l_entryCnt;
        i++ )
    {
        if // matching entry found
          ( pibErrTbl[i].iv_Opal == i_rc )
        {
            // extract translation value
            l_rv = pibErrTbl[i].iv_Piberr;
            break;
        }
    }

    return( l_rv );
}


/**
 * @brief Send the scom to the hypervisor
 *
 * @param[in]     i_opType    Operation type, see driverif.H
 * @param[in]     i_target    Scom target
 * @param[in]     i_scomAddr  Scom address
 * @param[in/out] io_buffer   Read: Pointer to output data storage
 *                            Write: Pointer to input data storage
 * @return  errlHndl_t
 */
errlHndl_t sendScomToHyp(DeviceFW::OperationType i_opType,
                         TARGETING::Target * i_target,
                         uint64_t i_scomAddr,
                         void * io_buffer)
{
    errlHndl_t l_err = nullptr;
    int l_hostRC = 0;

    do
    {
        // Convert target to something Sapphire understands
        RT_TARG::rtChipId_t target_id = 0;
        l_err = RT_TARG::getRtTarget(i_target,
                                    target_id);
        if(l_err)
        {
            break;
        }

        if(g_hostInterfaces != nullptr &&
        g_hostInterfaces->scom_read != nullptr &&
        g_hostInterfaces->scom_write != nullptr)
        {

            if(i_opType == DeviceFW::READ)
            {
                l_hostRC =
                    g_hostInterfaces->scom_read(target_id,
                                                i_scomAddr,
                                                io_buffer
                                            );
            }
            else if (i_opType == DeviceFW::WRITE)
            {
                l_hostRC =
                    g_hostInterfaces->scom_write(target_id,
                                                i_scomAddr,
                                                io_buffer
                                                );
            }

            if(l_hostRC)
            {
                TRACFCOMP(g_trac_scom,ERR_MRK
                    "Hypervisor scom read/write failed. "
                    "rc 0x%X target 0x%llX target_id 0x%llX addr 0x%llX r/w %d",
                    l_hostRC, get_huid(i_target), target_id, i_scomAddr, i_opType);

                // Use an unused bit in the 64-bit scom range to indicate
                //  read/write. Cannot use bit0 since that is part of an
                //  indirect address. Cannot use bit63 because that is a
                //  valid part of the address.
                uint64_t l_userdata2 = i_scomAddr;
                if(i_opType == DeviceFW::WRITE)
                {
                    l_userdata2 |= 0x4000000000000000;
                }

                // convert rc to error log
                /*@
                * @errortype
                * @moduleid     SCOM_RT_SEND_SCOM_TO_HYP
                * @reasoncode   SCOM_RUNTIME_HYP_ERR
                * @userdata1[0:31]   Hypervisor return code
                * @userdata2[32:63]  Chipid sent to Hyp
                * @userdata2[0:63]   SCOM address
                * @userdata2[1]      SCOM Op Type: 0=read, 1=write
                * @devdesc      Error from Hypervisor attempting SCOM
                */
                l_err = new ERRORLOG::ErrlEntry(
                                    ERRORLOG::ERRL_SEV_INFORMATIONAL,
                                    SCOM_RT_SEND_SCOM_TO_HYP,
                                    SCOM_RUNTIME_HYP_ERR,
                                    TWO_UINT32_TO_UINT64(
                                                    l_hostRC,
                                                    i_opType),
                                    l_userdata2);

                if (l_hostRC == HBRT_RC_CHANNEL_FAILURE)
                {
                    // Channel is dead so switch to using the FSP for
                    //  access
                    FSISCOM::switchToFspScomAccess(i_target);

                    // Callout the failing buffer chip
                    l_err->addHwCallout(i_target,
                                        HWAS::SRCI_PRIORITY_HIGH,
                                        HWAS::NO_DECONFIG,
                                        HWAS::GARD_NULL);
                }
                else
                {
                    // attempt to translate rc into a pib error assuming
                    //  the rc is in common format
                    int l_commonRc = l_hostRC;
                    PIB::PibError l_piberr = HbrtScomRcToPibErr( l_commonRc );

                    if // input was translated to a PIB error code
                        ( l_piberr != PIB::PIB_NO_ERROR )
                    {
                        // (translation was successful)
                        TRACFCOMP(g_trac_scom,ERR_MRK"RC to PIB Err: PIBERR 0x%X",l_piberr);
                    }

                    else if  // legacy opal
                        ( TARGETING::is_sapphire_load() )
                    {
                        // attempt to translate rc into a pib error assuming
                        //  the rc is in old opal format
                        // this preserves legacy behavior to avoid co-req/pre-req
                        l_piberr =  OpalRcToPibErr( l_hostRC );
                        TRACFCOMP(g_trac_scom,ERR_MRK"RC to PIB Err: OPAL 0x%X",l_piberr);
                    }

                    else if  // legacy phyp
                        ( TARGETING::is_phyp_load() )
                    {
                        // default to OFFLINE for now to trigger
                        // the multicast workaround in scom.C
                        l_piberr = PIB::PIB_CHIPLET_OFFLINE;
                        TRACFCOMP(g_trac_scom,ERR_MRK"RC to PIB Err: PIB_CHIPLET_OFFLINE");
                    }

                    PIB::addFruCallouts(i_target,
                                        l_piberr,
                                        i_scomAddr,
                                        l_err);
                }

                l_err->collectTrace( SCOM_COMP_NAME, 256);
                l_err->collectTrace( HBRT_TRACE_NAME, 256);
            }
        }
        else // Hypervisor interface not initialized
        {
            TRACFCOMP(g_trac_scom,ERR_MRK"Hypervisor scom interface not linked");
            /*@
            * @errortype
            * @moduleid     SCOM_RT_SEND_SCOM_TO_HYP
            * @reasoncode   SCOM_RUNTIME_INTERFACE_ERR
            * @userdata1    SCOM Op Type
            * @userdata2    SCOM address
            * @devdesc      SCOM runtime interface not linked.
            */
            l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_INFORMATIONAL,
                                            SCOM_RT_SEND_SCOM_TO_HYP,
                                            SCOM_RUNTIME_INTERFACE_ERR,
                                            i_opType,
                                            i_scomAddr);

            l_err->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE,
                                    HWAS::SRCI_PRIORITY_HIGH);
            l_err->collectTrace( SCOM_COMP_NAME, 256);
            l_err->collectTrace( HBRT_TRACE_NAME, 256);
        }

    } while(0);

    return l_err;
}

};  // end namespace SCOM
OpenPOWER on IntegriCloud