summaryrefslogtreecommitdiffstats
path: root/src/usr/ibscom/ibscom.C
blob: 874f8f98c0b78cd5aa2ef806de308358fdd4d745 (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
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/ibscom/ibscom.C $                                     */
/*                                                                        */
/* IBM CONFIDENTIAL                                                       */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 2012,2013              */
/*                                                                        */
/* p1                                                                     */
/*                                                                        */
/* Object Code Only (OCO) source materials                                */
/* Licensed Internal Code Source Materials                                */
/* IBM HostBoot Licensed Internal Code                                    */
/*                                                                        */
/* The source code for this program is not published or otherwise         */
/* divested of its trade secrets, irrespective of what has been           */
/* deposited with the U.S. Copyright Office.                              */
/*                                                                        */
/* Origin: 30                                                             */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

/*****************************************************************************/
// I n c l u d e s
/*****************************************************************************/
#include <sys/mmio.h>
#include <sys/task.h>
#include <sys/sync.h>
#include <sys/misc.h>
#include <string.h>
#include <devicefw/driverif.H>
#include <trace/interface.H>
#include <errl/errlentry.H>
#include <errl/errlmanager.H>
#include <errl/errludlogregister.H>
#include <targeting/common/targetservice.H>
#include <ibscom/ibscomreasoncodes.H>
#include "ibscom.H"
#include <assert.h>
#include <limits.h>
#include <errl/errludtarget.H>
#include <xscom/piberror.H>

// Easy macro replace for unit testing
//#define TRACUCOMP(args...)  TRACFCOMP(args)
#define TRACUCOMP(args...)

// Trace definition
trace_desc_t* g_trac_ibscom = NULL;
TRAC_INIT(&g_trac_ibscom, "IBSCOM", KILOBYTE);

using namespace ERRORLOG;
using namespace TARGETING;

namespace IBSCOM
{

// Register XSCcom access functions to DD framework
DEVICE_REGISTER_ROUTE(DeviceFW::WILDCARD,
                      DeviceFW::IBSCOM,
                      TYPE_MEMBUF,
                      ibscomPerformOp);

/**
 * @brief Internal routine that verifies the validity of input parameters
 * for an inband scom access.
 *
 * @param[in]   i_opType       Operation type, see DeviceFW::OperationType
 *                             in driverif.H
 * @param[in]   i_target       inband scom target
 * @param[in] i_buffer         Read: Pointer to output data storage
 *                             Write: Pointer to input data storage
 * @param[in] i_buflen         Input: size of io_buffer (in bytes)
 * @param[in] i_addr           Address being accessed (Used for FFDC)
 * @return  errlHndl_t
 */
errlHndl_t ibscomOpSanityCheck(const DeviceFW::OperationType i_opType,
                              const Target* i_target,
                              const void* i_buffer,
                              const size_t& i_buflen,
                              const uint64_t i_addr)
{
    errlHndl_t l_err = NULL;
    TRACDCOMP(g_trac_ibscom, INFO_MRK
              ">>ibscomOpSanityCheck: Entering Function");

    do
    {
        // Verify address is somewhat valid (not over 32-bits long)
        if(0 != (i_addr & 0xFFFFFFFF00000000))
        {
            TRACFCOMP(g_trac_ibscom, ERR_MRK"ibscomOpSanityCheck: Impossible address.  i_addr=0x%.16X",
                      i_buflen);
            /*@
             * @errortype
             * @moduleid     IBSCOM_SANITY_CHECK
             * @reasoncode   IBSCOM_INVALID_ADDRESS
             * @userdata1    Inband Scom  address
             * @userdata2    <none>
             * @devdesc      The provided address is over 32 bits long
             *               which makes it invalid.
             */
            l_err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE,
                                  IBSCOM_SANITY_CHECK,
                                  IBSCOM_INVALID_ADDRESS,
                                  i_addr,
                                  0);
            l_err->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE,
                                       HWAS::SRCI_PRIORITY_HIGH);
            break;
        }

        // Verify data buffer
        if ( (i_buflen < IBSCOM_BUFFER_SIZE) ||
             (i_buffer == NULL) )
        {
            TRACFCOMP(g_trac_ibscom, ERR_MRK
                      "ibscomOpSanityCheck: Invalid buffer.  i_buflen=0x%X",
                      i_buflen);
            /*@
             * @errortype
             * @moduleid     IBSCOM_SANITY_CHECK
             * @reasoncode   IBSCOM_INVALID_DATA_BUFFER
             * @userdata1    Buffer size
             * @userdata2    Inband Scom  address
             * @devdesc      Inband  buffer size < 8 bytes or NULL
             *               data buffer
             */
            l_err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE,
                                  IBSCOM_SANITY_CHECK,
                                  IBSCOM_INVALID_DATA_BUFFER,
                                  i_buflen,
                                  i_addr);
            l_err->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE,
                                       HWAS::SRCI_PRIORITY_HIGH);
            break;
        }

        // Verify OP type
        if ( (i_opType != DeviceFW::READ) &&
             (i_opType != DeviceFW::WRITE) )
        {
            TRACFCOMP(g_trac_ibscom, ERR_MRK
                      "ibscomOpSanityCheck: Invalid opType.  i_opType=0x%X",
                      i_opType);
            /*@
             * @errortype
             * @moduleid     IBSCOM_SANITY_CHECK
             * @reasoncode   IBSCOM_INVALID_OP_TYPE
             * @userdata1    Operation type
             * @userdata2    inband scom address
             * @devdesc      inband scom invalid operation type
             */
            l_err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE,
                                  IBSCOM_SANITY_CHECK,
                                  IBSCOM_INVALID_OP_TYPE,
                                  i_opType,
                                  i_addr);
            l_err->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE,
                                       HWAS::SRCI_PRIORITY_HIGH);
            break;
        }


    } while(0);

    return l_err;
}

/**
 * @brief Get the virtual address of the input target
 *        for an inband scom access.
 *
 * Logic:
 * If never inband scom to this chip:
 *     Call mmio_dev_map() to get virtual addr for this slave proc
 *     Save virtual addr used to this chip's attribute
 * Else
 *     Use virtual address stored in this chip's attributes.
 * End if
 *
 * @param[in]   i_target        inband scom target
 * @param[out]  o_virtAddr      Target's virtual address
 *
 * @return errlHndl_t
 */
errlHndl_t getTargetVirtualAddress(Target* i_target,
                                   uint64_t*& o_virtAddr)
{
    errlHndl_t l_err = NULL;
    o_virtAddr = NULL;
    IBScomBase_t l_IBScomBaseAddr = 0;

    do
    {
        // Get the virtual addr value of the chip from attribute
        o_virtAddr =  reinterpret_cast<uint64_t*>
          (i_target->getAttr<ATTR_IBSCOM_VIRTUAL_ADDR>());

        // If the virtual address equals NULL(default) then this is the
        // first IBSCOM to this target so we need to allocate
        // the virtual address and save it in the xscom address attribute.
        if (o_virtAddr == NULL)
        {

            TRACDCOMP(g_trac_ibscom, INFO_MRK
                      "getTargetVirtualAddress: Need to compute virtual address for Centaur");

            //Get MMIO Offset from parent MCS attribute.

            //Get the parent MCS
            Target* parentMCS = NULL;

            PredicateCTM l_mcs(CLASS_UNIT,
                               TYPE_MCS,
                               MODEL_NA);

            TargetHandleList mcs_list;
            targetService().
              getAssociated(mcs_list,
                            i_target,
                            TargetService::PARENT_BY_AFFINITY,
                            TargetService::ALL,
                            &l_mcs);

            if( mcs_list.size() != 1 )
            {
                TRACFCOMP(g_trac_ibscom, ERR_MRK
                          "getTargetVirtualAddress:  mcs_list size is zero");
                /*@
                 * @errortype
                 * @moduleid     IBSCOM_GET_TARG_VIRT_ADDR
                 * @reasoncode   IBSCOM_INVALID_CONFIG
                 * @userdata1[0:31]   HUID of Centaur Target
                 * @userdata2    Not Used
                 * @devdesc      System configuration does not have a Parent MCS
                 *               for the current centaur.
                 */
                l_err =
                  new ErrlEntry(ERRL_SEV_UNRECOVERABLE,
                                IBSCOM_GET_TARG_VIRT_ADDR,
                                IBSCOM_INVALID_CONFIG,
                                TWO_UINT32_TO_UINT64(
                                                     get_huid(i_target),
                                                     0),
                                0);
                l_err->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE,
                                           HWAS::SRCI_PRIORITY_HIGH);
                break;
            }
            parentMCS = *(mcs_list.begin());

            l_IBScomBaseAddr =
              parentMCS->getAttr<ATTR_IBSCOM_MCS_BASE_ADDR>();

            TRACUCOMP(g_trac_ibscom, INFO_MRK
                      "getTargetVirtualAddress: From Attribute query l_IBScomBaseAddr=0x%llX, i_target=0x%.8x",
                      l_IBScomBaseAddr,
                      i_target->getAttr<ATTR_HUID>());

            // Map target's virtual address
            //NOTE: mmio_dev_map only supports 32 GB Allocation.  Technically,
            //hostboot IBSCOM MMIO allocated 64GB, but the SCOM address space
            //is small enough that 32 GB is sufficient.
            o_virtAddr = static_cast<uint64_t*>
              (mmio_dev_map(reinterpret_cast<void*>(l_IBScomBaseAddr),
                            THIRTYTWO_GB));

            // Save the virtual address attribute.

            // Leaving the comments as a discussion point...
            // This issue is tracked under RTC: 35315
            // Technically there is a race condition here. The mutex is
            // a per-hardware thread mutex, not a mutex for the whole XSCOM
            // logic. So there is possibility that this same thread is running
            // on another thread at the exact same time. We can use atomic
            // update instructions here.
            // Comment for Nick: This is a good candidate for having a way
            // to return a reference to the attribute instead of requiring
            // to call setAttr. We currently have no way to SMP-safely update
            // this attribute, where as if we had a reference to it we could use
            // the atomic update functions (_sync_bool_compare_and_swap in
            // this case.
            i_target->setAttr<ATTR_IBSCOM_VIRTUAL_ADDR>
              (reinterpret_cast<uint64_t>(o_virtAddr));
        }

    } while (0);

    TRACDCOMP(g_trac_ibscom, EXIT_MRK
              "getTargetVirtualAddress: o_Virtual Base Address   =  0x%llX",
              o_virtAddr);


    return l_err;
}


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
errlHndl_t doIBScom(DeviceFW::OperationType i_opType,
                          Target* i_target,
                          void* io_buffer,
                          size_t& io_buflen,
                          uint64_t i_addr,
                          bool i_errDataPath)
{
    errlHndl_t l_err = NULL;
    mutex_t* l_mutex = NULL;
    bool need_unlock = false;

    do
    {
        TRACUCOMP(g_trac_ibscom, INFO_MRK
                  ">>doIBScom: Perform op to SCOM Address 0x%X",
                  i_addr);

        // inband scom operation sanity check
        l_err = ibscomOpSanityCheck(i_opType, i_target, io_buffer,
                                    io_buflen, i_addr);
        if (l_err)
        {
            break;
        }
        // Set to buffer len to 0 until successfully access
        io_buflen = 0;

        // Get the target chip's virtual address
        uint64_t* l_virtAddr = NULL;
        l_err = getTargetVirtualAddress(i_target, l_virtAddr);

        if (l_err)
        {
            break;
        }

        TRACDCOMP(g_trac_ibscom,
                  "doIBScom: Base Virt Addr: 0x%.16X, Read addr: 0x%.16X",
                  l_virtAddr, &(l_virtAddr[i_addr]));


        // The dereferencing should handle Cache inhibited internally
        // Use local variable and memcpy to avoid unaligned memory access
        uint64_t l_data = 0;
        bool rw_error = false;

        //Device already locked when re-entering function for error collection..
        if(!i_errDataPath)
        {
            l_mutex = i_target->getHbMutexAttr<TARGETING::ATTR_IBSCOM_MUTEX>();
            mutex_lock(l_mutex);
            need_unlock = true;
        }

        if (i_opType == DeviceFW::READ)
        {
            //This is the actual MMIO Read
            l_data = l_virtAddr[i_addr];
            eieio();

            TRACUCOMP(g_trac_ibscom,
                      "doIBScom: Read address: 0x%.8X data: %.16X",
                      i_addr, l_data);

            // Check for error or done
            if(l_data == MMIO_IBSCOM_UE_DETECTED)
            {
                if(i_errDataPath)
                {
                    TRACFCOMP(g_trac_ibscom, ERR_MRK"doIBScom:  SUE Occurred during IBSCOM Error path");
                    /*@
                     * @errortype
                     * @moduleid     IBSCOM_DO_IBSCOM
                     * @reasoncode   IBSCOM_SUE_IN_ERR_PATH
                     * @userdata1[0:31]   HUID of Centaur Target
                     * @userdata1[32:64]  SCOM Address
                     * @userdata2    Not Used
                     * @devdesc      SUE Encountered when collecting IBSCOM
                     *               Error Data
                     */
                    l_err =
                      new ErrlEntry(ERRL_SEV_UNRECOVERABLE,
                                    IBSCOM_DO_IBSCOM,
                                    IBSCOM_SUE_IN_ERR_PATH,
                                    TWO_UINT32_TO_UINT64(
                                                         get_huid(i_target),
                                                         i_addr),
                                    0);
                    //This error should NEVER get returned to caller, so it's a
                    //FW bug if it actually gets comitted.
                    l_err->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE,
                                               HWAS::SRCI_PRIORITY_HIGH);
                    break;
                }
                else
                {
                    TRACFCOMP(g_trac_ibscom,
                              "doIBScom: Error code found in read data");
                    rw_error = true;
                }
            }
            else
            {
                //Copy data to user buffer
                memcpy(io_buffer, &l_data, sizeof(l_data));
            }
        }
        else //i_opType == DeviceFW::WRITE
        {
            memcpy(&l_data, io_buffer, sizeof(l_data));
            TRACUCOMP(g_trac_ibscom,
                      "doIBScom: Write addr: 0x%.8X data: %.16X",
                      i_addr, l_data);
            //This is the actual MMIO Write
            l_virtAddr[i_addr] = l_data;
            eieio();

            TRACDCOMP(g_trac_ibscom,
                      "doIBScom: Read MBSIBWRSTAT to check for error");
            //Read MBSIBWRSTAT to check for errors
            //If an error occured on last write, reading MBSIBWRSTAT will
            //trigger a SUE.
            const uint32_t MBSIBWRSTAT = 0x201141D;
            uint64_t statData = 0;
            size_t readSize = sizeof(uint64_t);
            l_err = doIBScom(DeviceFW::READ,
                                  i_target,
                                  &statData,
                                  readSize,
                                  MBSIBWRSTAT,
                                  true);
            if(l_err != NULL)
            {
                if( IBSCOM_SUE_IN_ERR_PATH == l_err->reasonCode() )
                {
                    TRACFCOMP(g_trac_ibscom, ERR_MRK
                              "doIBScom: SUE on write detected");
                    delete l_err;
                    l_err = NULL;
                    rw_error = true;
                }
                else
                {
                    TRACFCOMP(g_trac_ibscom, ERR_MRK"doIBScom: Unexpected error when checking for SUE");
                    break;
                }
            }

        }

        if(rw_error)
        {
            bool busDown = false;
            TRACUCOMP(g_trac_ibscom,
                      "doIBScom: Get Error data, read MBSIBERR0");
            const uint32_t MBSIBERR0 = 0x201141B;
            const uint64_t HOST_ERROR_VALID = 0x0000000080000000;
            const uint64_t PIB_ERROR_STATUS_MASK = 0x0000000070000000;
            const uint64_t PIB_ERROR_SHIFT = 28;
            size_t readSize = sizeof(uint64_t);
            uint64_t mbsiberr0_data = 0;

            //Use FSISCOM as workaround for DD1.x centaur chips (HW246298)
            if(i_target->getAttr<TARGETING::ATTR_EC>() < 0x20)
            {
                //Need to explicitly use FSI SCOM in DD1X chips
                l_err = deviceOp( DeviceFW::READ,
                                     i_target,
                                     &mbsiberr0_data,
                                     readSize,
                                     DEVICE_FSISCOM_ADDRESS(MBSIBERR0) );
                if(l_err)
                {
                    TRACFCOMP(g_trac_ibscom, ERR_MRK
                              "doIBScom: Error reading MBSIBERR0 over FSI");
                    //Save away the IBSCOM address
                    ERRORLOG::ErrlUserDetailsLogRegister
                      l_logReg(i_target);
                    //Really just want to save the addres, so stick in some
                    //obvious dummy data
                    uint64_t dummyData = 0x00000000DEADBEEF;
                    l_logReg.addDataBuffer(&dummyData, sizeof(dummyData),
                                           DEVICE_IBSCOM_ADDRESS(i_addr));
                    l_logReg.addToLog(l_err);
                    break;
                }
                TRACUCOMP(g_trac_ibscom,
                          "doIBScom: MBSIBERR0(0x%.16x) = 0x%.16X",
                          MBSIBERR0, mbsiberr0_data);

                //attempt to clear the error register so future accesses
                //will work
                uint64_t zeroData = 0x0;
                readSize = sizeof(uint64_t);
                l_err = deviceOp( DeviceFW::WRITE,
                                     i_target,
                                     &zeroData,
                                     readSize,
                                     DEVICE_FSISCOM_ADDRESS(MBSIBERR0) );
                if(l_err )
                {
                    errlCommit(l_err,IBSCOM_COMP_ID);
                    l_err = NULL;
                }

                //if the MBSIBERR0Q_IB_HOST_ERROR_VALID bit is not set
                //  then we have a bus failure
                if( !(mbsiberr0_data & HOST_ERROR_VALID) )
                {
                    //Bus is down
                    busDown = true;
                }
            }
            else  // >= DD20
            {
                //TODO RTC: 68984: Validate error path on DD2.0 Centaurs
                l_err = doIBScom(DeviceFW::READ,
                                 i_target,
                                 &mbsiberr0_data,
                                 readSize,
                                 MBSIBERR0,
                                 true);
                if(l_err != NULL)
                {
                    if( IBSCOM_SUE_IN_ERR_PATH == l_err->reasonCode() )
                    {
                        TRACFCOMP(g_trac_ibscom, ERR_MRK
                                  "doIBScom: SUE on write detected");
                        delete l_err;
                        l_err = NULL;
                        busDown = true;
                    }
                    else
                    {
                        TRACFCOMP(g_trac_ibscom, ERR_MRK"doIBScom: Unexpected error when checking for SUE");
                        break;
                    }
                }
            } // >= DD20

            if(busDown)
            {
                //TODO RTC: 69115 - call PRD to do FIR analysis, return PRD
                //error instead.
                /*@
                 * @errortype
                 * @moduleid     IBSCOM_DO_IBSCOM
                 * @reasoncode   IBSCOM_BUS_FAILURE
                 * @userdata1[0:31]   HUID of Centaur Target
                 * @userdata1[32:64]  SCOM Address
                 * @userdata2    Contents of MBSIBERR0 register
                 * @devdesc      Bus failure when attempting to perform
                 *               IBSCOM operation.  IBSCOM disabled.
                 */
                l_err =
                  new ErrlEntry(ERRL_SEV_UNRECOVERABLE,
                                IBSCOM_DO_IBSCOM,
                                IBSCOM_BUS_FAILURE,
                                TWO_UINT32_TO_UINT64(
                                                     get_huid(i_target),
                                                     i_addr),
                                mbsiberr0_data);

                l_err->addHwCallout(i_target,
                                    HWAS::SRCI_PRIORITY_HIGH,
                                    HWAS::NO_DECONFIG,
                                    HWAS::GARD_NULL);

                //disable IBSCOM
                ScomSwitches l_switches =
                  i_target->getAttr<ATTR_SCOM_SWITCHES>();

                // If IBSCOM is not already disabled.
                if ((l_switches.useFsiScom != 1) ||
                    (l_switches.useInbandScom != 0))
                {
                    l_switches.useFsiScom = 1;
                    l_switches.useInbandScom = 0;

                    // Turn off IBSCOM and turn on FSI SCOM.
                    i_target->setAttr<ATTR_SCOM_SWITCHES>(l_switches);
                }
                break;
            }
            else // bus isn't down, some other kind of error
            {
                /*@
                 * @errortype
                 * @moduleid     IBSCOM_DO_IBSCOM
                 * @reasoncode   IBSCOM_PIB_FAILURE
                 * @userdata1[0:31]   HUID of Centaur Target
                 * @userdata1[32:64]  SCOM Address
                 * @userdata2    Contents of MBSIBERR0 register
                 * @devdesc      PIB error when attempting to perform
                 *               IBSCOM operation.
                 */
                l_err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE,
                                      IBSCOM_DO_IBSCOM,
                                      IBSCOM_BUS_FAILURE,
                                      TWO_UINT32_TO_UINT64(
                                          get_huid(i_target),
                                          i_addr),
                                      mbsiberr0_data);

                //Add this target to the FFDC
                ERRORLOG::ErrlUserDetailsTarget(i_target).addToLog(l_err);

                uint64_t pib_code =
                  (mbsiberr0_data & PIB_ERROR_STATUS_MASK) >> PIB_ERROR_SHIFT;

                //add callouts based on the PIB error
                PIB::addFruCallouts( i_target,
                                     pib_code,
                                     l_err );

                break;
            }
        }
        else
        {
            //Operation was a success, set buffer length
            io_buflen = sizeof(uint64_t);
        }

        TRACDCOMP(g_trac_ibscom,"doIBScom: OpType 0x%.16llX, SCOM Address 0x%llX, Virtual Address 0x%llX",
                  static_cast<uint64_t>(i_opType),
                  i_addr,
                  &(l_virtAddr[i_addr]));

    } while (0);

    if( need_unlock && l_mutex )
    {
        mutex_unlock(l_mutex);
    }

    return l_err;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
errlHndl_t ibscomPerformOp(DeviceFW::OperationType i_opType,
                          Target* i_target,
                          void* io_buffer,
                          size_t& io_buflen,
                          int64_t i_accessType,
                          va_list i_args)
{
    errlHndl_t l_err = NULL;
    uint64_t l_addr = va_arg(i_args,uint64_t);

    l_err = doIBScom(i_opType,
                     i_target,
                     io_buffer,
                     io_buflen,
                     l_addr,
                     false);
    return l_err;
}

} // end namespace
OpenPOWER on IntegriCloud