Example #1
0
errlHndl_t RtPnor::getSideInfo( PNOR::SideId i_side,
                                PNOR::SideInfo_t& o_info)
{
    errlHndl_t l_err = nullptr;

    do {
        // We only support the working side at runtime
        if( i_side != PNOR::WORKING )
        {
            /*@
             * @errortype
             * @moduleid           PNOR::MOD_RTPNOR_GETSIDEINFO
             * @reasoncode         PNOR::RC_INVALID_PNOR_SIDE
             * @userdata1          Requested SIDE
             * @userdata2          0
             * @devdesc            getSideInfo> Side not supported
             * @custdesc           A problem occurred while accessing the boot flash.
             */
            l_err = new ERRORLOG::ErrlEntry(
                             ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                             PNOR::MOD_RTPNOR_GETSIDEINFO,
                             PNOR::RC_INVALID_PNOR_SIDE,
                             TO_UINT64(i_side),
                             0,true);
            break;
        }

        o_info.id = PNOR::WORKING;
        o_info.side = (ALIGN_DOWN_X(iv_TOC[PNOR::HB_BASE_CODE].flashAddr,32*MEGABYTE) == 0)
          ? 'A':'B'; //@fixme TODO RTC:134436
        //iv_side[i].isGolden = (ffsUserData->miscFlags & FFS_MISC_GOLDEN);
        o_info.isGolden = false; //@fixme TODO RTC:134436
        o_info.isGuardPresent = (iv_TOC[PNOR::GUARD_DATA].flashAddr == 0)
          ? false : true;

        o_info.hasOtherSide = false; //@fixme TODO RTC:134436
        o_info.primaryTOC = iv_TOC[PNOR::TOC].flashAddr;
        o_info.backupTOC = 0; //@fixme TODO RTC:134436
        o_info.hbbAddress = iv_TOC[PNOR::HB_BASE_CODE].flashAddr;
        o_info.hbbMmioOffset = 0; //@fixme TODO RTC:134436
    } while(0);

    return l_err;
}
Example #2
0
/**
 * @brief Performs a presence detect operation on a Processor Chip.
 *
 * This function does FSI presence detect and compares it to the Module
 * VPD that is present, following the pre-defined prototype for a
 * device-driver framework function.
 *
 * @param[in]   i_opType        Operation type, see DeviceFW::OperationType
 *                              in driverif.H
 * @param[in]   i_target        Presence detect target
 * @param[in/out] io_buffer     Read: Pointer to output data storage
 *                              Write: Pointer to input data storage
 * @param[in/out] io_buflen     Input: size of io_buffer (in bytes, always 1)
 *                              Output: Success = 1, Failure = 0
 * @param[in]   i_accessType    DeviceFW::AccessType enum (userif.H)
 * @param[in]   i_args          This is an argument list for DD framework.
 *                              In this function, there are no arguments.
 * @return  errlHndl_t
 */
errlHndl_t procPresenceDetect(DeviceFW::OperationType i_opType,
                              TARGETING::Target* i_target,
                              void* io_buffer,
                              size_t& io_buflen,
                              int64_t i_accessType,
                              va_list i_args)
{
    errlHndl_t l_errl = NULL;
    uint32_t l_saved_plid = 0;

    if (unlikely(io_buflen < sizeof(bool)))
    {
        TRACFCOMP(g_trac_fsi,
                  ERR_MRK "FSI::procPresenceDetect> Invalid data length: %d",
                  io_buflen);
        /*@
         * @errortype
         * @moduleid     FSI::MOD_FSIPRES_PROCPRESENCEDETECT
         * @reasoncode   FSI::RC_INVALID_LENGTH
         * @userdata1    Data Length
         * @devdesc      presenceDetect> Invalid data length (!= 1 bytes)
         */
        l_errl =
                new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                        FSI::MOD_FSIPRES_PROCPRESENCEDETECT,
                                        FSI::RC_INVALID_LENGTH,
                                        TO_UINT64(io_buflen),
                                        true /*SW error*/);
        io_buflen = 0;
        return l_errl;
    }

    // First look for FSI presence bits
    bool fsi_present = false;

    TARGETING::Target* l_masterChip = NULL;
    TARGETING::targetService().masterProcChipTargetHandle(l_masterChip);

    if ((i_target == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL) ||
        (i_target == l_masterChip))
    {
        fsi_present = true;
    }
    else
    {
        fsi_present = isSlavePresent(i_target);
    }

    // Next look for valid Module VPD
    bool check_for_mvpd = true;
#ifdef CONFIG_MVPD_READ_FROM_HW
    check_for_mvpd = fsi_present;
#endif // CONFIG_MVPD_READ_FROM_HW

    bool mvpd_present = false;
    size_t theSize = 0;

    if ( check_for_mvpd )
    {
        l_errl = deviceRead( i_target,
                            NULL,
                            theSize,
                            DEVICE_MVPD_ADDRESS( MVPD::CP00,
                                                 MVPD::VD ) );
        if( l_errl )
        {
            if( fsi_present )
            {
                // Save this plid to use later
                l_saved_plid = l_errl->plid();

                // commit this log because we expected to have VPD
                errlCommit( l_errl,
                            FSI_COMP_ID );
            }
            else
            {
                // just delete this
                delete l_errl;
            }
        }

        if( theSize > 0 )
        {
            uint8_t theData[theSize];
            l_errl = deviceRead( i_target,
                                 theData,
                                 theSize,
                                 DEVICE_MVPD_ADDRESS( MVPD::CP00,
                                                      MVPD::VD ) );
            if( l_errl )
            {
                if( fsi_present )
                {

                    // Save this plid to use later
                    l_saved_plid = l_errl->plid();

                    // commit this log because we expected to have VPD
                    errlCommit( l_errl,
                                FSI_COMP_ID );
                }
                else
                {
                    // just delete this
                    delete l_errl;
                }
            }
            else
            {
                mvpd_present = true;
            }
        }
    }


    // Finally compare the 2 methods
    if( fsi_present != mvpd_present )
    {
        TRACFCOMP(g_trac_fsi,
                  ERR_MRK "FSI::procPresenceDetect> FSI (=%d) and MVPD (=%d) do not agree for %.8X",
                  fsi_present, mvpd_present, TARGETING::get_huid(i_target));
        /*@
         * @errortype
         * @moduleid     FSI::MOD_FSIPRES_PROCPRESENCEDETECT
         * @reasoncode   FSI::RC_FSI_MVPD_MISMATCH
         * @userdata1    HUID of processor
         * @userdata2[0:31]    FSI Presence
         * @userdata2[32:63]   MVPD Presence
         * @devdesc      presenceDetect> FSI and MVPD do not agree
         */
        l_errl =
                new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                        FSI::MOD_FSIPRES_PROCPRESENCEDETECT,
                                        FSI::RC_FSI_MVPD_MISMATCH,
                                        TARGETING::get_huid(i_target),
                                        TWO_UINT32_TO_UINT64(
                                            fsi_present,
                                            mvpd_present));

        // Callout the processor
        l_errl->addHwCallout( i_target,
                              HWAS::SRCI_PRIORITY_LOW,
                              HWAS::NO_DECONFIG,
                              HWAS::GARD_NULL );

        // if there is a saved PLID, apply it to this error log
        if (l_saved_plid)
        {
            l_errl->plid(l_saved_plid);
        }

        // Add FFDC for the target to an error log
        getFsiFFDC( FFDC_PRESENCE_FAIL, l_errl, i_target);


        // Add FSI and VPD trace
        l_errl->collectTrace("FSI");
        l_errl->collectTrace("VPD");

        // commit this log and move on
        errlCommit( l_errl,
                    FSI_COMP_ID );
    }


    bool present = fsi_present && mvpd_present;
    memcpy(io_buffer, &present, sizeof(present));
    io_buflen = sizeof(present);

    return NULL;
}
Example #3
0
/**
 * @brief Performs a mailbox write operation
 */
errlHndl_t mboxWrite(TARGETING::Target* i_target,void* i_buffer,
                         size_t& i_buflen)
{
    errlHndl_t l_err = NULL;
    uint32_t l_64bitBuf[2] = {0};
    size_t l_64bitSize = sizeof(uint64_t);

    do
    {
        //If the expected siZe in bytes is bigger than the max data allowed
        // send back an error.
        if (i_buflen > MBOX_MAX_DATA_BYTES)
        {
            TRACFCOMP(g_trac_mbox, ERR_MRK "MBOX::write> Invalid data length : i_buflen=%d", i_buflen);
            /*@
             * @errortype
             * @moduleid     MBOX::MOD_MBOXDD_WRITE
             * @reasoncode   MBOX::RC_INVALID_LENGTH
             * @userdata1    Target ID String...
             * @userdata2    Data Length
             * @devdesc      MboxDD::write> Invalid data length (> msg_t size)
             * @custdesc     A problem occurred during the
             *               IPL of the system.
             */
            l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                            MBOX::MOD_MBOXDD_WRITE,
                                            MBOX::RC_INVALID_LENGTH,
                                            TARGETING::get_huid(i_target),
                                            TO_UINT64(i_buflen),
                                            true /*Add HB Software Callout*/);

            l_err->collectTrace(MBOX_TRACE_NAME,1024);

            // Set the i_buflen to 0 to indicate no write occured
            i_buflen = 0;

            break;
        }

        // read the DB_STATUS_1A_REG: doorbell status and control 1a
        l_err = deviceOp(DeviceFW::READ,i_target,
                         l_64bitBuf,l_64bitSize,
                         DEVICE_XSCOM_ADDRESS(MBOX_DB_STAT_CNTRL_1));
        if (l_err)
        {
            TRACFCOMP(g_trac_mbox, ERR_MRK "mboxWrite> Unable to read Doorbell Status/Control Register");
            break;
        }

        /*
         * DB_STATUS_1A_REG: doorbell status and control 1a
         * Bit31(MSB) : Permission to Send Doorbell 1
         * Bit30 : Abort Doorbell 1
         * Bit29 : LBUS Slave B Pending Doorbell 1
         * Bit28 : PIB Slave A Pending Doorbell 1
         * Bit27 : Reserved
         * Bit26 : Xdn Doorbell 1
         * Bit25 : Xup Doorbell 1
         * Bit24 : Reserved
         * Bit23-20 : Header Count PIB Slave A Doorbell 1
         * Bit19-12 : Data Count PIB Slave A Doorbell 1
         * Bit11-8 : Header Count LBUS Slave B Doorbell 1
         * Bit7-0 : Data Count LBUS Slave B Doorbell 1
         */

        //Verify There is no LBUS Pending,
        if ((l_64bitBuf[0] &
            (MBOX_LBUS_SLAVE_B_PND |  MBOX_HDR_PIB_SLAVE_A | MBOX_DATA_PIB_SLAVE_A)) == 0)
        {
            // Current register counter indicating which of the mbox registers
            // to write to
            uint32_t cur_reg_cntr = 0;
            uint32_t l_data[2] = {0};

            // Total number of registers to read to get all the data.
            uint8_t l_numRegsToWrite = (i_buflen*sizeof(uint8_t))/sizeof(uint32_t);

            uint8_t l_numBytesLeft =
              (i_buflen*sizeof(uint8_t))%sizeof(uint32_t);

            if (l_numBytesLeft != 0)
            {
                l_numRegsToWrite++;
            }

            uint32_t *l_buf = static_cast<uint32_t *>(i_buffer);

            // For the write we put the data into the MBOX data registers.
            // MBOX_DATA_PIB_START    = 0x00050040 and the end address is
            // MBOX_DATA_PIB_END      = 0x0005004F
            // each address inbetween increments by 1.

            //Write Data registers.  Start at the first and increment through
            //the registers until all the data has been written.
            while (cur_reg_cntr < l_numRegsToWrite)
            {

                // If this is the last register we need to write and are not word aligned
                if (((cur_reg_cntr + 1) == l_numRegsToWrite) &&
                    (l_numBytesLeft != 0))
                {
                    // zero out the data reg.
                    l_data[0] = 0;

                    // Only copy the number of bytes remaining..
                    memcpy(&l_data[0], l_buf+cur_reg_cntr,l_numBytesLeft);

                }
                else
                {
                    // point to the next 32bits of data in the buffer.
                    l_data[0] = *(l_buf+cur_reg_cntr);

                }

                l_err = deviceOp(DeviceFW::WRITE,i_target,
                                 l_data,l_64bitSize,
                                 DEVICE_XSCOM_ADDRESS(MBOX_DATA_PIB_START+cur_reg_cntr));
                if (l_err)
                {
                    TRACFCOMP(g_trac_mbox, ERR_MRK "mboxWrite> Unable to write Data Area Register 0x%X",MBOX_DATA_PIB_START+cur_reg_cntr);
                    break;
                }
                //increment counter so we are at the next register
                cur_reg_cntr++;
            }
            if (l_err)
            {
                break;
            }

            //Write LBUS Pending(28) and Data Count bits(11-0) to indicate
            // data has been written.
            l_64bitBuf[0] =  MBOX_LBUS_SLAVE_B_PND | (MBOX_DATA_PIB_SLAVE_A &
                                                      (i_buflen << 12));

            l_err = deviceOp(DeviceFW::WRITE,i_target,
                             l_64bitBuf,l_64bitSize,
                             DEVICE_XSCOM_ADDRESS(MBOX_DB_STAT_CNTRL_1));

            if (l_err)
            {
                TRACFCOMP(g_trac_mbox, ERR_MRK "mboxWrite> Unable to set Doorbell Status/Control Register");
                break;
            }
        }
        else
        {
            TRACFCOMP(g_trac_mbox, ERR_MRK "mboxWrite> Message still pending : MBOX_DB_STAT_CNTRL_1=%X", l_64bitBuf[0]);
            /*@
             * @errortype
             * @moduleid     MBOX::MOD_MBOXDD_WRITE
             * @reasoncode   MBOX::RC_MSG_PENDING
             * @userdata1    Target ID String...
             * @userdata2    Status/Control Register
             * @devdesc      MboxDD::write> Message still pending
             * @custdesc     A problem occurred during the
             *               IPL of the system.
             */
            l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                        MBOX::MOD_MBOXDD_WRITE,
                                        MBOX::RC_MSG_PENDING,
                                        TARGETING::get_huid(i_target),
                                        reinterpret_cast<uint64_t>(l_64bitBuf),
                                        true /*Add HB Software Callout*/);

            // Set the i_buflen to 0 to indicate no write occured
            i_buflen = 0;
            l_err->collectTrace(MBOX_TRACE_NAME,1024);
            break;
        }

    } while(0);

    return l_err;
}
Example #4
0
// ------------------------------------------------------------------
// ensureCacheIsInSync
// ------------------------------------------------------------------
errlHndl_t ensureCacheIsInSync ( TARGETING::Target * i_target )
{
    errlHndl_t l_err = NULL;

    TRACSSCOMP( g_trac_vpd, ENTER_MRK"ensureCacheIsInSync() " );

    IpVpdFacade& l_ipvpd = Singleton<MvpdFacade>::instance();

    vpdRecord  l_record    = 0;
    vpdKeyword l_keywordPN = 0;
    vpdKeyword l_keywordSN = 0;

    TARGETING::TYPE l_type = i_target->getAttr<TARGETING::ATTR_TYPE>();

    if( l_type == TARGETING::TYPE_PROC )
    {
        l_record    = MVPD::VINI;
        l_keywordPN = MVPD::PN;
        l_keywordSN = MVPD::SN;
    }
    else if( l_type == TARGETING::TYPE_MEMBUF )
    {
        l_ipvpd     = Singleton<CvpdFacade>::instance();
        l_record    = CVPD::VINI;
        l_keywordPN = CVPD::PN;
        l_keywordSN = CVPD::SN;
    }
    else if( l_type == TARGETING::TYPE_DIMM )
    {
        // SPD does not have a singleton instance
        // SPD does not use records
        l_keywordPN = SPD::MODULE_PART_NUMBER;
        l_keywordSN = SPD::MODULE_SERIAL_NUMBER;
    }
    else
    {
        TRACFCOMP(g_trac_vpd,ERR_MRK"ensureCacheIsInSync() Unexpected target type, huid=0x%X",TARGETING::get_huid(i_target));
        /*@
         * @errortype
         * @moduleid     VPD_ENSURE_CACHE_IS_IN_SYNC
         * @reasoncode   VPD_UNEXPECTED_TARGET_TYPE
         * @userdata1    Target HUID
         * @userdata2    <UNUSED>
         * @devdesc      Unexpected target type
         */
        l_err = new ERRORLOG::ErrlEntry(
                                ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                VPD_ENSURE_CACHE_IS_IN_SYNC,
                                VPD_UNEXPECTED_TARGET_TYPE,
                                TO_UINT64(TARGETING::get_huid(i_target)),
                                0x0,
                                true /*Add HB Software Callout*/ );
        return l_err;
    }

    do
    {
        // Compare the Part Numbers in PNOR/SEEPROM
        bool l_matchPN = false;
        if( ( l_type == TARGETING::TYPE_PROC   ) ||
            ( l_type == TARGETING::TYPE_MEMBUF ) )
        {
            l_err = l_ipvpd.cmpPnorToSeeprom( i_target,
                                              l_record,
                                              l_keywordPN,
                                              l_matchPN );
        }
        else if( l_type == TARGETING::TYPE_DIMM )
        {
            l_err = SPD::cmpPnorToSeeprom( i_target,
                                           l_keywordPN,
                                           l_matchPN );
        }
        if (l_err)
        {
            TRACFCOMP(g_trac_vpd,ERR_MRK"VPD::ensureCacheIsInSync: Error checking for PNOR/SEEPROM PN match");
            break;
        }

        // Compare the Serial Numbers in PNOR/SEEPROM
        bool l_matchSN = false;
        if( ( l_type == TARGETING::TYPE_PROC   ) ||
            ( l_type == TARGETING::TYPE_MEMBUF ) )
        {
            l_err = l_ipvpd.cmpPnorToSeeprom( i_target,
                                              l_record,
                                              l_keywordSN,
                                              l_matchSN );
        }
        else if( l_type == TARGETING::TYPE_DIMM )
        {
            l_err = SPD::cmpPnorToSeeprom( i_target,
                                           l_keywordSN,
                                           l_matchSN );
        }
        if( l_err )
        {
            TRACFCOMP(g_trac_vpd,ERR_MRK"VPD::ensureCacheIsInSync: Error checking for PNOR/SEEPROM SN match");
            break;
        }

        // If we did not match, we need to load SEEPROM VPD data into PNOR
        if( l_matchPN && l_matchSN )
        {
            TRACFCOMP(g_trac_vpd,"VPD::ensureCacheIsInSync: PNOR_PN/SN = SEEPROM_PN/SN");
        }
        else
        {
            TRACFCOMP(g_trac_vpd,"VPD::ensureCacheIsInSync: PNOR_PN/SN != SEEPROM_PN/SN, Loading PNOR from SEEPROM");

            // @todo RTC 116553 - Need HCDB update call here
            // Load the PNOR data from the SEEPROM
            if( ( l_type == TARGETING::TYPE_PROC   ) ||
                ( l_type == TARGETING::TYPE_MEMBUF ) )
            {
                l_err = l_ipvpd.loadPnor( i_target );
            }
            else if( l_type == TARGETING::TYPE_DIMM )
            {
                l_err = SPD::loadPnor( i_target );
            }
            if( l_err )
            {
                TRACFCOMP(g_trac_vpd,"Error loading SEEPROM VPD into PNOR");
                break;
            }
        }

        // Set target attribute switch that says VPD is loaded into PNOR
        TARGETING::ATTR_VPD_SWITCHES_type vpdSwitches =
                    i_target->getAttr<TARGETING::ATTR_VPD_SWITCHES>();
        vpdSwitches.pnorLoaded = 1;
        i_target->setAttr<TARGETING::ATTR_VPD_SWITCHES>( vpdSwitches );

    } while(0);

    TRACSSCOMP( g_trac_vpd, EXIT_MRK"ensureCacheIsInSync()" );

    return l_err;
}
Example #5
0
// ------------------------------------------------------------------
// writePNOR
// ------------------------------------------------------------------
errlHndl_t writePNOR ( uint64_t i_byteAddr,
                       size_t i_numBytes,
                       void * i_data,
                       TARGETING::Target * i_target,
                       pnorInformation & i_pnorInfo,
                       uint64_t &io_cachedAddr,
                       mutex_t * i_mutex )
{
    errlHndl_t err = NULL;
    int64_t vpdLocation = 0;
    uint64_t addr = 0x0;
    const char * writeAddr = NULL;

    TRACSSCOMP( g_trac_vpd,
                ENTER_MRK"writePNOR()" );

    do
    {
        // Check if we have the PNOR addr cached.
        if( 0x0 == io_cachedAddr )
        {
            err = getPnorAddr( i_pnorInfo,
                               io_cachedAddr,
                               i_mutex );

            if( err )
            {
                break;
            }
        }
        addr = io_cachedAddr;

        // Find vpd location of the target
        err = getVpdLocation( vpdLocation,
                              i_target );

        if( err )
        {
            break;
        }

        // Offset cached address by vpd location multiplier
        addr += (vpdLocation * i_pnorInfo.segmentSize);

        // Now offset into that chunk of data by i_byteAddr
        addr += i_byteAddr;

        //TODO: Validate write is within bounds of appropriate PNOR
        //   partition/section.   RTC: 51807

        TRACUCOMP( g_trac_vpd,
                   INFO_MRK"Address to write: 0x%08x",
                   addr );

        // Write the data
        writeAddr = reinterpret_cast<const char*>( addr );
        memcpy( (void*)(writeAddr),
                i_data,
                i_numBytes );

        // @todo RTC:117042 - enable flush once PNOR writes supported
        // Flush the page to make sure it gets to the PNOR
#if 0
        int rc = mm_remove_pages( FLUSH, (void*)addr, i_numBytes );
        if( rc )
        {
            TRACFCOMP(g_trac_vpd,ERR_MRK"writePNOR() Error from mm_remove_pages, rc=%d",rc);
            /*@
             * @errortype
             * @moduleid     VPD_WRITE_PNOR
             * @reasoncode   VPD_REMOVE_PAGES_FAIL
             * @userdata1    Requested Address
             * @userdata2    rc from mm_remove_pages
             * @devdesc      writePNOR mm_remove_pages FLUSH failed
             */
            err = new ERRORLOG::ErrlEntry(
                            ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                            VPD_WRITE_PNOR,
                            VPD_REMOVE_PAGES_FAIL,
                            addr,
                            TO_UINT64(rc),
                            true /*Add HB Software Callout*/ );
        }
#endif
    } while( 0 );

    TRACSSCOMP( g_trac_vpd,
                EXIT_MRK"writePNOR()" );

    return err;
}
Example #6
0
///////////////////////////////////////////////////////////////////////////////
// See header file for doxygen documentation
///////////////////////////////////////////////////////////////////////////////
errlHndl_t validateInputs(DeviceFW::OperationType i_opType,
                          const TARGETING::Target* i_target,
                          size_t i_buflen,
                          uint64_t i_scomAddr)
{
    errlHndl_t l_err = nullptr;
    uint32_t l_commonPlid = 0;  // If there are multiple issues found link logs with first

    // Verify that the target is of type OCMB_CHIP
    TARGETING::ATTR_TYPE_type l_targetType =
                    i_target->getAttr<TARGETING::ATTR_TYPE>();

    // Only target we can perform ocmb scoms on are OCMB chip targets
    if( l_targetType != TARGETING::TYPE_OCMB_CHIP )
    {
        TRACFCOMP( g_trac_expscom, ERR_MRK "validateInputs> Invalid target type : l_targetType=0x%X", l_targetType );
        /*@
          * @errortype
          * @moduleid     EXPSCOM::MOD_OCMB_UTILS
          * @reasoncode   EXPSCOM::RC_INVALID_MODEL_TYPE
          * @userdata1    SCOM Address
          * @userdata2    Model Type
          * @devdesc      validateInputs> Invalid target type (!= OCMB_CHIP)
          * @custdesc     A problem occurred during the IPL of the system:
          *               Invalid target type for a SCOM operation.
          */
        l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                        EXPSCOM::MOD_OCMB_UTILS,
                                        EXPSCOM::RC_INVALID_MODEL_TYPE,
                                        i_scomAddr,
                                        l_targetType,
                                        ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);

        l_err->collectTrace(EXPSCOM_COMP_NAME);
        ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target").
          addToLog(l_err);
        l_commonPlid = l_err->plid();
    }

    // The address passed to the OCMB scom functions is really only 32 bits
    //  just to be safe make sure that first 4 bytes are 0s
    if( i_scomAddr & FIRST_4_BYTES )
    {
        TRACFCOMP( g_trac_expscom,
                    ERR_MRK "validateInputs> Invalid address : i_scomAddr=0x%lx , first 32 bits should be 0's",
                    i_scomAddr );

        // If there is already an error from prev checks, then commit it
        if(l_err)
        {
            errlCommit(l_err, EXPSCOM_COMP_ID);
        }

        /*@
          * @errortype
          * @moduleid     EXPSCOM::MOD_OCMB_UTILS
          * @reasoncode   EXPSCOM::RC_INVALID_ADDRESS
          * @userdata1    SCOM Address
          * @userdata2    Target HUID
          * @devdesc      validateInputs> Invalid scom address, first 4
          *               bytes should be 0's
          * @custdesc     A problem occurred during the IPL of the system:
          *               Invalid address for a SCOM operation.
          */
        l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                        EXPSCOM::MOD_OCMB_UTILS,
                                        EXPSCOM::RC_INVALID_ADDRESS,
                                        i_scomAddr,
                                        TARGETING::get_huid(i_target),
                                        ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);

        l_err->collectTrace(EXPSCOM_COMP_NAME);
        ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target").
          addToLog(l_err);

        if(l_commonPlid == 0)
        {
            l_commonPlid = l_err->plid();
        }
        else
        {
            l_err->plid(l_commonPlid);
        }
    }

    // The buffer passed into validateInputs should ALWAYS be 8 bytes.
    // If it is an IBM scom then all 8 bytes are used. If its microchip scom
    // then only the last 4 bytes are used.
    if (i_buflen != sizeof(uint64_t))
    {
        TRACFCOMP( g_trac_expscom, ERR_MRK "validateInputs> Invalid data length : io_buflen=%d ,"
                    " expected sizeof(uint64_t)", i_buflen );

        // If there is already an error from prev checks, then commit it
        if(l_err)
        {
            errlCommit(l_err, EXPSCOM_COMP_ID);
        }

        /*@
          * @errortype
          * @moduleid     EXPSCOM::MOD_OCMB_UTILS
          * @reasoncode   EXPSCOM::RC_INVALID_LENGTH
          * @userdata1    SCOM Address
          * @userdata2    Data Length
          * @devdesc      validateInputs> Invalid data length (!= 8 bytes)
          * @custdesc     A problem occurred during the IPL of the system:
          *               Invalid data length for a SCOM operation.
          */
        l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                        EXPSCOM::MOD_OCMB_UTILS,
                                        EXPSCOM::RC_INVALID_LENGTH,
                                        i_scomAddr,
                                        TO_UINT64(i_buflen),
                                        ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);

        l_err->collectTrace(EXPSCOM_COMP_NAME);
        ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target").
          addToLog(l_err);

        if(l_commonPlid == 0)
        {
            l_commonPlid = l_err->plid();
        }
        else
        {
            l_err->plid(l_commonPlid);
        }
    }

    // The only valid operations are READ and WRITE if anything else comes in we need to error out
    if (i_opType != DeviceFW::READ && i_opType != DeviceFW::WRITE )
    {
        TRACFCOMP( g_trac_expscom, ERR_MRK "validateInputs> Invalid operation type : i_opType=%d", i_opType );

        if(l_err)
        {
            errlCommit(l_err, EXPSCOM_COMP_ID);
        }

        /*@
          * @errortype
          * @moduleid     EXPSCOM::MOD_OCMB_UTILS
          * @reasoncode   EXPSCOM::RC_INVALID_OPTYPE
          * @userdata1    SCOM Address
          * @userdata2    Access Type
          * @devdesc      validateInputs> Invalid OP type (!= READ or WRITE)
          * @custdesc     A problem occurred during the IPL of the system:
          *               Invalid operation type for a SCOM operation.
          */
        l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                        EXPSCOM::MOD_OCMB_UTILS,
                                        EXPSCOM::RC_INVALID_OPTYPE,
                                        i_scomAddr,
                                        i_opType,
                                        ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);

        l_err->collectTrace(EXPSCOM_COMP_NAME);
        ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target").
          addToLog(l_err);

        if(l_commonPlid == 0)
        {
            l_commonPlid = l_err->plid();
        }
        else
        {
            l_err->plid(l_commonPlid);
        }
    }

    return l_err;
}
Example #7
0
/**
 * @brief Performs a presence detect operation on a Processor Chip.
 *
 * This function does FSI presence detect and compares it to the Module
 * VPD that is present, following the pre-defined prototype for a
 * device-driver framework function.
 *
 * @param[in]   i_opType        Operation type, see DeviceFW::OperationType
 *                              in driverif.H
 * @param[in]   i_target        Presence detect target
 * @param[in/out] io_buffer     Read: Pointer to output data storage
 *                              Write: Pointer to input data storage
 * @param[in/out] io_buflen     Input: size of io_buffer (in bytes, always 1)
 *                              Output: Success = 1, Failure = 0
 * @param[in]   i_accessType    DeviceFW::AccessType enum (userif.H)
 * @param[in]   i_args          This is an argument list for DD framework.
 *                              In this function, there are no arguments.
 * @return  errlHndl_t
 */
errlHndl_t procPresenceDetect(DeviceFW::OperationType i_opType,
                              TARGETING::Target* i_target,
                              void* io_buffer,
                              size_t& io_buflen,
                              int64_t i_accessType,
                              va_list i_args)
{
    errlHndl_t l_errl = NULL;
    uint32_t l_saved_plid = 0;

    if (unlikely(io_buflen < sizeof(bool)))
    {
        TRACFCOMP(g_trac_fsi,
                  ERR_MRK "FSI::procPresenceDetect> Invalid data length: %d",
                  io_buflen);
        /*@
         * @errortype
         * @moduleid     FSI::MOD_FSIPRES_PROCPRESENCEDETECT
         * @reasoncode   FSI::RC_INVALID_LENGTH
         * @userdata1    Data Length
         * @devdesc      presenceDetect> Invalid data length (!= 1 bytes)
         */
        l_errl =
                new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                        FSI::MOD_FSIPRES_PROCPRESENCEDETECT,
                                        FSI::RC_INVALID_LENGTH,
                                        TO_UINT64(io_buflen),
                                        true /*SW error*/);
        io_buflen = 0;
        return l_errl;
    }

    // First look for FSI presence bits
    bool fsi_present = false;

    TARGETING::Target* l_masterChip = NULL;
    TARGETING::targetService().masterProcChipTargetHandle(l_masterChip);

    if ((i_target == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL) ||
        (i_target == l_masterChip))
    {
        fsi_present = true;
    }
    else
    {
        fsi_present = isSlavePresent(i_target);
    }

    // Next look for valid Module VPD
    bool mvpd_present = false;
    bool check_for_mvpd = true;

#ifdef CONFIG_MVPD_READ_FROM_HW
    check_for_mvpd = fsi_present;
#endif

    if ( check_for_mvpd )
    {
       mvpd_present = VPD::mvpdPresent( i_target );
    }

#if defined(CONFIG_MVPD_READ_FROM_HW) && defined(CONFIG_MVPD_READ_FROM_PNOR)
    if( mvpd_present )
    {
        // Check if the VPD data in the PNOR matches the SEEPROM
        l_errl = VPD::ensureCacheIsInSync( i_target );
        if( l_errl )
        {
            // Save this plid to use later
            l_saved_plid = l_errl->plid();
            mvpd_present = false;

            TRACFCOMP(g_trac_fsi,ERR_MRK "FSI::procPresenceDetect> Error during ensureCacheIsInSync (MVPD)" );
            errlCommit( l_errl, FSI_COMP_ID );
        }
    }
    else
    {
        // Invalidate MVPD in the PNOR
        l_errl = VPD::invalidatePnorCache(i_target);
        if (l_errl)
        {
            TRACFCOMP( g_trac_fsi, "Error invalidating MVPD in PNOR" );
            errlCommit( l_errl, FSI_COMP_ID );
        }
    }
#endif

    // Finally compare the 2 methods
    if( fsi_present != mvpd_present )
    {
        TRACFCOMP(g_trac_fsi, ERR_MRK "FSI::procPresenceDetect> "
                  "FSI (=%d) and MVPD (=%d) do not agree for %.8X",
                  fsi_present, mvpd_present, TARGETING::get_huid(i_target));
        /*@
         * @errortype
         * @moduleid     FSI::MOD_FSIPRES_PROCPRESENCEDETECT
         * @reasoncode   FSI::RC_FSI_MVPD_MISMATCH
         * @userdata1    HUID of processor
         * @userdata2[0:31]    FSI Presence
         * @userdata2[32:63]   MVPD Presence
         * @devdesc      presenceDetect> FSI and MVPD do not agree
         */
        l_errl =
                new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                        FSI::MOD_FSIPRES_PROCPRESENCEDETECT,
                                        FSI::RC_FSI_MVPD_MISMATCH,
                                        TARGETING::get_huid(i_target),
                                        TWO_UINT32_TO_UINT64(
                                            fsi_present,
                                            mvpd_present));

        // Callout the processor
        l_errl->addHwCallout( i_target,
                              HWAS::SRCI_PRIORITY_LOW,
                              HWAS::NO_DECONFIG,
                              HWAS::GARD_NULL );


        // If there is a saved PLID, apply it to this error log
        if (l_saved_plid)
        {
            l_errl->plid(l_saved_plid);
        }

        // Add FFDC for the target to an error log
        getFsiFFDC( FFDC_PRESENCE_FAIL, l_errl, i_target);

        // Add FSI and VPD trace
        l_errl->collectTrace("FSI");
        l_errl->collectTrace("VPD");

        // Commit this log and move on
        errlCommit( l_errl,
                    FSI_COMP_ID );
    }

    bool present = fsi_present && mvpd_present;
    if( present )
    {
        //Fsp sets PN/SN so if there is none, do it here
        if(!INITSERVICE::spBaseServicesEnabled())
        {
            // set part and serial number attributes for current target
            VPD::setPartAndSerialNumberAttributes( i_target );

        }
    }

    memcpy(io_buffer, &present, sizeof(present));
    io_buflen = sizeof(present);

    return NULL;
}
Example #8
0
/**
 * @brief  Message receiver
 */
void PnorRP::waitForMessage()
{
    TRACFCOMP(g_trac_pnor, "PnorRP::waitForMessage>" );

    errlHndl_t l_errhdl = NULL;
    msg_t* message = NULL;
    uint8_t* user_addr = NULL;
    uint8_t* eff_addr = NULL;
    uint64_t dev_offset = 0;
    uint64_t chip_select = 0xF;
    bool needs_ecc = false;
    int rc = 0;
    uint64_t status_rc = 0;
    uint64_t fatal_error = 0;

    while(1)
    {
        status_rc = 0;
        TRACUCOMP(g_trac_pnor, "PnorRP::waitForMessage> waiting for message" );
        message = msg_wait( iv_msgQ );
        if( message )
        {
            /*  data[0] = virtual address requested
             *  data[1] = address to place contents
             */
            eff_addr = (uint8_t*)message->data[0];
            user_addr = (uint8_t*)message->data[1];

            //figure out the real pnor offset
            l_errhdl = computeDeviceAddr( eff_addr, dev_offset, chip_select, needs_ecc );
            if( l_errhdl )
            {
                status_rc = -EFAULT; /* Bad address */
            }
            else
            {
                switch(message->type)
                {
                    case( MSG_MM_RP_READ ):
                        l_errhdl = readFromDevice( dev_offset,
                                                   chip_select,
                                                   needs_ecc,
                                                   user_addr,
                                                   fatal_error );
                        if( l_errhdl || ( 0 != fatal_error ) )
                        {
                            status_rc = -EIO; /* I/O error */
                        }
                        break;
                    case( MSG_MM_RP_WRITE ):
                        l_errhdl = writeToDevice( dev_offset, chip_select, needs_ecc, user_addr );
                        if( l_errhdl )
                        {
                            status_rc = -EIO; /* I/O error */
                        }
                        break;
                    default:
                        TRACFCOMP( g_trac_pnor, "PnorRP::waitForMessage> Unrecognized message type : user_addr=%p, eff_addr=%p, msgtype=%d", user_addr, eff_addr, message->type );
                        /*@
                         * @errortype
                         * @moduleid     PNOR::MOD_PNORRP_WAITFORMESSAGE
                         * @reasoncode   PNOR::RC_INVALID_MESSAGE_TYPE
                         * @userdata1    Message type
                         * @userdata2    Requested Virtual Address
                         * @devdesc      PnorRP::waitForMessage> Unrecognized
                         *               message type
                         * @custdesc     A problem occurred while accessing
                         *               the boot flash.
                         */
                        l_errhdl = new ERRORLOG::ErrlEntry(
                                           ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                           PNOR::MOD_PNORRP_WAITFORMESSAGE,
                                           PNOR::RC_INVALID_MESSAGE_TYPE,
                                           TO_UINT64(message->type),
                                           (uint64_t)eff_addr,
                                           true /*Add HB SW Callout*/);
                        l_errhdl->collectTrace(PNOR_COMP_NAME);
                        status_rc = -EINVAL; /* Invalid argument */
                }
            }

            if( !l_errhdl && msg_is_async(message) )
            {
                TRACFCOMP( g_trac_pnor, "PnorRP::waitForMessage> Unsupported Asynchronous Message  : user_addr=%p, eff_addr=%p, msgtype=%d", user_addr, eff_addr, message->type );
                /*@
                 * @errortype
                 * @moduleid     PNOR::MOD_PNORRP_WAITFORMESSAGE
                 * @reasoncode   PNOR::RC_INVALID_ASYNC_MESSAGE
                 * @userdata1    Message type
                 * @userdata2    Requested Virtual Address
                 * @devdesc      PnorRP::waitForMessage> Unrecognized message
                 *               type
                 * @custdesc     A problem occurred while accessing the boot
                 *               flash.
                 */
                l_errhdl = new ERRORLOG::ErrlEntry(
                                         ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                         PNOR::MOD_PNORRP_WAITFORMESSAGE,
                                         PNOR::RC_INVALID_ASYNC_MESSAGE,
                                         TO_UINT64(message->type),
                                         (uint64_t)eff_addr,
                                         true /*Add HB SW Callout*/);
                l_errhdl->collectTrace(PNOR_COMP_NAME);
                status_rc = -EINVAL; /* Invalid argument */
            }

            if( l_errhdl )
            {
                errlCommit(l_errhdl,PNOR_COMP_ID);
            }


            /*  Expected Response:
             *      data[0] = virtual address requested
             *      data[1] = rc (0 or negative errno value)
             *      extra_data = Specific reason code.
             */
            message->data[1] = status_rc;
            message->extra_data = reinterpret_cast<void*>(fatal_error);
            rc = msg_respond( iv_msgQ, message );
            if( rc )
            {
                TRACFCOMP(g_trac_pnor, "PnorRP::waitForMessage> Error from msg_respond, giving up : rc=%d", rc );
                break;
            }
        }
    }


    TRACFCOMP(g_trac_pnor, "< PnorRP::waitForMessage" );
}
Example #9
0
/**
 * @brief  Return the size and address of a given section of PNOR data
 */
errlHndl_t PnorRP::getSectionInfo( PNOR::SectionId i_section,
                                   PNOR::SectionInfo_t& o_info )
{
    //TRACDCOMP(g_trac_pnor, "PnorRP::getSectionInfo> i_section=%d", i_section );
    errlHndl_t l_errhdl = NULL;
    PNOR::SectionId id = i_section;

    do
    {
        // Abort this operation if we had a startup failure
        uint64_t rc = 0;
        if( didStartupFail(rc) )
        {
            TRACFCOMP( g_trac_pnor, "PnorRP::getSectionInfo> RP not properly initialized, failing : rc=%X", rc );
            /*@
             * @errortype
             * @moduleid     PNOR::MOD_PNORRP_GETSECTIONINFO
             * @reasoncode   PNOR::RC_STARTUP_FAIL
             * @userdata1    Requested Section
             * @userdata2    Startup RC
             * @devdesc      PnorRP::getSectionInfo> RP not properly initialized
             * @custdesc    A problem occurred while accessing the boot flash.
             */
            l_errhdl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                               PNOR::MOD_PNORRP_GETSECTIONINFO,
                                               PNOR::RC_STARTUP_FAIL,
                                               TO_UINT64(i_section),
                                               rc,
                                               true /*Add HB SW Callout*/);
            l_errhdl->collectTrace(PNOR_COMP_NAME);

            // set the return section to our invalid data
            id = PNOR::INVALID_SECTION;
            break;
        }

        // Zero-length means the section is invalid
        if( 0 == iv_TOC[id].size )
        {
            TRACFCOMP( g_trac_pnor, "PnorRP::getSectionInfo> Invalid Section Requested : i_section=%d", i_section );
            TRACFCOMP(g_trac_pnor, "o_info={ id=%d, size=%d }", iv_TOC[i_section].id, iv_TOC[i_section].size );
            /*@
             * @errortype
             * @moduleid     PNOR::MOD_PNORRP_GETSECTIONINFO
             * @reasoncode   PNOR::RC_INVALID_SECTION
             * @userdata1    Requested Section
             * @userdata2    TOC used
             * @devdesc      PnorRP::getSectionInfo> Invalid Address for read/write
             * @custdesc    A problem occurred while accessing the boot flash.
            */
            l_errhdl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                               PNOR::MOD_PNORRP_GETSECTIONINFO,
                                               PNOR::RC_INVALID_SECTION,
                                               TO_UINT64(i_section),
                                               iv_TOC_used,
                                               true /*Add HB SW Callout*/);
            l_errhdl->collectTrace(PNOR_COMP_NAME);

            // set the return section to our invalid data
            id = PNOR::INVALID_SECTION;
            break;
        }
    } while(0);

    if (PNOR::INVALID_SECTION != id)
    {
        TRACDCOMP( g_trac_pnor, "PnorRP::getSectionInfo: i_section=%d, id=%d", i_section, iv_TOC[i_section].id );

        // copy my data into the external format
        o_info.id = iv_TOC[id].id;
        o_info.name = cv_EYECATCHER[id];
        o_info.vaddr = iv_TOC[id].virtAddr;
        o_info.size = iv_TOC[id].size;
        o_info.eccProtected = ((iv_TOC[id].integrity & FFS_INTEG_ECC_PROTECT)
                                != 0) ? true : false;
        o_info.sha512Version = ((iv_TOC[id].version & FFS_VERS_SHA512)
                                 != 0) ? true : false;
        o_info.sha512perEC = ((iv_TOC[id].version & FFS_VERS_SHA512_PER_EC)
                               != 0) ? true : false;
    }

    return l_errhdl;
}
Example #10
0
/**
 * @brief Initialize the daemon
 */
void PnorRP::initDaemon()
{
    TRACUCOMP(g_trac_pnor, "PnorRP::initDaemon> " );
    errlHndl_t l_errhdl = NULL;

    do
    {
        // read the TOC in the PNOR to compute the sections
        l_errhdl = readTOC();
        if( l_errhdl )
        {
            break;
        }

        // create a message queue
        iv_msgQ = msg_q_create();

        // create a Block, passing in the message queue
        int rc = mm_alloc_block( iv_msgQ, (void*) BASE_VADDR, TOTAL_SIZE );
        if( rc )
        {
            TRACFCOMP( g_trac_pnor, "PnorRP::initDaemon> Error from mm_alloc_block : rc=%d", rc );
            /*@
             * @errortype
             * @moduleid     PNOR::MOD_PNORRP_INITDAEMON
             * @reasoncode   PNOR::RC_EXTERNAL_ERROR
             * @userdata1    Requested Address
             * @userdata2    rc from mm_alloc_block
             * @devdesc      PnorRP::initDaemon> Error from mm_alloc_block
             * @custdesc    A problem occurred while accessing the boot flash.
             */
            l_errhdl = new ERRORLOG::ErrlEntry(
                           ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                           PNOR::MOD_PNORRP_INITDAEMON,
                           PNOR::RC_EXTERNAL_ERROR,
                           TO_UINT64(BASE_VADDR),
                           TO_UINT64(rc),
                           true /*Add HB SW Callout*/);
            l_errhdl->collectTrace(PNOR_COMP_NAME);
            break;
        }

        //Register this memory range to be FLUSHed during a shutdown.
        INITSERVICE::registerBlock(reinterpret_cast<void*>(BASE_VADDR),
                                   TOTAL_SIZE,PNOR_PRIORITY);

        // Need to set permissions to R/W
        rc = mm_set_permission((void*) BASE_VADDR,TOTAL_SIZE,
                               WRITABLE | WRITE_TRACKED);



        // start task to wait on the queue
        task_create( wait_for_message, NULL );

    } while(0);

    if( l_errhdl )
    {
        iv_startupRC = l_errhdl->reasonCode();
        errlCommit(l_errhdl,PNOR_COMP_ID);
    }

    // call ErrlManager function - tell him that PNOR is ready!
    ERRORLOG::ErrlManager::errlResourceReady(ERRORLOG::PNOR);

    TRACUCOMP(g_trac_pnor, "< PnorRP::initDaemon" );
}
Example #11
0
/**
 * @brief Performs a presence detect operation on MCSs
 *
 * Although not a physical part, presence detect confirms access
 * to direct access memory vpd.
 *
 * @param[in]   i_opType        Operation type, see DeviceFW::OperationType
 *                              in driverif.H
 * @param[in]   i_target        Presence detect target
 * @param[in/out] io_buffer     Read: Pointer to output data storage
 *                              Write: Pointer to input data storage
 * @param[in/out] io_buflen     Input: size of io_buffer (in bytes, always 1)
 *                              Output: Success = 1, Failure = 0
 * @param[in]   i_accessType    DeviceFW::AccessType enum (userif.H)
 * @param[in]   i_args          This is an argument list for DD framework.
 *                              In this function, there are no arguments.
 * @return  errlHndl_t
 */
errlHndl_t directMemoryPresenceDetect(DeviceFW::OperationType i_opType,
                              TARGETING::Target* i_target,
                              void* io_buffer,
                              size_t& io_buflen,
                              int64_t i_accessType,
                              va_list i_args)
{
    errlHndl_t l_errl = NULL;
    bool dvpd_present = false;

    TRACSSCOMP(g_trac_vpd,
                  ENTER_MRK "directMemoryPresenceDetect");

    if (unlikely(io_buflen < sizeof(bool)))
    {
        TRACFCOMP(g_trac_vpd,
                  ERR_MRK "directMemoryPresenceDetect> Invalid data length: %d",
                  io_buflen);
        /*@
         * @errortype
         * @moduleid     VPD::VPD_DVPD_PRESENCEDETECT
         * @reasoncode   VPD::VPD_INVALID_LENGTH
         * @userdata1    Data Length
         * @devdesc      presenceDetect> Invalid data length (!= 1 bytes)
         */
        l_errl =
                new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                        VPD::VPD_DVPD_PRESENCEDETECT,
                                        VPD::VPD_INVALID_LENGTH,
                                        TO_UINT64(io_buflen),
                                        true /*SW error*/);
        io_buflen = 0;
        return l_errl;
    }

    dvpd_present = DVPD::dvpdPresent( i_target );
#if defined(CONFIG_MEMVPD_READ_FROM_HW) && defined(CONFIG_MEMVPD_READ_FROM_PNOR)
    //skipping cache sync when dvpd is present as it will be taken care by node
    //vpd
    if( !dvpd_present )
    {
        TRACFCOMP(g_trac_vpd,
                  ERR_MRK "directMemoryPresenceDetect> failed presence detect");

        // Defer invalidating DVPD in the PNOR in case another target might be
        // sharing this VPD_REC_NUM. Check all targets sharing this
        // VPD_REC_NUM after target discovery in VPD::validateSharedPnorCache.
        // Ensure the VPD_SWITCHES cache valid bit is invalid at this point.
        TARGETING::ATTR_VPD_SWITCHES_type vpdSwitches =
        i_target->getAttr<TARGETING::ATTR_VPD_SWITCHES>();
        vpdSwitches.pnorCacheValid = 0;
        i_target->setAttr<TARGETING::ATTR_VPD_SWITCHES>( vpdSwitches );
    }
#endif

    memcpy(io_buffer, &dvpd_present, sizeof(dvpd_present));
    io_buflen = sizeof(dvpd_present);

    TRACSSCOMP(g_trac_vpd,
                  EXIT_MRK "directMemoryPresenceDetect = %d",dvpd_present);
    return NULL;
}
Example #12
0
// ------------------------------------------------------------------
// dimmPresenceDetect
// ------------------------------------------------------------------
errlHndl_t dimmPresenceDetect( DeviceFW::OperationType i_opType,
                               TARGETING::Target * i_target,
                               void * io_buffer,
                               size_t & io_buflen,
                               int64_t i_accessType,
                               va_list i_args )
{
    errlHndl_t err = NULL;
    bool present = false;
    size_t presentSz = sizeof(present);

    TRACSSCOMP( g_trac_spd,
                ENTER_MRK"dimmPresenceDetect()" );

    do
    {
        // Check to be sure that the buffer is big enough.
        if( !(io_buflen >= sizeof(bool)) )
        {
            TRACFCOMP( g_trac_spd,
                       ERR_MRK"dimmPresenceDetect() - Invalid Data Length: %d",
                       io_buflen );

            /*@
             * @errortype
             * @reasoncode       VPD::VPD_INSUFFICIENT_BUFFER_SIZE
             * @severity         ERRORLOG::ERRL_SEV_UNRECOVERABLE
             * @moduleid         VPD::VPD_SPD_PRESENCE_DETECT
             * @userdata1        Buffer Length
             * @userdata2        <UNUSED>
             * @devdesc          Buffer for checking Presence Detect
             *                   was not the correct size.
             */
            err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                           VPD::VPD_SPD_PRESENCE_DETECT,
                                           VPD::VPD_INSUFFICIENT_BUFFER_SIZE,
                                           TO_UINT64(io_buflen),
                                           0x0,
                                           true /*Add HB Software Callout*/);

            err->collectTrace( "SPD", 256);

            break;
        }

        // Is the target present
#ifdef CONFIG_DJVPD_READ_FROM_HW
        // Check if the parent MBA/MEMBUF is present.  If it is not then
        // no reason to check the DIMM which would otherwise generate
        // tons of FSI errors.  We can't just check if parent MBA
        // is functional because DIMM presence detect is called before
        // the parent MBA/MEMBUF is set as present/functional.
        TARGETING::TargetHandleList membufList;
        TARGETING::PredicateCTM membufPred( TARGETING::CLASS_CHIP,
                                            TARGETING::TYPE_MEMBUF );
        TARGETING::targetService().getAssociated(
            membufList,
            i_target,
            TARGETING::TargetService::PARENT_BY_AFFINITY,
            TARGETING::TargetService::ALL,
            &membufPred);

        bool parentPresent = false;
        const TARGETING::TargetHandle_t membufTarget = *(membufList.begin());

        err = deviceRead(membufTarget, &parentPresent, presentSz,
                                DEVICE_PRESENT_ADDRESS());
        if (err)
        {
            TRACFCOMP(
                g_trac_spd,
                "Error reading parent MEMBUF present: huid 0x%X DIMM huid 0x%X",
                TARGETING::get_huid(membufTarget),
                TARGETING::get_huid(i_target) );
            break;
        }
        if (!parentPresent)
        {
            present = false;
            // Invalidate the SPD in PNOR
            err = VPD::invalidatePnorCache(i_target);
            if (err)
            {
                TRACFCOMP( g_trac_spd, "Error invalidating SPD in PNOR" );
            }
            break;
        }
#endif

        present = spdPresent( i_target );

        if( present == false )
        {
            TRACUCOMP( g_trac_spd,
                       INFO_MRK"Dimm was found to be NOT present." );
        }
        else
        {
            TRACUCOMP( g_trac_spd,
                       INFO_MRK"Dimm was found to be present." );
        }

#if defined(CONFIG_DJVPD_READ_FROM_HW) && defined(CONFIG_DJVPD_READ_FROM_PNOR)
        if( present )
        {
            // Check if the VPD data in the PNOR matches the SEEPROM
            err = VPD::ensureCacheIsInSync( i_target );
            if( err )
            {
                present = false;

                TRACFCOMP(g_trac_spd,ERR_MRK "dimmPresenceDetectt> Error during ensureCacheIsInSync (SPD)" );
                break;
            }
        }
        else
        {
            // SPD is not present, invalidate the SPD in PNOR
            err = VPD::invalidatePnorCache(i_target);
            if (err)
            {
                TRACFCOMP( g_trac_spd, "Error invalidating SPD in PNOR" );
            }
        }
#endif

        if( present && !err )
        {
            //Fsp sets PN/SN so if there is none, do it here
            if(!INITSERVICE::spBaseServicesEnabled())
            {
                //populate serial and part number attributes
                SPD::setPartAndSerialNumberAttributes( i_target );
            }

            // Read ATTR_CLEAR_DIMM_SPD_ENABLE attribute
            TARGETING::Target* l_sys = NULL;
            TARGETING::targetService().getTopLevelTarget(l_sys);

            TARGETING::ATTR_CLEAR_DIMM_SPD_ENABLE_type l_clearSPD =
                l_sys->getAttr<TARGETING::ATTR_CLEAR_DIMM_SPD_ENABLE>();

            // If SPD clear is enabled then write 0's into magic word for 
            // DIMM_BAD_DQ_DATA keyword
            // Note: If there's an error from performing the clearing,
            // just log the error and continue.
            if (l_clearSPD)
            {
                size_t l_size = 0;

                // Do a read to get the DIMM_BAD_DQ_DATA keyword size
                err = deviceRead(i_target, NULL, l_size,
                                 DEVICE_SPD_ADDRESS( DIMM_BAD_DQ_DATA ));
                if (err)
                {
                    TRACFCOMP(g_trac_spd, "dimmPresenceDetect - "
                        "Error reading DIMM_BAD_DQ_DATA keyword size");
                    errlCommit( err, VPD_COMP_ID );
                }
                else
                {
                    // Clear the data
                    TRACFCOMP( g_trac_spd, "Clearing out BAD_DQ_DATA SPD on "
                               "DIMM HUID 0x%X",
                               TARGETING::get_huid(i_target));

                    uint8_t * l_data = static_cast<uint8_t*>(malloc( l_size ));
                    memset(l_data, 0, l_size);

                    err = deviceWrite(i_target, l_data, l_size,
                                     DEVICE_SPD_ADDRESS( DIMM_BAD_DQ_DATA ));
                    if (err)
                    {
                        TRACFCOMP( g_trac_spd, "Error trying to clear SPD on "
                                   "DIMM HUID 0x%X",
                                   TARGETING::get_huid(i_target));
                        errlCommit( err, VPD_COMP_ID );
                    }

                    // Free the memory
                    if (NULL != l_data)
                    {
                        free(l_data);
                    }
                }
            }
        }

        // copy present value into output buffer so caller can read it
        memcpy( io_buffer, &present, presentSz );
        io_buflen = presentSz;

    } while( 0 );

    TRACSSCOMP( g_trac_spd,
                EXIT_MRK"dimmPresenceDetect()" );

    return err;
} // end dimmPresenceDetect
Example #13
0
// ------------------------------------------------------------------
// dimmPresenceDetect
// ------------------------------------------------------------------
errlHndl_t dimmPresenceDetect( DeviceFW::OperationType i_opType,
                               TARGETING::Target * i_target,
                               void * io_buffer,
                               size_t & io_buflen,
                               int64_t i_accessType,
                               va_list i_args )
{
    errlHndl_t err = NULL;
    bool present = false;
    size_t presentSz = sizeof(present);

    TRACSSCOMP( g_trac_spd, ENTER_MRK"dimmPresenceDetect() "
                "DIMM HUID 0x%X", TARGETING::get_huid(i_target));
    do
    {
        // Check to be sure that the buffer is big enough.
        if( !(io_buflen >= sizeof(bool)) )
        {
            TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() "
                       "Invalid Data Length: %d",
                       io_buflen );

            /*@
             * @errortype
             * @reasoncode       VPD::VPD_INSUFFICIENT_BUFFER_SIZE
             * @severity         ERRORLOG::ERRL_SEV_UNRECOVERABLE
             * @moduleid         VPD::VPD_SPD_PRESENCE_DETECT
             * @userdata1        Buffer Length
             * @userdata2        <UNUSED>
             * @devdesc          Buffer for checking Presence Detect
             *                   was not the correct size.
             */
            err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                           VPD::VPD_SPD_PRESENCE_DETECT,
                                           VPD::VPD_INSUFFICIENT_BUFFER_SIZE,
                                           TO_UINT64(io_buflen),
                                           0x0,
                                           true /*Add HB Software Callout*/);

            err->collectTrace( "SPD", 256);

            break;
        }

        // Is the target present?
#ifdef CONFIG_DJVPD_READ_FROM_HW
        // Check if the i2c master is present.
        // If it is not then no reason to check the DIMM which would
        // otherwise generate tons of FSI errors.
        // We can't just check if parent MCA or MBA
        // is functional because DIMM presence detect is called before
        // the parent MCS/MCA or MBA/MEMBUF is set as present/functional.
        bool l_i2cMasterPresent = false;

        do
        {
            // get eeprom vpd primary info
            TARGETING::EepromVpdPrimaryInfo eepromData;
            if( !(i_target->
                     tryGetAttr<TARGETING::ATTR_EEPROM_VPD_PRIMARY_INFO>
                         ( eepromData ) ) )
            {
                TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() "
                           "Error: no eeprom vpd primary info" );
                break;
            }

            // find i2c master target
            TARGETING::TargetService& tS = TARGETING::targetService();
            bool exists = false;
            tS.exists( eepromData.i2cMasterPath, exists );
            if( !exists )
            {
                TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() "
                           "i2cMasterPath attribute path doesn't exist");
                break;
            }

            // Since it exists, convert to a target
            TARGETING::Target * l_i2cMasterTarget =
                                   tS.toTarget( eepromData.i2cMasterPath );

            if( NULL == l_i2cMasterTarget )
            {
                TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() "
                           "i2cMasterPath target is NULL");
                break;
            }
            TRACSSCOMP( g_trac_spd, "dimmPresenceDetect() "
                "i2c master HUID 0x%X", TARGETING::get_huid(l_i2cMasterTarget));

            // Check if present
            TARGETING::Target* masterProcTarget = NULL;
            TARGETING::targetService().masterProcChipTargetHandle(
                                                        masterProcTarget );
            // Master proc is taken as always present. Validate other targets.
            if (l_i2cMasterTarget != masterProcTarget)
            {
                l_i2cMasterPresent = FSI::isSlavePresent(l_i2cMasterTarget);
                if( !l_i2cMasterPresent )
                {
                    TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() "
                               "isSlavePresent failed");
                    break;
                }
            }
            l_i2cMasterPresent = true;
        }
        while (0);

        if (!l_i2cMasterPresent)
        {
            present = false;
            // Invalidate the SPD in PNOR
            err = VPD::invalidatePnorCache(i_target);
            if (err)
            {
                TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() "
                           "Error invalidating SPD in PNOR" );
            }
            break;
        }
#endif

        present = spdPresent( i_target );

        if( present == false )
        {
            TRACUCOMP( g_trac_spd, INFO_MRK"dimmPresenceDetect() "
                       "Dimm was found to be NOT present." );
        }
        else
        {
            TRACUCOMP( g_trac_spd, INFO_MRK"dimmPresenceDetect() "
                       "Dimm was found to be present." );
        }

#if defined(CONFIG_DJVPD_READ_FROM_HW) && defined(CONFIG_DJVPD_READ_FROM_PNOR)
        if( present )
        {
            // Check if the VPD data in the PNOR matches the SEEPROM
            err = VPD::ensureCacheIsInSync( i_target );
            if( err )
            {
                present = false;
                TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() "
                           "Error during ensureCacheIsInSync (SPD)" );
                break;
            }
        }
        else
        {
            // SPD is not present, invalidate the SPD in PNOR
            err = VPD::invalidatePnorCache(i_target);
            if (err)
            {
                TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() "
                           "Error invalidating SPD in PNOR" );
            }
        }
#endif

        if( present && !err )
        {
            //Fsp sets PN/SN so if there is none, do it here
            if(!INITSERVICE::spBaseServicesEnabled())
            {
                //populate serial and part number attributes
                SPD::setPartAndSerialNumberAttributes( i_target );
            }

            // Read ATTR_CLEAR_DIMM_SPD_ENABLE attribute
            TARGETING::Target* l_sys = NULL;
            TARGETING::targetService().getTopLevelTarget(l_sys);

            TARGETING::ATTR_CLEAR_DIMM_SPD_ENABLE_type l_clearSPD =
                l_sys->getAttr<TARGETING::ATTR_CLEAR_DIMM_SPD_ENABLE>();

            // If SPD clear is enabled then write 0's into magic word for
            // DIMM_BAD_DQ_DATA keyword
            // Note: If there's an error from performing the clearing,
            // just log the error and continue.
            if (l_clearSPD)
            {
                size_t l_size = 0;

                // Do a read to get the DIMM_BAD_DQ_DATA keyword size
                err = deviceRead(i_target, NULL, l_size,
                                 DEVICE_SPD_ADDRESS( DIMM_BAD_DQ_DATA ));
                if (err)
                {
                    TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() "
                        "Error reading DIMM_BAD_DQ_DATA keyword size");
                    errlCommit( err, VPD_COMP_ID );
                }
                else
                {
                    // Clear the data
                    TRACFCOMP( g_trac_spd, "Clearing out BAD_DQ_DATA SPD on "
                               "DIMM HUID 0x%X",
                               TARGETING::get_huid(i_target));

                    uint8_t * l_data = static_cast<uint8_t*>(malloc( l_size ));
                    memset(l_data, 0, l_size);

                    err = deviceWrite(i_target, l_data, l_size,
                                     DEVICE_SPD_ADDRESS( DIMM_BAD_DQ_DATA ));
                    if (err)
                    {
                        TRACFCOMP(g_trac_spd, ERR_MRK"dimmPresenceDetect() "
                                  "Error trying to clear SPD on DIMM HUID 0x%X",
                                  TARGETING::get_huid(i_target));
                        errlCommit( err, VPD_COMP_ID );
                    }

                    // Free the memory
                    if (NULL != l_data)
                    {
                        free(l_data);
                    }
                }
            }
        }

        // copy present value into output buffer so caller can read it
        memcpy( io_buffer, &present, presentSz );
        io_buflen = presentSz;

    } while( 0 );

    TRACSSCOMP( g_trac_spd, EXIT_MRK"dimmPresenceDetect()" );

    return err;
} // end dimmPresenceDetect
Example #14
0
errlHndl_t fsiScomPerformOp(DeviceFW::OperationType i_opType,
                         TARGETING::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_scomAddr = va_arg(i_args,uint64_t);
    ioData6432 scratchData;
    uint32_t l_command = 0;
    uint32_t l_status = 0;
    bool need_unlock = false;
    size_t op_size = sizeof(uint32_t);
    mutex_t* l_mutex = NULL;

    do{

        if( io_buflen != sizeof(uint64_t) )
        {
            TRACFCOMP( g_trac_fsiscom, ERR_MRK "fsiScomPerformOp> Invalid data length : io_buflen=%d", io_buflen );
            /*@
             * @errortype
             * @moduleid     FSISCOM::MOD_FSISCOM_PERFORMOP
             * @reasoncode   FSISCOM::RC_INVALID_LENGTH
             * @userdata1    SCOM Address
             * @userdata2    Data Length
             * @devdesc      fsiScomPerformOp> Invalid data length (!= 8 bytes)
             * @custdesc     A problem occurred during the IPL of the system:
             *               Invalid data length for a SCOM operation.
             */
            l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                            FSISCOM::MOD_FSISCOM_PERFORMOP,
                                            FSISCOM::RC_INVALID_LENGTH,
                                            l_scomAddr,
                                            TO_UINT64(io_buflen));
            l_err->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE,
                                        HWAS::SRCI_PRIORITY_LOW );
            ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target").
              addToLog(l_err);
            break;
        }

        if( (l_scomAddr & 0xFFFFFFFF80000000) != 0)
        {
            TRACFCOMP( g_trac_fsiscom, ERR_MRK "fsiScomPerformOp> Address contains more than 31 bits : l_scomAddr=0x%.16X", l_scomAddr );
            /*@
             * @errortype
             * @moduleid     FSISCOM::MOD_FSISCOM_PERFORMOP
             * @reasoncode   FSISCOM::RC_INVALID_ADDRESS
             * @userdata1    SCOM Address
             * @userdata2    Target HUID
             * @devdesc      fsiScomPerformOp> Address contains
             *               more than 31 bits.
             * @custdesc     A problem occurred during the IPL of the system:
             *               Invalid address on a SCOM operation.
             */
            l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                            FSISCOM::MOD_FSISCOM_PERFORMOP,
                                            FSISCOM::RC_INVALID_ADDRESS,
                                            l_scomAddr,
                                            TARGETING::get_huid(i_target));
            l_err->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE,
                                        HWAS::SRCI_PRIORITY_LOW );
            ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target").
              addToLog(l_err);
            break;
        }

        l_command = static_cast<uint32_t>(l_scomAddr & 0x000000007FFFFFFF);

        // use the chip-specific mutex attribute
        l_mutex = i_target->getHbMutexAttr<TARGETING::ATTR_FSI_SCOM_MUTEX>();

        if(i_opType == DeviceFW::WRITE)
        {
            memcpy(&(scratchData.data64), io_buffer, 8);

            TRACUCOMP( g_trac_fsiscom, "fsiScomPerformOp> Write(l_scomAddr=0x%X, l_data0=0x%X, l_data1=0x%X)", l_scomAddr, scratchData.data32_0, scratchData.data32_1);


            // atomic section >>
            mutex_lock(l_mutex);
            need_unlock = true;


            //write bits 0-31 to data0
            l_err = DeviceFW::deviceOp( DeviceFW::WRITE,
                                        i_target,
                                        &scratchData.data32_0,
                                        op_size,
                                        DEVICE_FSI_ADDRESS(DATA0_REG));
            if(l_err)
            {
                break;
            }

            //write bits 32-63 to data1
            l_err = DeviceFW::deviceOp( DeviceFW::WRITE,
                                        i_target,
                                        &scratchData.data32_1,
                                        op_size,
                                        DEVICE_FSI_ADDRESS(DATA1_REG));
            if(l_err)
            {
                break;
            }

            //write to FSI2PIB command reg starts write operation
             //bit 0 high => write command
            l_command = 0x80000000 | l_command;
            l_err = DeviceFW::deviceOp( DeviceFW::WRITE,
                                        i_target,
                                        &l_command,
                                        op_size,
                                        DEVICE_FSI_ADDRESS(COMMAND_REG));
            if(l_err)
            {
                break;
            }

            //check status reg to see result
            l_err = DeviceFW::deviceOp( DeviceFW::READ,
                                        i_target,
                                        &l_status,
                                        op_size,
                                        DEVICE_FSI_ADDRESS(STATUS_REG));
            if(l_err)
            {
                break;
            }

            // Check the status reg for errors
            if( (l_status & PIB_ERROR_BITS)      // PCB/PIB Errors
                || (l_status & PIB_ABORT_BIT)  ) // PIB Abort
            {
                TRACFCOMP( g_trac_fsiscom, ERR_MRK"fsiScomPerformOp:Write: PCB/PIB error received: l_status=0x%X)", l_status);
                /*@
                 * @errortype
                 * @moduleid     FSISCOM::MOD_FSISCOM_PERFORMOP
                 * @reasoncode   FSISCOM::RC_WRITE_ERROR
                 * @userdata1    SCOM Addr
                 * @userdata2[00:31]  Target HUID
                 * @userdata2[32:63]  SCOM Status Reg
                 * @devdesc      fsiScomPerformOp> Error returned
                 *               from SCOM Engine after write
                 * @custdesc     A problem occurred during the IPL of the system:
                 *               Error returned from SCOM engine after write.
                 */
                l_err = new ERRORLOG::ErrlEntry(
                                ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                FSISCOM::MOD_FSISCOM_PERFORMOP,
                                FSISCOM::RC_WRITE_ERROR,
                                l_scomAddr,
                                TWO_UINT32_TO_UINT64(
                                           TARGETING::get_huid(i_target),
                                           l_status));

                // call common error handler to do callouts and recovery
                pib_error_handler( i_target, l_err, l_status, l_scomAddr );

                //Grab the PIB2OPB Status reg for a XSCOM Block error
                if( (l_status & 0x00007000) == 0x00001000 ) //piberr=001
                {
                    //@todo: Switch to external FSI FFDC interfaces RTC:35064
                    TARGETING::Target* l_master = NULL;
                    TARGETING::targetService().
                      masterProcChipTargetHandle(l_master);

                    uint64_t scomdata = 0;
                    size_t scomsize = sizeof(uint64_t);
                    errlHndl_t l_err2 = DeviceFW::deviceOp( DeviceFW::READ,
                                           l_master,
                                           &scomdata,
                                           scomsize,
                                           DEVICE_XSCOM_ADDRESS(0x00020001));
                    if( l_err2 ) {
                        delete l_err2;
                    } else {
                        TRACFCOMP( g_trac_fsiscom, "PIB2OPB Status = %.16X", scomdata );
                    }
                }

                break;
            }

            // atomic section <<
            need_unlock = false;
            mutex_unlock(l_mutex);
        }
        else if(i_opType == DeviceFW::READ)
        {
            TRACUCOMP( g_trac_fsiscom, "fsiScomPerformOp: Read(l_scomAddr=0x%.8X)", l_scomAddr);

            // atomic section >>
            mutex_lock(l_mutex);
            need_unlock = true;


            //write to FSI2PIB command reg starts read operation
            // bit 0 low -> read command
            l_err = DeviceFW::deviceOp( DeviceFW::WRITE,
                                        i_target,
                                        &l_command,
                                        op_size,
                                        DEVICE_FSI_ADDRESS(COMMAND_REG));
            if(l_err)
            {
                break;
            }

            //check ststus reg to see result
            l_err = DeviceFW::deviceOp( DeviceFW::READ,
                                        i_target,
                                        &l_status,
                                        op_size,
                                        DEVICE_FSI_ADDRESS(STATUS_REG));
            if(l_err)
            {
                break;
            }

            // Check the status reg for errors
            if( (l_status & PIB_ERROR_BITS)      // PCB/PIB Errors
                || (l_status & PIB_ABORT_BIT)  ) // PIB Abort
            {
                TRACFCOMP( g_trac_fsiscom, ERR_MRK"fsiScomPerformOp:Read: PCB/PIB error received: l_status=0x%0.8X)", l_status);

                /*@
                 * @errortype
                 * @moduleid     FSISCOM::MOD_FSISCOM_PERFORMOP
                 * @reasoncode   FSISCOM::RC_READ_ERROR
                 * @userdata1    SCOM Addr
                 * @userdata2[00:31]  Target HUID
                 * @userdata2[32:63]  SCOM Status Reg
                 * @devdesc      fsiScomPerformOp> Error returned from SCOM Engine after read.
                 * @custdesc     A problem occurred during the IPL of the system:
                 *               Error returned from SCOM engine after read.
                 */
                l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                                FSISCOM::MOD_FSISCOM_PERFORMOP,
                                                FSISCOM::RC_READ_ERROR,
                                                l_scomAddr,
                                                TWO_UINT32_TO_UINT64(
                                                 TARGETING::get_huid(i_target),
                                                 l_status));

                // call common error handler to do callouts and recovery
                pib_error_handler( i_target, l_err, l_status, l_scomAddr );

                break;
            }

            //read bits 0-31 to data0
            l_err = DeviceFW::deviceOp( DeviceFW::READ,
                                        i_target,
                                        &scratchData.data32_0,
                                        op_size,
                                        DEVICE_FSI_ADDRESS(DATA0_REG));
            if(l_err)
            {
                break;
            }

            //read bits 32-63 to data1
            l_err = DeviceFW::deviceOp( DeviceFW::READ,
                                        i_target,
                                        &scratchData.data32_1,
                                        op_size,
                                        DEVICE_FSI_ADDRESS(DATA1_REG));
            if(l_err)
            {
                break;
            }

            // atomic section <<
            need_unlock = false;
            mutex_unlock(l_mutex);

            TRACUCOMP( g_trac_fsiscom, "fsiScomPerformOp: Read: l_scomAddr=0x%X, l_data0=0x%X, l_data1=0x%X", l_scomAddr, scratchData.data32_0, scratchData.data32_1);

             memcpy(io_buffer, &(scratchData.data64), 8);
        }
        else
        {
            TRACFCOMP( g_trac_fsiscom, ERR_MRK"fsiScomPerformOp:Unsupported Operation Type: i_opType=%d)", i_opType);

            /*@
             * @errortype
             * @moduleid     FSISCOM::MOD_FSISCOM_PERFORMOP
             * @reasoncode   FSISCOM::RC_INVALID_OPTYPE
             * @userdata1[0:31]    Operation Type (i_opType) : 0=READ, 1=WRITE
             * @userdata1[32:64]   Input scom address
             * @userdata2    Target HUID
             * @devdesc      fsiScomPerformOp> Unsupported Operation Type specified
             * @custdesc     A problem occurred during the IPL of the system:
             *               Unsupported SCOM operation type.
             */
            l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                            FSISCOM::MOD_FSISCOM_PERFORMOP,
                                            FSISCOM::RC_INVALID_OPTYPE,
                                            TWO_UINT32_TO_UINT64(i_opType,
                                                                 l_scomAddr),
                                            TARGETING::get_huid(i_target),
                                            true /*SW error*/);
            //Add this target to the FFDC
            ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target").
              addToLog(l_err);

            break;

        }

    }while(0);

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


    return l_err;

}