/*
 * Copyright (C) Jan 2013 Mellanox Technologies Ltd. All rights reserved.
 * Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 *
 * This software is available to you under a choice of one of two
 * licenses.  You may choose to be licensed under the terms of the GNU
 * General Public License (GPL) Version 2, available from the file
 * COPYING in the main directory of this source tree, or the
 * OpenIB.org BSD license below:
 *
 *     Redistribution and use in source and binary forms, with or
 *     without modification, are permitted provided that the following
 *     conditions are met:
 *
 *      - Redistributions of source code must retain the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer.
 *
 *      - Redistributions in binary form must reproduce the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */
 /*
  * fw_comps_mgr.cpp
  *
  *  Created on: Jul 31, 2016
  *      Author: adham
  */
#include "fw_comps_mgr.h"
#include "fw_comps_mgr_abstract_access.h"
#include "fw_comps_mgr_dma_access.h"
#include "bit_slice.h"
#include <signal.h>

#include "mflash/mflash_access_layer.h"
#ifndef UEFI_BUILD
#include <mft_sig_handler.h>
#include "mad_ifc/mad_ifc.h"
#else
// no signal handling.
static void mft_signal_set_handling(int isOn)
{
    return;
}
#endif

#include <errno.h>
 
static mfile* mopen_fw_ctx(void *fw_cmd_context, void *fw_cmd_func, void *dma_func, void *extra_data)
{

    if (fw_cmd_context == NULL || fw_cmd_func == NULL || extra_data == NULL) {
        errno = EINVAL;
        return NULL;
    }

    mfile *mf = (mfile *)malloc(sizeof(mfile));

    if (!mf) {
        errno = ENOMEM;
        return NULL;
    }

    memset(mf, 0, sizeof(mfile));
    mf->flags = MDEVS_FWCTX;
    mf->tp = MST_FWCTX;
    mf->context.fw_cmd_context = fw_cmd_context;
    mf->context.fw_cmd_func = fw_cmd_func;
    mf->context.fw_cmd_dma = dma_func;
    mf->sock = -1; // we are not opening remotely
    return mf;
}

const char*  StateNames[256] = {
"FSMST_IDLE",
"FSMST_LOCKED",
"FSMST_INITIALIZE",
"FSMST_DOWNLOAD",
"FSMST_VERIFY",
"FSMST_APPLY",
"FSMST_ACTIVATE",
"FSMST_UPLOAD",
"FSMST_UPLOAD_PENDING",
"FSMST_DOWNSTREAM_DEVICE_TRANSFER",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT",
"FSMST_NOT_IMPORTANT"
};


const char* CommandsName[256] =  {
    "QUERY",
    "CMD_LOCK_UPDATE_HANDLE",
    "CMD_RELEASE_UPDATE_HANDLE",
    "CMD_UPDATE_COMPONENT",
    "CMD_VERIFY_COMPONENT",
    "CMD_ACTIVATE_COMPONENET",
    "CMD_ACTIVATE_ALL",
    "CMD_READ_COMPONENT",
    "CMD_CANCEL",
    "CMD_CHECK_UPDATE_HANDLE",
    "CMD_FORCE_HANDLE_RELEASE",
    "CMD_READ_PENDING_COMPONENT",
    "CMD_DOWNSTREAM_DEVICE_TRANSFER",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND",
    "NO_COMMAND"
};


#define DEFAULT_SIZE 64
#define MAX_TOUT 3000
#define REG_ACCESS_TOUT 100
#define SLEEP_TIME 80
#define MAX_SLEEP_TIME 800
#define INIT_PARTITION_SLEEP_TIME 240

#define MTCR_IB_TIMEOUT_VAR "MTCR_IB_TIMEOUT"
#define MTCR_IB_TIMEOUT_VAL "30000"

#define NV_BASE_MAC_GUID_IDX     0x02
#define NV_BASE_MAC_GUID_CAP_IDX 0x03



/*
 * Wrapper to call the NVDA command
 */

bool FwCompsMgr::runNVDA(std::vector<u_int8_t>& buff,
                         u_int16_t len,
                         u_int32_t tlvType,
                         reg_access_method_t method,
                         bool queryDefault)
{
    struct tools_open_nvda nvdaTlv;
    memset(&nvdaTlv, 0, sizeof(struct tools_open_nvda));

    nvdaTlv.nv_hdr.length = len;
    if (queryDefault) {
        nvdaTlv.nv_hdr.default_ = 1;
    }
    // tlvType should be in the correct endianess
    nvdaTlv.nv_hdr.type.tlv_type_dw.tlv_type_dw = tlvType;
    if (method == REG_ACCESS_METHOD_SET) {
        memcpy(nvdaTlv.data, buff.data(), len);
    }
    MError rc;
    // "suspend" signals as we are going to take semaphores
    mft_signal_set_handling(1);
    rc = reg_access_nvda(_mf, method, &nvdaTlv);
    deal_with_signal();
    if (rc) {
        _lastError = regErrTrans(rc);
        setLastRegisterAccessStatus(rc);
        return false;
    }
    if (buff.size() < nvdaTlv.nv_hdr.length) {
        buff.resize(nvdaTlv.nv_hdr.length);
    }
    memcpy(buff.data(), nvdaTlv.data, nvdaTlv.nv_hdr.length);
    return true;
}

bool FwCompsMgr::accessComponent(u_int32_t offset,
    u_int32_t size,
    u_int32_t data[],
    access_type_t access,
    ProgressCallBackAdvSt *progressFuncAdv,
    control_fsm_args_t* lastFsmCommandArgs)
{
    bool bRes = _accessObj->accessComponent(_updateHandle, offset, size, data, access, _currComponentStr, progressFuncAdv);
    if (!bRes && lastFsmCommandArgs != NULL && isDMAAccess()) {
        printf("\nBurning with DMA has failed, switching to Register-Access burn.\n");
        bRes = fallbackToRegisterAccess();

        if (bRes) {
            if (!controlFsm(FSM_CMD_CANCEL, FSMST_LOCKED)) {
                DPRINTF(("Cancel instruction to FW component has failed!\n"));
                return false;
            }
            if (!controlFsm(lastFsmCommandArgs->command, lastFsmCommandArgs->expectedState, lastFsmCommandArgs->size,
                            lastFsmCommandArgs->currentState, lastFsmCommandArgs->progressFuncAdv, lastFsmCommandArgs->reg_access_timeout)) {
                DPRINTF(("FSM reinitialize for fallback has failed!\n"));
                return false;
            }

            bRes = _accessObj->accessComponent(_updateHandle, offset, size, data, access, _currComponentStr, progressFuncAdv);
        }
    }

    setLastFirmwareError(_accessObj->getLastFirmwareError());
    setLastRegisterAccessStatus(_accessObj->getLastRegisterAccessStatus());
    return bRes;
}

bool FwCompsMgr::isDMAAccess()
{
    return (dynamic_cast<DMAComponentAccess*>(_accessObj) != NULL);
}

bool FwCompsMgr::fallbackToRegisterAccess() 
{
    bool bRes = false;
    AbstractComponentAccess* newAccessObj = NULL;

    ComponentAccessFactory* factory = ComponentAccessFactory::GetInstance();
    newAccessObj = factory->createDataAccessObject(this, _mf, false);

    if (newAccessObj != NULL) {
        delete _accessObj;
        _accessObj = newAccessObj;
        bRes = true;
    }

    return bRes;
}

const char* FwCompsMgr::stateToStr(fsm_state_t st)
{
    switch (st) {
    case FSMST_INITIALIZE:
        return "Initializing image partition";
    case FSMST_DOWNSTREAM_DEVICE_TRANSFER:
        return "Transferring data do LNKX device";
    default:
        return "Progress";
    }
}

const char* FwCompsMgr::commandToStr(fsm_command_t cmd)
{
    switch (cmd) {
    case FSM_CMD_VERIFY_COMPONENT:
        return "Verifying component";

    case FSM_CMD_UPDATE_COMPONENT:
        return "Updating component";

    default:
        return "Unknown Command";
    }
}


bool FwCompsMgr::controlFsm(fsm_command_t command,
    fsm_state_t expectedState,
    u_int32_t size,
    fsm_state_t currentState,
    ProgressCallBackAdvSt *progressFuncAdv,
    u_int32_t reg_access_timeout)
{
    reg_access_status_t rc = ME_OK;
    reg_access_method_t method = REG_ACCESS_METHOD_SET;
    if (!reg_access_timeout) {
        reg_access_timeout = MAX_TOUT;
    }
    if (currentState != FSMST_NA || expectedState != FSMST_NA) {
        DPRINTF(("controlFsm : command %s current state %s expected state %s\n", CommandsName[command], StateNames[currentState], StateNames[expectedState]));
    }
    unsigned int count = 0;
    do {
        unsigned sleep_time = SLEEP_TIME;
        if ((currentState == FSMST_DOWNSTREAM_DEVICE_TRANSFER && expectedState == FSMST_LOCKED) ||
            (_linkXFlow && currentState == FSMST_ACTIVATE)){
            sleep_time = MAX_SLEEP_TIME;
        }
        if (count) {
            msleep(sleep_time);
        }
        method = REG_ACCESS_METHOD_SET;
        if (command == FSM_QUERY) {
            method = REG_ACCESS_METHOD_GET;
        }
        mft_signal_set_handling(1);
        memset(&_lastFsmCtrl, 0, sizeof(_lastFsmCtrl));
        _lastFsmCtrl.instruction = command;
        _lastFsmCtrl.device_type = _deviceType;
        _lastFsmCtrl.device_index = _deviceIndex;
        _lastFsmCtrl.component_index = _componentIndex;
        _lastFsmCtrl.component_size = size;
        _lastFsmCtrl.update_handle = _updateHandle;
        if(command == FSM_CMD_DOWNSTREAM_DEVICE_TRANSFER || (_linkXFlow && command == FSM_CMD_ACTIVATE_ALL)) {
            _lastFsmCtrl.component_index = 0;// This the FW need - for downstream need to work with 0/device_id or auto_update
            if (_autoUpdate) {
                _lastFsmCtrl.auto_update = 1;
                _lastFsmCtrl.device_index_size = 0;
            }
            else {
                _lastFsmCtrl.auto_update = 0;
                _lastFsmCtrl.device_index_size = _linkXDeviceSize;
                _lastFsmCtrl.device_index = _linkXDeviceIndex;
            }
            if (_linkXFlow && command == FSM_CMD_ACTIVATE_ALL) {
                _lastFsmCtrl.activation_delay_sec = _activation_delay_sec;
                _isDelayedActivationCommandSent = _activation_delay_sec > 0;
            }
        }
        rc = reg_access_mcc(_mf, method, &_lastFsmCtrl);
        //add here auto_update + device_index_size
        deal_with_signal();
        
    } while (rc == ME_REG_ACCESS_RES_NOT_AVLBL && count++ < reg_access_timeout);
    if (rc) {
        if (_lastFsmCtrl.error_code) {
            _lastError = mccErrTrans(_lastFsmCtrl.error_code);
            if ((currentState == FSMST_LOCKED && expectedState == FSMST_DOWNSTREAM_DEVICE_TRANSFER) || (_linkXFlow && currentState == FSMST_LOCKED && expectedState == FSMST_ACTIVATE)) {
                _rejectedIndex = _lastFsmCtrl.rejected_device_index;
                DPRINTF(("\nGot _rejectedIndex = %d\n", _rejectedIndex));
            }
        }
        else {
            _lastError = regErrTrans(rc);
            setLastRegisterAccessStatus(rc);
        }
        // if mcc failed, FSM should be unlocked and handle released
        _isDelayedActivationCommandSent = false;
        return false;
    }
    if (expectedState == FSMST_NA && currentState == FSMST_NA) {
        return true;
    }
    count = 0;
    // initialization longer then other states
    unsigned sleep_time = SLEEP_TIME;
    if (currentState == FSMST_INITIALIZE) {
        sleep_time = INIT_PARTITION_SLEEP_TIME;
    }
    if ((currentState == FSMST_DOWNSTREAM_DEVICE_TRANSFER && expectedState == FSMST_LOCKED) || 
        (_linkXFlow && currentState == FSMST_ACTIVATE)) {
        sleep_time = MAX_SLEEP_TIME;
    }
    while (currentState != FSMST_NA && _lastFsmCtrl.control_state == currentState && count < MAX_TOUT) {
        if (count) {
            msleep(sleep_time);
        }
        if (progressFuncAdv && progressFuncAdv->func) {
            if (command == FSM_QUERY && currentState == FSMST_DOWNSTREAM_DEVICE_TRANSFER && expectedState == FSMST_LOCKED) {
                if (progressFuncAdv->func(_lastFsmCtrl.control_progress, StateNames[currentState], PROG_WITH_PRECENTAGE, progressFuncAdv->opaque)) {
                    _lastError = FWCOMPS_ABORTED;
                    return false;
                }
            }
            else {
                if (progressFuncAdv->func(0, StateNames[currentState], PROG_WITHOUT_PRECENTAGE, progressFuncAdv->opaque)) {
                    _lastError = FWCOMPS_ABORTED;
                    return false;
                }
            }
        }
        if (!controlFsm(FSM_QUERY)) {
            if (command == FSM_QUERY && currentState == FSMST_DOWNSTREAM_DEVICE_TRANSFER && expectedState == FSMST_LOCKED) {
                //we are in the middle of downstream, but failed
                _rejectedIndex = _lastFsmCtrl.rejected_device_index;
                DPRINTF(("\nGot _rejectedIndex = %d\n", _rejectedIndex));
            }
            else if (_linkXFlow && command == FSM_QUERY && currentState == FSMST_ACTIVATE && expectedState == FSMST_LOCKED) {
                //we are in the middle of activaation, but failed
                _rejectedIndex = _lastFsmCtrl.rejected_device_index;
                DPRINTF(("\nGot _rejectedIndex = %d\n", _rejectedIndex));
            }
            return false;
        }
        count++;
    }
    if (count >= MAX_TOUT) {
        _lastError = FWCOMPS_MCC_TOUT;
        return false;
    }
    if (expectedState != FSMST_NA && _lastFsmCtrl.control_state != expectedState) {
        DPRINTF(("controlFsm : control_state FW %s expected %s\n", StateNames[_lastFsmCtrl.control_state], StateNames[expectedState]));
        _lastError = FWCOMPS_MCC_UNEXPECTED_STATE;
        return false;
    }

    if (progressFuncAdv && progressFuncAdv->func && currentState != FSMST_NA) {
        if (progressFuncAdv->func(100, StateNames[currentState], PROG_OK, progressFuncAdv->opaque)) {
            _lastError = FWCOMPS_ABORTED;
            return false;
        }
    }
    return true;
}

bool FwCompsMgr::runMCQI(u_int32_t componentIndex,
                         u_int8_t readPending,
                         u_int32_t infoType,
                         u_int32_t dataSize,
                         u_int32_t offset,
                         u_int32_t *data)
{
    bool ret = true;
    mft_signal_set_handling(1);
    memset(&_currCompInfo, 0, sizeof(_currCompInfo));
    _currCompInfo.read_pending_component = readPending;
    _currCompInfo.info_type = infoType;
    _currCompInfo.offset = offset;
    _currCompInfo.data_size = dataSize;
    _currCompInfo.component_index = componentIndex;
    _currCompInfo.device_index = _deviceIndex;
    _currCompInfo.device_type = _deviceType;
    DPRINTF(("-D- MCQI: read_pending_component %u infoType %u offset %u dataSize %u, componentIndex %u _deviceIndex %u \n",
        readPending, infoType, offset, dataSize, componentIndex, _deviceIndex));
    reg_access_status_t rc = reg_access_mcqi(_mf, REG_ACCESS_METHOD_GET, &_currCompInfo);
    deal_with_signal();
    if (rc) {
        _lastError = regErrTrans(rc);
        setLastRegisterAccessStatus(rc);
        ret = false;
    }
    if (data && dataSize) {
        if (!rc) {
            memcpy(data, &_currCompInfo.data, _currCompInfo.info_size);
        }
    }
    return ret;
}

bool FwCompsMgr::getDeviceHWInfo(FwCompsMgr::MQISDeviceDescriptionT op, vector<u_int8_t>& infoString)
{
    mqisReg mqisRegister;
    mfile *mf;
    mf = getMfileObj();
    if (!mf) {
        return false;
    }
    reg_access_status_t rc;
    int maxDataSize = sizeof(mqisRegister.info_string);

    memset(&mqisRegister, 0, sizeof(mqisReg));
    if (op < MQIS_REGISTER_FIRST_VALUE || op > MQIS_REGISTER_LAST_VALUE)
        return false;

    mqisRegister.info_type = (u_int8_t)op;
    mqisRegister.read_length = maxDataSize;
    mft_signal_set_handling(1);

    rc = reg_access_mqis(mf, REG_ACCESS_METHOD_GET, &mqisRegister);
    deal_with_signal();
    if (rc) {
        return false;
    }
    //reg_access_hca_mqis_reg_print(&mqisRegister, stdout, 4);
    int infoSize = mqisRegister.info_length;
    if (infoSize == 0) {
        return false;
    }
    infoString.resize(infoSize + 1, '\0');

    // copy the output
    memcpy(infoString.data(), mqisRegister.info_string,
            mqisRegister.read_length);

    if (infoSize > mqisRegister.read_length) {
        int leftSize = infoSize - mqisRegister.read_length;
        while (leftSize > 0) {
            mqisRegister.read_offset = infoSize - leftSize;
            mqisRegister.read_length = leftSize > maxDataSize ? maxDataSize : leftSize;
            mft_signal_set_handling(1);

            rc = reg_access_mqis(mf, REG_ACCESS_METHOD_GET, &mqisRegister);
            deal_with_signal();
            if (rc) {
                return false;
            }
            //reg_access_hca_mqis_reg_print(&mqisRegister, stdout, 4);
            memcpy(infoString.data() + mqisRegister.read_offset,
                   (mqisRegister.info_string), mqisRegister.read_length);
            leftSize -= mqisRegister.read_length;
        }
    }
    return true;
}

bool FwCompsMgr::queryComponentInfo(u_int32_t componentIndex,
                                    u_int8_t readPending,
                                    u_int32_t infoType,
                                    u_int32_t dataSize,
                                    u_int32_t *data)
{
    u_int32_t maxDataSize = mget_max_reg_size(_mf, MACCESS_REG_METHOD_GET) - sizeof(_currCompInfo);
    if (maxDataSize > MAX_REG_DATA) {
        maxDataSize = MAX_REG_DATA;
    }
    if (!runMCQI(componentIndex, readPending, infoType, maxDataSize, 0, data)) {
        return false;
    }
    u_int32_t compInfoSize = _currCompInfo.info_size;
    u_int32_t tOffset = maxDataSize;
    if (tOffset >= compInfoSize) {
        return true;
    }
    if (dataSize < compInfoSize) {
        compInfoSize = dataSize;
    }
    while (tOffset < compInfoSize) {
        u_int32_t toRead = compInfoSize - tOffset > maxDataSize ? maxDataSize : compInfoSize - tOffset;
        if (!runMCQI(componentIndex, readPending, infoType, toRead, tOffset, data + tOffset)) {
            return false;
        }
        tOffset += maxDataSize;
    }
    return true;
}

reg_access_status_t FwCompsMgr::getGI(mfile *mf, mgirReg *gi)
{
    reg_access_status_t rc = ME_REG_ACCESS_OK;
    u_int32_t tp = 0;
    mget_mdevs_type(mf, &tp);
    mft_signal_set_handling(1);
#if !defined(UEFI_BUILD) && !defined(NO_INBAND)
    if (tp == MST_IB) {
        rc = (reg_access_status_t)mad_ifc_general_info_hw(mf, &gi->hw_info);
        if (rc) {
            goto cleanup;
        }
        if (gi->hw_info.device_id == 4129) {
            DPRINTF(("FwCompsMgr::getGI CX7 IB device found, sending regular MGIR\n"));
            rc = reg_access_mgir(mf, REG_ACCESS_METHOD_GET, gi);
            goto cleanup;
        }
        rc = (reg_access_status_t)mad_ifc_general_info_fw(mf, &gi->fw_info);
        if (rc) {
            goto cleanup;
        }
        rc = (reg_access_status_t)mad_ifc_general_info_sw(mf, &gi->sw_info);
    }
    else {
        rc = reg_access_mgir(mf, REG_ACCESS_METHOD_GET, gi);
        goto cleanup;
    }
#else
    rc = reg_access_mgir(mf, REG_ACCESS_METHOD_GET, gi);
    goto cleanup;
#endif
cleanup:
    deal_with_signal();
    return rc;

}

bool FwComponent::init(const std::vector<u_int8_t>&  buff,
                       u_int32_t size,
                       comps_ids_t type,
                       u_int32_t idx)
{
    if (_initialized) {
        return false;
    }
    _type = type;
    _size = size;
    _data = buff;
    _componentIndex = idx;
    _initialized = true;
    return true;
}

void FwCompsMgr::initialize(mfile *mf)
{
    _mf = mf;
    memset(&_lastFsmCtrl, 0, sizeof(fsm_control_st));
    _lastError = FWCOMPS_SUCCESS;
    _componentIndex = 0;
    _lastRegAccessStatus = ME_OK;
    _updateHandle = 0;
    if (getFwSupport()) {
        GenerateHandle();
    }
    ComponentAccessFactory* factory = ComponentAccessFactory::GetInstance();
    _accessObj = factory->createDataAccessObject(this, mf, isDmaSupported);
    _refreshed = false;
}

void FwCompsMgr::SetIndexAndSize(int deviceIndex, int deviceSize, bool autoUpdate, bool activationNeeded, bool downloadTransferNeeded, int activate_delay_sec)
{
    _linkXDeviceSize = deviceSize;
    _linkXDeviceIndex = deviceIndex ;
    _autoUpdate = autoUpdate;
    _linkXFlow = true;
    _activationNeeded = activationNeeded;
    _downloadTransferNeeded = downloadTransferNeeded;
    _activation_delay_sec = activate_delay_sec;
    _rejectedIndex = -1;
}

FwCompsMgr::FwCompsMgr(mfile *mf, DeviceTypeT devType, int deviceIndex)
{
    _clearSetEnv = false;
    _openedMfile = false;
    _hwDevId = 0;
    _deviceType = devType;
    _deviceIndex = deviceIndex;
    _accessObj = NULL;
    _mircCaps = false;
#ifndef UEFI_BUILD    
    _trm = NULL;
#endif    
    _linkXDeviceSize = 0;
    _linkXDeviceIndex = 0;
    _autoUpdate = false;
    _linkXFlow = false;
    _activationNeeded = true;
    _downloadTransferNeeded = true;
    _activation_delay_sec = 0;
    _rejectedIndex = -1;
    _isDelayedActivationCommandSent = false;
    initialize(mf);
}

FwCompsMgr::FwCompsMgr(const char *devname, DeviceTypeT devType, int deviceIndex)
{
    _mf = NULL;
    _openedMfile = false;
    _clearSetEnv = false;
    _accessObj = NULL;
    _deviceType = devType;
    _deviceIndex = deviceIndex;
    _linkXDeviceSize = 0;
    _linkXDeviceIndex = 0;
    _autoUpdate = false;
    _linkXFlow = false;
    _activationNeeded = true;
    _downloadTransferNeeded = true;
    _activation_delay_sec = 0;
    _rejectedIndex = -1;
    _isDelayedActivationCommandSent = false;
#ifndef UEFI_BUILD
    if (getenv(MTCR_IB_TIMEOUT_VAR) == NULL) {
        _clearSetEnv = true;
#if defined(_WIN32) || defined(_WIN64) || defined(__MINGW64__) || defined(__MINGW32__)
        putenv(MTCR_IB_TIMEOUT_VAR "=" MTCR_IB_TIMEOUT_VAL);
#else
        setenv(MTCR_IB_TIMEOUT_VAR, MTCR_IB_TIMEOUT_VAL, 1);
#endif
    }
#endif
    _hwDevId = 0;
    _mircCaps = false;
#ifndef UEFI_BUILD    
    _trm = NULL;
#endif
    _lastError = FWCOMPS_SUCCESS;
    mfile *mf = mopen(devname);
    if (!mf) {
        _lastError = FWCOMPS_BAD_PARAM;
        return;
    }
    _openedMfile = true;
    initialize(mf);
}

FwCompsMgr::FwCompsMgr(uefi_Dev_t *uefi_dev, uefi_dev_extra_t *uefi_extra)
{
    _mf = NULL;
    _accessObj = NULL;
    _openedMfile = false;
    _clearSetEnv = false;
    _mircCaps = false;
    mfile *mf = mopen_fw_ctx((void *)uefi_dev, (void *)uefi_extra->fw_cmd_func, \
        (void *)uefi_extra->dma_func, (void *)&uefi_extra->dev_info);
    if (!mf) {
        _lastError = FWCOMPS_MEM_ALLOC_FAILED;
        return;
    }
    if (uefi_extra != NULL) {
        _hwDevId = uefi_extra->dev_info.hw_dev_id;
    }
    _openedMfile = true;
    _autoUpdate = false;
    _linkXFlow = false;
    _activationNeeded = true;
    _downloadTransferNeeded = true;
    _activation_delay_sec = 0;
    _rejectedIndex = -1;
    _isDelayedActivationCommandSent = false;
    initialize(mf);
}
FwCompsMgr::~FwCompsMgr()
{
#ifndef UEFI_BUILD
    unlock_flash_semaphore();
    if (_clearSetEnv) {
#if defined(_WIN32) || defined(_WIN64) || defined(__MINGW64__) || defined(__MINGW32__)
        putenv(MTCR_IB_TIMEOUT_VAR "=");
#else
        unsetenv(MTCR_IB_TIMEOUT_VAR);
#endif
    }
#endif
    if (_mf) {
        if (!_isDelayedActivationCommandSent) {
            if (_lastFsmCtrl.control_state != FSMST_IDLE) {
                controlFsm(FSM_CMD_CANCEL, FSMST_LOCKED);
                controlFsm(FSM_CMD_RELEASE_UPDATE_HANDLE, FSMST_IDLE);
            }
        }
    }
    if (_openedMfile) {
        if (_mf) {
            mclose(_mf);
        }
    }
    if (_accessObj != NULL) {
        delete _accessObj;
        _accessObj = NULL;
    }
}

bool FwCompsMgr::forceRelease()
{
    return controlFsm(FSM_CMD_FORCE_HANDLE_RELEASE);
}

void FwCompsMgr::GenerateHandle()
{
    if (!controlFsm(FSM_QUERY, FSMST_NA, 0, FSMST_NA, NULL, REG_ACCESS_TOUT)) {
        _updateHandle = 0;
        return;
    }
    _updateHandle = _lastFsmCtrl.update_handle & 0xffffff;
}

const char* CompNames[] = {
    "NO_COMPONENT 1",
    "COMPID_BOOT_IMG",
    "COMPID_RUNTIME_IMG",
    "COMPID_USER_NVCONFIG",
    "COMPID_OEM_NVCONFIG",
    "COMPID_MLNX_NVCONFIG",
    "COMPID_CS_TOKEN",
    "COMPID_DBG_TOKEN",
    "COMPID_DEV_INFO",
    "NO_COMPONENT 2",
    "COMPID_GEARBOX",
    "COMPID_CONGESTION_CONTROL",
    "COMPID_LINKX_PROPERTIES",
    "COMPID_CRYPTO_TO_COMMISSIONING",
    "COMPID_RMCS_TOKEN",
    "COMPID_RMDT_TOKEN"
};

bool FwCompsMgr::RefreshComponentsStatus(comp_status_st* ComponentStatus)
{
    u_int16_t compIdx = 0;
    int last_index_flag = 0;
    comp_query_st compStatus;
    if (_refreshed) {
        return true;
    }
    if (_compsQueryMap.size()) {
        _compsQueryMap.clear();
    }
    _compsQueryMap.resize((unsigned)(FwComponent::COMPID_UNKNOWN));
    while (!last_index_flag) {
        memset(&compStatus, 0, sizeof(comp_query_st));
        if (queryComponentStatus(compIdx, &(compStatus.comp_status))) {
            compStatus.comp_status.component_index = compIdx;
            if (ComponentStatus != NULL && compStatus.comp_status.identifier == FwComponent::COMPID_LINKX) {
                memcpy(ComponentStatus, &compStatus.comp_status, sizeof(compStatus.comp_status));
            }
            /* */
            u_int32_t capSt[DEFAULT_SIZE] = { 0 };
            if (queryComponentInfo(compIdx, 1, COMPINFO_CAPABILITIES, DEFAULT_SIZE, capSt) == false) {
                if (queryComponentInfo(compIdx, 0, COMPINFO_CAPABILITIES, DEFAULT_SIZE, capSt) == false) {
                    //_lastError = FWCOMPS_REG_FAILED;
                    DPRINTF(("-D- Found component: %#x name %s MCQI failed \n", compStatus.comp_status.identifier, CompNames[compStatus.comp_status.identifier]));
                    return false;
                }
            }
            compStatus.valid = 1;
            compStatus.comp_cap.supported_info_bitmask = _currCompInfo.data.mcqi_cap.supported_info_bitmask;
            compStatus.comp_cap.component_size = _currCompInfo.data.mcqi_cap.component_size;
            compStatus.comp_cap.max_component_size = _currCompInfo.data.mcqi_cap.max_component_size;
            compStatus.comp_cap.mcda_max_write_size = _currCompInfo.data.mcqi_cap.mcda_max_write_size;
            compStatus.comp_cap.log_mcda_word_size = _currCompInfo.data.mcqi_cap.log_mcda_word_size;
            compStatus.comp_cap.match_base_guid_mac = _currCompInfo.data.mcqi_cap.match_base_guid_mac;
            compStatus.comp_cap.check_user_timestamp = _currCompInfo.data.mcqi_cap.check_user_timestamp;
            compStatus.comp_cap.match_psid = _currCompInfo.data.mcqi_cap.match_psid;
            compStatus.comp_cap.match_chip_id = _currCompInfo.data.mcqi_cap.match_chip_id;
            compStatus.comp_cap.signed_updates_only = _currCompInfo.data.mcqi_cap.signed_updates_only;
            compStatus.comp_cap.rd_en = _currCompInfo.data.mcqi_cap.rd_en;
            memcpy(&(_compsQueryMap[compStatus.comp_status.identifier]), &compStatus, sizeof(compStatus));
            //reg_access_hca_mcqi_cap_print(&(compStatus.comp_cap), stdout, 3);
            last_index_flag = compStatus.comp_status.last_index_flag;
            DPRINTF(("-D- Found component with identifier=%#x index=%u name=%s supported_info_bitmask=0x%x \n", \
                compStatus.comp_status.identifier, compIdx, CompNames[compStatus.comp_status.identifier], 
                compStatus.comp_cap.supported_info_bitmask));

        }
        else {
            DPRINTF(("-D- queryComponentStatus failed for component index %d !!\n", compIdx));
            return false;
        }
        compIdx++;
    }
    _refreshed = true;
    return true;
}

//TODO: Check all the rc ..

bool FwCompsMgr::readComponent(FwComponent::comps_ids_t compType, FwComponent& fwComp, bool readPending,
                               ProgressCallBackAdvSt *progressFuncAdv)
{
    if (!RefreshComponentsStatus()) {
        return false;
    }
    _currCompQuery = &(_compsQueryMap[compType]);
    _componentIndex = _currCompQuery->comp_status.component_index;
    std::vector<u_int8_t> data;
    u_int32_t compSize = _currCompQuery->comp_cap.component_size;
    if (_currCompQuery->comp_cap.rd_en) {
        data.resize(compSize);
        if (!controlFsm(FSM_CMD_LOCK_UPDATE_HANDLE, FSMST_LOCKED)) {
            return false;
        }
        if (!controlFsm(readPending ? FSM_CMD_READ_PENDING_COMPONENT : FSM_CMD_READ_COMPONENT, FSMST_UPLOAD)) {
            controlFsm(FSM_CMD_RELEASE_UPDATE_HANDLE);
            return false;
        }
        _currComponentStr = FwComponent::getCompIdStr(compType);
        control_fsm_args_t fsmReadCommand;
        fsmReadCommand.command = readPending ? FSM_CMD_READ_PENDING_COMPONENT : FSM_CMD_READ_COMPONENT;
        fsmReadCommand.expectedState = FSMST_UPLOAD;
        if (!accessComponent(0, compSize, (u_int32_t *)(data.data()), MCC_READ_COMP, progressFuncAdv, &fsmReadCommand)) {
            return false;
        }
        if (!controlFsm(FSM_CMD_RELEASE_UPDATE_HANDLE)) {
            return false;
        }
    }
    else {
        DPRINTF(("readComponent : RD EN is 0 for component index %u compId %s \n", _componentIndex, FwComponent::getCompIdStr(compType)));
        _lastError = FWCOMPS_READ_COMP_NOT_SUPPORTED;
        return false;
    }

    fwComp.init(data, compSize, (FwComponent::comps_ids_t)_currCompInfo.info_type, _componentIndex);
    return true;
}

bool FwCompsMgr::readComponentInfo(FwComponent::comps_ids_t compType,
                                   comp_info_t infoType,
                                   std::vector<u_int32_t>& retData,
                                   bool readPending)
{
    if (!RefreshComponentsStatus()) {
        return false;
    }
    _currCompQuery = &(_compsQueryMap[compType]);
    _componentIndex = _currCompQuery->comp_status.component_index;


    if (!queryComponentInfo(_componentIndex, readPending == true, infoType, 0, 0)) {
        return false;
    }
    if (_currCompQuery->comp_cap.supported_info_bitmask & (1 << infoType)) 
    {
        u_int32_t size = _currCompInfo.info_size;
        retData.resize(size);
        queryComponentInfo(_componentIndex, readPending == true, infoType, size, (u_int32_t *)(retData.data()));
        return true;
    }
    else {
        _lastError = FWCOMPS_INFO_TYPE_NOT_SUPPORTED;
        return false;
    }
    //return true;
}

bool FwCompsMgr::queryComponentStatus(u_int32_t componentIndex,
    comp_status_st *query)
{
    mft_signal_set_handling(1);
    query->component_index = componentIndex;
    query->device_index = _deviceIndex;
    query->device_type = _deviceType;
    reg_access_status_t rc = reg_access_mcqs(_mf, REG_ACCESS_METHOD_GET, query);
    deal_with_signal();
    if (rc) {
        _lastError = regErrTrans(rc);
        setLastRegisterAccessStatus(rc);
        return false;
    }
    return true;
}

bool FwCompsMgr::burnComponents(std::vector<FwComponent>& comps,
                                ProgressCallBackAdvSt *progressFuncAdv)
{
    unsigned i = 0;
    if (!RefreshComponentsStatus()) {
        return false;
    }
    if (!controlFsm(FSM_CMD_LOCK_UPDATE_HANDLE, FSMST_LOCKED)) {
        DPRINTF(("Cannot lock the handle!\n"));
        if (forceRelease() == false) {
            printf("FSM is locked.\n");
        }
        return false;
    }
    if (_downloadTransferNeeded == true) {
        for (i = 0; i < comps.size(); i++) {
            int component = comps[i].getType();
            _currCompQuery = &(_compsQueryMap[component]);
            if (!_currCompQuery->valid) {
                _lastError = FWCOMPS_COMP_NOT_SUPPORTED;
                DPRINTF(("MCC flow for component %d is not supported!\n", component));
                return false;
            }
            _componentIndex = _currCompQuery->comp_status.component_index;
            if (!controlFsm(FSM_CMD_UPDATE_COMPONENT, FSMST_DOWNLOAD, comps[i].getSize(), FSMST_INITIALIZE, progressFuncAdv)) {
                DPRINTF(("Initializing downloading FW component has failed!\n"));
                return false;
            }
            _currComponentStr = FwComponent::getCompIdStr(comps[i].getType());
            control_fsm_args_t fsmUpdateCommand;
            fsmUpdateCommand.command = FSM_CMD_UPDATE_COMPONENT;
            fsmUpdateCommand.expectedState = FSMST_DOWNLOAD;
            fsmUpdateCommand.size = comps[i].getSize();
            fsmUpdateCommand.currentState = FSMST_INITIALIZE;
            fsmUpdateCommand.progressFuncAdv = progressFuncAdv;
            if (!accessComponent(0, comps[i].getSize(), (u_int32_t *)(comps[i].getData().data()), MCC_WRITE_COMP, progressFuncAdv, &fsmUpdateCommand)) {
                DPRINTF(("Downloading FW component has failed!\n"));
                return false;
            }
            if (!controlFsm(FSM_CMD_VERIFY_COMPONENT, FSMST_LOCKED, 0, FSMST_NA, progressFuncAdv)) {
                DPRINTF(("Verifying FW component has failed!\n"));
                return false;
            }
            if (comps[i].getType() == FwComponent::COMPID_LINKX) {
                if (!controlFsm(FSM_CMD_DOWNSTREAM_DEVICE_TRANSFER, FSMST_DOWNSTREAM_DEVICE_TRANSFER, 0, FSMST_LOCKED, progressFuncAdv)) {
                    DPRINTF(("Downstream LinkX begin has failed!\n"));
                    return false;
                }
                if (!controlFsm(FSM_QUERY, FSMST_LOCKED, 0, FSMST_DOWNSTREAM_DEVICE_TRANSFER, progressFuncAdv)) {
                    DPRINTF(("Downstream LinkX ending has failed!\n"));
                    return false;
                }
            }
        }
    }
    if (_linkXFlow) {
        if (_activationNeeded == true) { //by default
            if (!controlFsm(FSM_CMD_ACTIVATE_ALL, FSMST_ACTIVATE, 0, FSMST_LOCKED, progressFuncAdv)) {
                DPRINTF(("Moving to ACTIVATE state has failed!\n"));
                return false;
            }

            // In case of activation delay, FW will set FSM to LOCKED
            if (!_isDelayedActivationCommandSent) {
                printf("Please wait while activating the transceiver(s) FW ...\n");
                if (!controlFsm(FSM_QUERY, FSMST_LOCKED, 0, FSMST_ACTIVATE, progressFuncAdv)) {
                    DPRINTF(("Moving from activate state to locked state has failed!\n"));
                    return false;
                }
            }
        }
    }
    else {
        if (!controlFsm(FSM_CMD_ACTIVATE_ALL)) {
            DPRINTF(("Activating FW component has failed!\n"));
            return false;
        }
    }

    // In case of activation delay, FW will release the update handle
    if (!_isDelayedActivationCommandSent) {
        if (!controlFsm(FSM_CMD_RELEASE_UPDATE_HANDLE)) {
            DPRINTF(("Release FW handle has failed!\n"));
            return false;
        }
    }
    _refreshed = false;
    return true;
}


bool FwCompsMgr::getFwComponents(std::vector<FwComponent>& compsMap, bool readEn)
{
    if (!RefreshComponentsStatus()) {
        return false;
    }
    for (std::vector<comp_query_st>::iterator it = _compsQueryMap.begin();
        it != _compsQueryMap.end(); it++) {
        if (!it->valid) {
            continue;
        }
        FwComponent fwCmp((FwComponent::comps_ids_t)it->comp_status.identifier,
                          (FwComponent::comps_status_t)it->comp_status.component_status);
        if (readEn && !readComponent((FwComponent::comps_ids_t)it->comp_status.identifier, fwCmp, 0)) {
            return false;
        }
        else {
            fwCmp.setSize(it->comp_cap.component_size);
        }
        compsMap.push_back(fwCmp);
    }
    return true;
}

const char* FwComponent::getCompIdStr(comps_ids_t compId)
{
    switch (compId) {
    case COMPID_BOOT_IMG:
        return "Boot image";

    case COMPID_RUNTIME_IMG:
        return "RUNTIME_IMAGE";

    case COMPID_CS_TOKEN:
        return "CS_TOKEN";

    case COMPID_MLNX_NVCONFIG:
        return "MLNX_NVCONFIG";

    case COMPID_OEM_NVCONFIG:
        return "OEM_NVCONFIG";

    case COMPID_DBG_TOKEN:
        return "DBG_TOKEN";

    case COMPID_GEARBOX:
        return "GEARBOX";

    case COMPID_CONGESTION_CONTROL:
            return "CONGESTION_CONTROL";

    case COMPID_LINKX:
        return "COMPID_LINKX";

    case COMPID_CRYPTO_TO_COMMISSIONING:
        return "COMPID_CRYPTO_TO_COMMISSIONING";

    case COMPID_RMCS_TOKEN:
        return "COMPID_RMCS_TOKEN";

    case COMPID_RMDT_TOKEN:
        return "COMPID_RMDT_TOKEN";

    default:
        return "UNKNOWN_COMPONENT";
    }
}

u_int32_t FwCompsMgr::getFwSupport()
{
    u_int32_t devid = 0;
    isDmaSupported = false;
#ifndef UEFI_BUILD
    if (getenv("FW_CTRL") != NULL) {
        return 1;
    }
    if (mread4(_mf, 0xf0014, &devid) != 4) {
        /*
         * Best effort to check MCAM
         */
        devid = 0;
    }
#else
    devid = _hwDevId;
#endif
    devid = EXTRACT(devid, 0, 16);
    /*
     * If 4TH gen nic or switch with no MCAM reg return not supported
     */
    if (devid == CX2_HW_ID ||
        devid == CX3_HW_ID ||
        devid == CX3_PRO_HW_ID ||
        devid == SWITCHX_HW_ID ||
        devid == IS4_HW_ID ||
        devid == SWITCH_IB_HW_ID ||
        devid == SWITCH_IB2_HW_ID) {
        _lastError = FWCOMPS_UNSUPPORTED_DEVICE;
        return 0;
    }

    tools_open_mcam mcam;
    memset(&mcam, 0, sizeof(mcam));
    reg_access_status_t rc = reg_access_mcam(_mf, REG_ACCESS_METHOD_GET, &mcam);
    if (rc) {
        DPRINTF(("getFwSupport MCAM not supported! rc = %d\n", rc));
        _lastError = FWCOMPS_UNSUPPORTED_DEVICE;
        return 0;
    }
    /*
     * MCDA bit are in offsets 0x60-0x64
     * MCDD in bit 0x5C
     * MGIR in bit 0x20
     * The bytes are in reverse order
     */
    u_int8_t mcdaCaps = EXTRACT(mcam.mng_access_reg_cap_mask[3], 0, 5);
    u_int8_t mcddCaps = EXTRACT(mcam.mng_access_reg_cap_mask[4], 4, 1);//##EDDY: need check ! register 5c
    u_int8_t mgirCaps = EXTRACT(mcam.mng_access_reg_cap_mask[11], 0, 1);
    if (mcddCaps == 1)
        isDmaSupported = true;

    memset(&mcam, 0, sizeof(mcam));
    mcam.access_reg_group = 2;//for MIRC register
    rc = reg_access_mcam(_mf, REG_ACCESS_METHOD_GET, &mcam);
    if (rc) {
        _lastError = FWCOMPS_UNSUPPORTED_DEVICE;
        return 0;
    }

    _mircCaps = EXTRACT(mcam.mng_access_reg_cap_mask[3], 2, 1);//MIRC is 0x9162
    DPRINTF(("getFwSupport _mircCaps = %d mcdaCaps = %d mcddCaps = %d mgirCaps = %d\n", _mircCaps, mcdaCaps, mcddCaps, mgirCaps));

    if (mcdaCaps == 0x1f && mgirCaps) {
        return 1;
    }
    _lastError = FWCOMPS_UNSUPPORTED_DEVICE;
    return 0;
}

#define UID_EXTRACT(INT64, INT32ARR) INT64 = ((u_int64_t)INT32ARR[0] << 32) | INT32ARR[1];

bool FwCompsMgr::extractMacsGuids(fwInfoT *fwQuery)
{
    std::vector<u_int8_t> nvBaseMacGuidData;
    std::vector<u_int8_t> nvBaseMacGuidDataOrig;
    std::vector<u_int8_t> nvBaseMacGuidCap;
    std::vector<u_int8_t> nvBaseMacGuidCapOrig;
    struct tools_open_nv_base_mac_guid currMacGuid;
    struct tools_open_nv_base_mac_guid origMacGuid;

    struct tools_open_nv_base_mac_guid_cap currMacGuidCap;
    struct tools_open_nv_base_mac_guid_cap origMacGuidCap;

    memset(&currMacGuid, 0, sizeof(currMacGuid));
    memset(&origMacGuid, 0, sizeof(origMacGuid));
    memset(&currMacGuidCap, 0, sizeof(currMacGuidCap));
    memset(&origMacGuidCap, 0, sizeof(origMacGuidCap));

    if (!runNVDA(nvBaseMacGuidData, 64, NV_BASE_MAC_GUID_IDX, REG_ACCESS_METHOD_GET, false)) {
        return false;
    }
    if (!runNVDA(nvBaseMacGuidDataOrig, 64, NV_BASE_MAC_GUID_IDX, REG_ACCESS_METHOD_GET, true)) {
        return false;
    }
    if (!runNVDA(nvBaseMacGuidCap, 64, NV_BASE_MAC_GUID_CAP_IDX, REG_ACCESS_METHOD_GET, false)) {
        return false;
    }
    if (!runNVDA(nvBaseMacGuidCapOrig, 64, NV_BASE_MAC_GUID_CAP_IDX, REG_ACCESS_METHOD_GET, true)) {
        return false;
    }
    tools_open_nv_base_mac_guid_unpack(&currMacGuid, nvBaseMacGuidData.data());
    tools_open_nv_base_mac_guid_unpack(&origMacGuid, nvBaseMacGuidDataOrig.data());
    tools_open_nv_base_mac_guid_cap_unpack(&currMacGuidCap, nvBaseMacGuidCap.data());
    tools_open_nv_base_mac_guid_cap_unpack(&origMacGuidCap, nvBaseMacGuidCapOrig.data());

    UID_EXTRACT(fwQuery->base_mac.uid, currMacGuid.base_mac);
    UID_EXTRACT(fwQuery->base_guid.uid, currMacGuid.base_guid);
    UID_EXTRACT(fwQuery->base_guid_orig.uid, origMacGuid.base_guid);

    fwQuery->base_mac.num_allocated = currMacGuidCap.num_of_allocated_macs;
    fwQuery->base_guid.num_allocated = currMacGuidCap.num_of_allocated_guids;
    fwQuery->base_mac_orig.num_allocated = origMacGuidCap.num_of_allocated_macs;
    fwQuery->base_guid_orig.num_allocated = origMacGuidCap.num_of_allocated_guids;
    return true;
}


bool FwCompsMgr::setMacsGuids(mac_guid_t macGuid)
{
    std::vector<u_int8_t> macsGuidsBuff(16, 0);

    struct tools_open_nv_base_mac_guid baseMacGuid;

    baseMacGuid.base_guid[0] = macGuid.guid.h;
    baseMacGuid.base_guid[1] = macGuid.guid.l;
    baseMacGuid.base_mac[0] = macGuid.mac.h;
    baseMacGuid.base_mac[1] = macGuid.mac.l;

    tools_open_nv_base_mac_guid_pack(&baseMacGuid, macsGuidsBuff.data());

    return runNVDA(macsGuidsBuff, 16, NV_BASE_MAC_GUID_IDX, REG_ACCESS_METHOD_SET, false);
}

u_int8_t transRomType(u_int8_t mgirRomType)
{
    switch (mgirRomType) {
    case 0x1: //FLEXBOOT
        return 0x10;

    case 0x2: //UEFI
        return 0x11;
         
    case 0x3: //UEFI_CLP
        return 0x12;

    case 0x4: //NVMe
        return 0x13;

    case 0x5: //FCODE
        return 0x21;

    case 0x6: // UEFI Virtio net
        return 0x14;

    case 0x7: //UEFI Virtio blk
        return 0x15;

    case 0x8: //PXE Virtio net
        return 0x16;

    default:
        return mgirRomType;
    }
}

void FwCompsMgr::extractRomInfo(mgirReg *mgir, fwInfoT *fwQuery)
{
    if (!fwQuery || !mgir) {
        return;
    }
    fwQuery->nRoms = 0;
    if (mgir->sw_info.rom3_type) {
        fwQuery->roms[fwQuery->nRoms].arch = mgir->sw_info.rom3_arch;
        fwQuery->roms[fwQuery->nRoms].type = transRomType(mgir->sw_info.rom3_type);
        fwQuery->roms[fwQuery->nRoms].version = mgir->sw_info.rom3_version;
        fwQuery->nRoms++;
    }
    if (mgir->sw_info.rom2_type) {
        fwQuery->roms[fwQuery->nRoms].arch = mgir->sw_info.rom2_arch;
        fwQuery->roms[fwQuery->nRoms].type = transRomType(mgir->sw_info.rom2_type);
        fwQuery->roms[fwQuery->nRoms].version = mgir->sw_info.rom2_version;
        fwQuery->nRoms++;
    }
    if (mgir->sw_info.rom1_type) {
        fwQuery->roms[fwQuery->nRoms].arch = mgir->sw_info.rom1_arch;
        fwQuery->roms[fwQuery->nRoms].type = transRomType(mgir->sw_info.rom1_type);
        fwQuery->roms[fwQuery->nRoms].version = mgir->sw_info.rom1_version;
        fwQuery->nRoms++;
    }
    if (mgir->sw_info.rom0_type) {
        fwQuery->roms[fwQuery->nRoms].arch = mgir->sw_info.rom0_arch;
        fwQuery->roms[fwQuery->nRoms].type = transRomType(mgir->sw_info.rom0_type);
        fwQuery->roms[fwQuery->nRoms].version = mgir->sw_info.rom0_version;
        fwQuery->nRoms++;
    }
}

bool FwCompsMgr::queryFwInfo(fwInfoT *query, bool next_boot_fw_ver)
{
    if (!query) {
        _lastError = FWCOMPS_BAD_PARAM;
        return false;
    }
    /*
    * MGIR
    */
    reg_access_status_t rc;
    mgirReg mgir;
    memset(&mgir, 0, sizeof(mgir));
    memset(query, 0, sizeof(fwInfoT));

    if (getComponentVersion(FwComponent::COMPID_BOOT_IMG, true, &query->pending_fw_version)) {
        query->pending_fw_valid = 1;
    }
    if (!getComponentVersion(FwComponent::COMPID_BOOT_IMG, false, &query->running_fw_version)) {
        return false;
    }
    if (next_boot_fw_ver) {
        // query next_boot_fw_ver only. enough to query pending, running versions and device_id.
        rc = getGI(_mf, &mgir);
        if (rc) {
            _lastError = FWCOMPS_QUERY_FAILED;
            return false;
        }
        query->hw_dev_id = mgir.hw_info.hw_dev_id;
        query->dev_id = mgir.hw_info.device_id;
        query->rev_id = mgir.hw_info.device_hw_revision;
        return true;
    }

    if (query->running_fw_version.version_string_length &&
        query->running_fw_version.version_string_length <= PRODUCT_VER_LEN) {
        strcpy(query->product_ver, (char *)_productVerStr.data());
    }

    rc = getGI(_mf, &mgir);
    if (rc) {
        _lastError = FWCOMPS_QUERY_FAILED;
        return false;
    }
    //tools_open_mgir_print(&mgir, stdout, 1);
    memcpy(query->psid, mgir.fw_info.psid, PSID_LEN);
    query->hw_dev_id = mgir.hw_info.hw_dev_id;
    query->dev_id = mgir.hw_info.device_id;
    query->rev_id = mgir.hw_info.device_hw_revision;
    query->security_type.secure_fw = mgir.fw_info.secured;
    query->security_type.signed_fw = mgir.fw_info.signed_fw;
    query->security_type.debug_fw = mgir.fw_info.debug;
    query->security_type.dev_fw = mgir.fw_info.dev;
    query->life_cycle = (life_cycle_t)mgir.fw_info.life_cycle;
    query->sec_boot = mgir.fw_info.sec_boot;
    query->encryption = mgir.fw_info.encryption;
    query->signed_fw = _compsQueryMap[FwComponent::COMPID_BOOT_IMG].comp_cap.signed_updates_only;

    query->base_mac_orig.uid = ((u_int64_t)mgir.hw_info.manufacturing_base_mac_47_32 << 32 | mgir.hw_info.manufacturing_base_mac_31_0);
    if (!extractMacsGuids(query)) {
        /*
         * We don't fail, it will show NA in the query
         */
    }

    extractRomInfo(&mgir, query);

    /*
     * MQIS
     */
    vector<u_int8_t> nameInfoString;
    vector<u_int8_t> descriptionInfoString;
    vector<u_int8_t> imageVsd;
    vector<u_int8_t> deviceVsd;
    if (getDeviceHWInfo(FwCompsMgr::MQIS_REGISTER_DEVICE_NAME, nameInfoString)) {
        strncpy(query->name, (char *)nameInfoString.data(), NAME_LEN - 1);
    }
    if (getDeviceHWInfo(FwCompsMgr::MQIS_REGISTER_DEVICE_DESCRIPTION_INFO, descriptionInfoString)) {
        strncpy(query->description, (char *)descriptionInfoString.data(), DESCRIPTION_LEN - 1);
    }
    if (getDeviceHWInfo(FwCompsMgr::MQIS_REGISTER_IMAGE_VSD, imageVsd)) {
        strncpy(query->imageVsd, (char *)imageVsd.data(), VSD_LEN);
    }
    if (getDeviceHWInfo(FwCompsMgr::MQIS_REGISTER_DEVICE_VSD, deviceVsd)) {
        strncpy(query->deviceVsd, (char *)deviceVsd.data(), VSD_LEN);
    }

    return true;
}

unsigned char*  FwCompsMgr::getLastErrMsg()
{
    static unsigned char bufferErr[512] = { 0 };
    memset(bufferErr, 0, sizeof(bufferErr));
    switch (_lastError) {
    case FWCOMPS_ABORTED:
        return (unsigned char*)"Aborting ... received interrupt signal";

    case FWCOMPS_MCC_ERR_ERROR:
        return (unsigned char*)"MCC error";

    case FWCOMPS_MCC_ERR_REJECTED_DIGEST_ERR:
        return (unsigned char*)"The Digest in the signature is wrong";

    case FWCOMPS_MCC_ERR_REJECTED_UNSIGNED:
        return (unsigned char*)"The component is not signed";

    case FWCOMPS_MCC_ERR_BLOCKED_PENDING_RESET:
        return (unsigned char*)"The firmware image was already updated on flash, pending reset.";

    case FWCOMPS_MCC_ERR_REJECTED_NOT_APPLICABLE:
        return (unsigned char*)"Component is not applicable";

    case FWCOMPS_MCC_ERR_REJECTED_AUTH_FAILED:
        return (unsigned char*)"Rejected authentication";

    case FWCOMPS_MCC_ERR_REJECTED_KEY_NOT_APPLICABLE:
        return (unsigned char*)"The key is not applicable";

    case FWCOMPS_READ_COMP_NOT_SUPPORTED:
        return (unsigned char*)"Reading component is not supported";
        break;

    case FWCOMPS_COMP_NOT_SUPPORTED:
        return (unsigned char*)"Component not supported";

    case FWCOMPS_VERIFY_FAILED:
        return (unsigned char*)"Firmware verifying failed!";

    case FWCOMPS_CR_ERR:
        return (unsigned char*)"Failed to access CR-Space";

    case FWCOMPS_MCC_REJECTED_NOT_A_SECURED_FW:
        return (unsigned char*)"The firmware image is not secured";

    case FWCOMPS_MCC_REJECTED_MFG_BASE_MAC_NOT_LISTED:
        return (unsigned char*)"The manufacturing base MAC was not listed";

    case FWCOMPS_MCC_REJECTED_NO_DEBUG_TOKEN:
        return (unsigned char*)"There is no Debug Token installed";

    case FWCOMPS_MCC_REJECTED_VERSION_NUM_MISMATCH:
        return (unsigned char*)"Firmware version mismatch";

    case FWCOMPS_MCC_REJECTED_USER_TIMESTAMP_MISMATCH:
        return (unsigned char*)"User timestamp mismatch";

    case FWCOMPS_MCC_REJECTED_FORBIDDEN_VERSION:
        return (unsigned char*)"Forbidden version rejected";

    case FWCOMPS_MCC_FLASH_ERASE_ERROR:
        return (unsigned char*)"Error while erasing the flash";

    case FWCOMPS_MCC_UNEXPECTED_STATE:
        return (unsigned char*)"Unexpected state";

    case FWCOMPS_MCC_TOUT:
        return (unsigned char*)"Time-out reached while waiting for the FSM to be updated";

    case FWCOMPS_MCC_REJECTED_IMAGE_CAN_NOT_BOOT_FROM_PARTITION:
        return (unsigned char*)"Image cannot boot from partition.";

    case FWCOMPS_MCC_REJECTED_LINKX_TYPE_NOT_SUPPORTED:
    {
        if (_rejectedIndex != -1) {
            sprintf((char*)bufferErr, "LinkX type not supported for device index %d\n", _rejectedIndex);
            return bufferErr;
        }
        else {
            return (unsigned char*)"LinkX type not supported";
        }
    }
    case FWCOMPS_MCC_REJECTED_HOST_STORAGE_IN_USE:
        return (unsigned char*)"Host storage is in use";

    case FWCOMPS_MCC_REJECTED_LINKX_TRANSFER:
    {
        if (_rejectedIndex != -1) {
            sprintf((char*)bufferErr, "LinkX downstream transfer failed for device index %d\n", _rejectedIndex);
            return bufferErr;
        }
        else {
            return (unsigned char*)"LinkX downstream transfer failed";
        }
    }
    case FWCOMPS_MCC_REJECTED_LINKX_ACTIVATE: {
        if (_rejectedIndex != -1) {
            sprintf((char*)bufferErr, "LinkX activation failed for device index %d\n", _rejectedIndex);
            return bufferErr;
        }
        else {
            return (unsigned char*)"LinkX activation failed";
        }
    }

    case FWCOMPS_MCC_REJECTED_INCOMPATIBLE_FLASH:
        return (unsigned char*)"The image does not support the device's flash type";

    case FWCOMPS_UNSUPPORTED_DEVICE:
        return (unsigned char*)"Unsupported device";

    case FWCOMPS_MTCR_OPEN_DEVICE_ERROR:
        return (unsigned char*)"Failed to open device";

    case FWCOMPS_FAIL_TO_LOCK_FLASH_SEMAPHORE:
        return (unsigned char*)"Failed to lock flash semaphore";

    case FWCOMPS_FAIL_TO_CREATE_TRM_CONTEXT:
        return (unsigned char*)"Failed to create TRM context";

    case FWCOMPS_REG_ACCESS_BAD_STATUS_ERR:
    case FWCOMPS_REG_ACCESS_BAD_METHOD:
    case FWCOMPS_REG_ACCESS_NOT_SUPPORTED:
    case FWCOMPS_REG_ACCESS_DEV_BUSY:
    case FWCOMPS_REG_ACCESS_VER_NOT_SUPP:
    case FWCOMPS_REG_ACCESS_UNKNOWN_TLV:
    case FWCOMPS_REG_ACCESS_REG_NOT_SUPP:
    case FWCOMPS_REG_ACCESS_CLASS_NOT_SUPP:
    case FWCOMPS_REG_ACCESS_METHOD_NOT_SUPP:
    case FWCOMPS_REG_ACCESS_BAD_PARAM:
    case FWCOMPS_REG_ACCESS_RES_NOT_AVLBL:
    case FWCOMPS_REG_ACCESS_MSG_RECPT_ACK:
    case FWCOMPS_REG_ACCESS_UNKNOWN_ERR:
    case FWCOMPS_REG_ACCESS_SIZE_EXCCEEDS_LIMIT:
    case FWCOMPS_REG_ACCESS_CONF_CORRUPT:
    case FWCOMPS_REG_ACCESS_LEN_TOO_SMALL:
    case FWCOMPS_REG_ACCESS_BAD_CONFIG:
    case FWCOMPS_REG_ACCESS_ERASE_EXEEDED:
    case FWCOMPS_REG_ACCESS_INTERNAL_ERROR:
        return (unsigned char*)reg_access_err2str(_lastRegAccessStatus);

    default:
        if (_lastRegAccessStatus) {
            return (unsigned char*)reg_access_err2str(_lastRegAccessStatus);
        }
        return (unsigned char*)"GENERAL ERROR";
    }
}

bool FwCompsMgr::lock_flash_semaphore()
{
#ifndef UEFI_BUILD
    int rc = 0;
    trm_sts trm_rc = trm_create(&_trm, _mf);
    if (trm_rc) {
        _lastError = FWCOMPS_FAIL_TO_CREATE_TRM_CONTEXT;
        return false;
    }
    rc = trm_lock(_trm, TRM_RES_FLASH_PROGRAMING, MAX_FLASH_PROG_SEM_RETRY_CNT);
    if (rc && rc != TRM_STS_RES_NOT_SUPPORTED) {
        _lastError = FWCOMPS_FAIL_TO_LOCK_FLASH_SEMAPHORE;
        return false;
    }
#endif
    return true;
}

void FwCompsMgr::unlock_flash_semaphore()
{
#ifndef UEFI_BUILD
    if (_trm != NULL) {
        trm_unlock(_trm, TRM_RES_FLASH_PROGRAMING);
        trm_destroy(_trm);
        _trm = NULL;
    }
#endif
}


void FwCompsMgr::deal_with_signal()
{
#ifndef UEFI_BUILD
    int sig;
    sig = mft_signal_is_fired();
    if (sig) {
        unlock_flash_semaphore();
        // reset received signal
        mft_signal_set_fired(0);
        // retore prev handler
        mft_signal_set_handling(0);
        //raise signal to let the previous handle deal with it.
        raise(sig);
    }
    mft_signal_set_handling(0);
#endif
    return;
}

bool FwCompsMgr::getComponentVersion(FwComponent::comps_ids_t compType,
                                     bool pending,
                                     component_version_st *cmpVer)
{
    std::vector<u_int32_t> imageInfoData;
    if (!cmpVer) {
        _lastError = FWCOMPS_BAD_PARAM;
        return false;
    }
    if (!readComponentInfo(compType, COMPINFO_VERSIONS, imageInfoData, pending)) {
        return false;
    }
    memset(cmpVer, 0, sizeof(component_version_st));
    cmpVer->version_string_length = _currCompInfo.data.mcqi_version.version_string_length;
    cmpVer->user_defined_time_valid = _currCompInfo.data.mcqi_version.user_defined_time_valid;
    cmpVer->build_time_valid = _currCompInfo.data.mcqi_version.build_time_valid;
    cmpVer->version = _currCompInfo.data.mcqi_version.version;
    cmpVer->build_time = _currCompInfo.data.mcqi_version.build_time;
    cmpVer->user_defined_time = _currCompInfo.data.mcqi_version.user_defined_time;
    cmpVer->build_tool_version = _currCompInfo.data.mcqi_version.build_tool_version;
    if (_currCompInfo.data.mcqi_version.version_string_length) {
        memcpy(cmpVer->version_string, _currCompInfo.data.mcqi_version.version_string, _currCompInfo.data.mcqi_version.version_string_length);
        _productVerStr.resize(_currCompInfo.data.mcqi_version.version_string_length);
        memcpy(_productVerStr.data(), _currCompInfo.data.mcqi_version.version_string, _currCompInfo.data.mcqi_version.version_string_length);
    }
    return true;
}

bool FwCompsMgr::GetComponentLinkxProperties(FwComponent::comps_ids_t compType, component_linkx_st *cmpLinkX)
{
    std::vector<u_int32_t> imageInfoData;
    if (!cmpLinkX) {
        _lastError = FWCOMPS_BAD_PARAM;
        return false;
    }
    _deviceIndex = _linkXDeviceIndex;

    //make MCQS first of all to check if device is present

    comp_query_st * currCompQuery = &(_compsQueryMap[compType]);
    u_int32_t componentIndex = currCompQuery->comp_status.component_index;
    comp_status_st query;
    if (!queryComponentStatus(componentIndex, &query)) {
        return false;
    }
    if (query.component_status == 0) {
        printf("Cable %d is not found, please check that cable connected.\n", _deviceIndex - 1);
        _lastError = FWCOMPS_MCC_ERR_REJECTED_NOT_APPLICABLE;
        return false;
    }

    if (!readComponentInfo(compType, COMPINFO_LINKX_PROPERTIES, imageInfoData, false)) {
        return false;
    }
    memset(cmpLinkX, 0, sizeof(component_linkx_st));
    cmpLinkX->fw_image_status_bitmap = _currCompInfo.data.mcqi_linkx_properties.fw_image_status_bitmap;
    cmpLinkX->fw_image_info_bitmap = _currCompInfo.data.mcqi_linkx_properties.fw_image_info_bitmap;
    cmpLinkX->image_a_minor = _currCompInfo.data.mcqi_linkx_properties.image_a_minor;
    cmpLinkX->image_a_major = _currCompInfo.data.mcqi_linkx_properties.image_a_major;
    cmpLinkX->image_a_subminor = _currCompInfo.data.mcqi_linkx_properties.image_a_subminor;
    cmpLinkX->image_b_minor = _currCompInfo.data.mcqi_linkx_properties.image_b_minor;
    cmpLinkX->image_b_major = _currCompInfo.data.mcqi_linkx_properties.image_b_major;
    cmpLinkX->image_b_subminor = _currCompInfo.data.mcqi_linkx_properties.image_b_subminor;
    cmpLinkX->factory_image_minor = _currCompInfo.data.mcqi_linkx_properties.factory_image_minor;
    cmpLinkX->factory_image_major = _currCompInfo.data.mcqi_linkx_properties.factory_image_major;
    cmpLinkX->factory_image_subminor = _currCompInfo.data.mcqi_linkx_properties.factory_image_subminor;
    cmpLinkX->management_interface_protocol = _currCompInfo.data.mcqi_linkx_properties.management_interface_protocol;
    cmpLinkX->activation_type = _currCompInfo.data.mcqi_linkx_properties.activation_type;
    cmpLinkX->vendor_sn = _currCompInfo.data.mcqi_linkx_properties.vendor_sn;
    return true;
}

bool FwCompsMgr::readBlockFromComponent(FwComponent::comps_ids_t compId,
                                        u_int32_t offset,
                                        u_int32_t size,
                                        std::vector<u_int8_t>& data)
{
    if (!RefreshComponentsStatus()) {
        return false;
    }
    _currCompQuery = &(_compsQueryMap[compId]);
    _componentIndex = _currCompQuery->comp_status.component_index;
    u_int32_t compSize = _currCompQuery->comp_cap.component_size;
    if (offset + size > compSize) {
        _lastError = FWCOMPS_READ_OUTSIDE_IMAGE_RANGE;
        return false;
    }
    if (_currCompQuery->comp_cap.rd_en) {
        data.resize(size);
        if (!controlFsm(FSM_CMD_LOCK_UPDATE_HANDLE, FSMST_LOCKED)) {
            return false;
        }
        control_fsm_args_t fsmReadCommand;
        fsmReadCommand.command = FSM_CMD_READ_PENDING_COMPONENT;
        fsmReadCommand.expectedState = FSMST_UPLOAD;
        if (!controlFsm(FSM_CMD_READ_PENDING_COMPONENT, FSMST_UPLOAD)) {
            fsmReadCommand.command = FSM_CMD_READ_COMPONENT;
            if (!controlFsm(FSM_CMD_READ_COMPONENT, FSMST_UPLOAD)) {
                _lastError = FWCOMPS_READ_COMP_FAILED;
                return false;
            }
        }
        if (!accessComponent(offset, size, (u_int32_t *)(data.data()), MCC_READ_COMP, NULL, &fsmReadCommand)) {
            return false;
        }
        if (!controlFsm(FSM_CMD_RELEASE_UPDATE_HANDLE)) {
            return false;
        }
    }
    else {
        _lastError = FWCOMPS_READ_COMP_NOT_SUPPORTED;
        DPRINTF(("readBlockFromComponent : RD EN is 0 for component index %u compId %s \n", _componentIndex, FwComponent::getCompIdStr(compId)));
        return false;
    }
    return true;
}

bool FwCompsMgr::fwReactivateImage()
{
    tools_open_mirc_reg mirc;
    mirc.status_code = 0;
    int currentIteration = 0;
    int sleepTimeMs = 50;
    int maxWaitingTime = 30000;//30 sec is enough time
    int maxNumOfIterations = maxWaitingTime / sleepTimeMs;//600 iterations

    if (_mircCaps == false) {
        _lastError = FWCOMPS_IMAGE_REACTIVATION_FW_NOT_SUPPORTED;
        setLastRegisterAccessStatus(ME_REG_ACCESS_NOT_SUPPORTED);
        return false;
    }

    reg_access_status_t rc;
    rc = reg_access_mirc(_mf, REG_ACCESS_METHOD_SET, &mirc);//send trigger to FW
    deal_with_signal();
    if (rc) {
        DPRINTF(("1 reg_access_mirc failed rc = %d\n", rc));
        _lastError = regErrTrans(rc);
        setLastRegisterAccessStatus(rc);
        return false;
    }
    memset(&mirc, 0, sizeof(mirc));
    msleep(sleepTimeMs);
    rc = reg_access_mirc(_mf, REG_ACCESS_METHOD_GET, &mirc);
    if (rc) {
        DPRINTF(("2 reg_access_mirc failed rc = %d\n", rc));
        _lastError = regErrTrans(rc);
        return false;
    }
    DPRINTF(("1 mirc.status_code = %d\n", mirc.status_code));
    while (mirc.status_code == IMAGE_REACTIVATION_BUSY) {
        msleep(sleepTimeMs);
        rc = reg_access_mirc(_mf, REG_ACCESS_METHOD_GET, &mirc);
        deal_with_signal();
        if (rc) {
            _lastError = regErrTrans(rc);
            setLastRegisterAccessStatus(rc);
            DPRINTF(("3 reg_access_mirc failed rc = %d\n", rc));
            return false;
        }
        DPRINTF(("2 iteration %d mirc.status_code = %d\n", currentIteration++, mirc.status_code));
        if (currentIteration >= maxNumOfIterations) {
            _lastError = FWCOMPS_IMAGE_REACTIVATION_WAITING_TIME_EXPIRED;
            return false;
        }
    }
    if (mirc.status_code == IMAGE_REACTIVATION_SUCCESS) {
        return true;
    }
    else if (mirc.status_code == IMAGE_REACTIVATION_PROHIBITED_FW_VER_ERR) {
        _lastError = FWCOMPS_IMAGE_REACTIVATION_PROHIBITED_FW_VER_ERR;
    }
    else if (mirc.status_code == IMAGE_REACTIVATION_FIRST_PAGE_COPY_FAILED) {
        _lastError = FWCOMPS_IMAGE_REACTIVATION_FIRST_PAGE_COPY_FAILED;
    }
    else if (mirc.status_code == IMAGE_REACTIVATION_FIRST_PAGE_ERASE_FAILED) {
        _lastError = FWCOMPS_IMAGE_REACTIVATION_FIRST_PAGE_ERASE_FAILED;
    }
    else if (mirc.status_code == IMAGE_REACTIVATION_FIRST_PAGE_RESTORE_FAILED) {
        _lastError = FWCOMPS_IMAGE_REACTIVATION_FIRST_PAGE_RESTORE_FAILED;
    }
    else if (mirc.status_code == IMAGE_REACTIVATION_FW_DEACTIVATION_FAILED) {
        _lastError = FWCOMPS_IMAGE_REACTIVATION_FW_DEACTIVATION_FAILED;
    }
    else if (mirc.status_code == IMAGE_REACTIVATION_FW_ALREADY_ACTIVATED) {
        _lastError = FWCOMPS_IMAGE_REACTIVATION_FW_ALREADY_ACTIVATED;
    }
    else if (mirc.status_code == IMAGE_REACTIVATION_ERROR_DEVICE_RESET_REQUIRED) {
        _lastError = FWCOMPS_IMAGE_REACTIVATION_ERROR_DEVICE_RESET_REQUIRED;
    }
    else if (mirc.status_code == IMAGE_REACTIVATION_FW_PROGRAMMING_NEEDED) {
        _lastError = FWCOMPS_IMAGE_REACTIVATION_FW_PROGRAMMING_NEEDED;
    }
    else {
        _lastError = FWCOMPS_IMAGE_REACTIVATION_UNKNOWN_ERROR;
    }
    return false;
}
void FwCompsMgr::setLastFirmwareError(fw_comps_error_t fw_error)
{
    _lastError = fw_error;
}

void FwCompsMgr::setLastRegisterAccessStatus(reg_access_status_t err)
{
    _lastRegAccessStatus = err;
}

fw_comps_error_t FwCompsMgr::regErrTrans(reg_access_status_t err)
{
    if (err != ME_REG_ACCESS_OK) {
        DPRINTF(("%s error - %d\n",__FUNCTION__, err));
    }
    switch (err) {
    case ME_REG_ACCESS_OK:
        return FWCOMPS_REG_ACCESS_OK;

    case ME_REG_ACCESS_BAD_STATUS_ERR:
        return FWCOMPS_REG_ACCESS_BAD_STATUS_ERR;

    case ME_REG_ACCESS_BAD_METHOD:
        return FWCOMPS_REG_ACCESS_BAD_STATUS_ERR;

    case ME_REG_ACCESS_NOT_SUPPORTED:
        return FWCOMPS_REG_ACCESS_NOT_SUPPORTED;

    case ME_REG_ACCESS_DEV_BUSY:
        return FWCOMPS_REG_ACCESS_DEV_BUSY;

    case ME_REG_ACCESS_VER_NOT_SUPP:
        return FWCOMPS_REG_ACCESS_VER_NOT_SUPP;

    case ME_REG_ACCESS_UNKNOWN_TLV:
        return FWCOMPS_REG_ACCESS_UNKNOWN_TLV;

    case ME_REG_ACCESS_REG_NOT_SUPP:
        return FWCOMPS_REG_ACCESS_REG_NOT_SUPP;

    case ME_REG_ACCESS_CLASS_NOT_SUPP:
        return FWCOMPS_REG_ACCESS_CLASS_NOT_SUPP;

    case ME_REG_ACCESS_METHOD_NOT_SUPP:
        return FWCOMPS_REG_ACCESS_METHOD_NOT_SUPP;

    case ME_REG_ACCESS_BAD_PARAM:
        return FWCOMPS_REG_ACCESS_BAD_PARAM;

    case ME_REG_ACCESS_RES_NOT_AVLBL:
        return FWCOMPS_REG_ACCESS_RES_NOT_AVLBL;

    case ME_REG_ACCESS_MSG_RECPT_ACK:
        return FWCOMPS_REG_ACCESS_MSG_RECPT_ACK;

    case ME_REG_ACCESS_UNKNOWN_ERR:
        return FWCOMPS_REG_ACCESS_UNKNOWN_ERR;

    case ME_REG_ACCESS_SIZE_EXCCEEDS_LIMIT:
        return FWCOMPS_REG_ACCESS_SIZE_EXCCEEDS_LIMIT;

    case ME_REG_ACCESS_CONF_CORRUPT:
        return FWCOMPS_REG_ACCESS_CONF_CORRUPT;

    case ME_REG_ACCESS_LEN_TOO_SMALL:
        return FWCOMPS_REG_ACCESS_CONF_CORRUPT;

    case ME_REG_ACCESS_BAD_CONFIG:
        return FWCOMPS_REG_ACCESS_BAD_CONFIG;

    case ME_REG_ACCESS_ERASE_EXEEDED:
        return FWCOMPS_REG_ACCESS_ERASE_EXEEDED;

    case ME_REG_ACCESS_INTERNAL_ERROR:
        return FWCOMPS_REG_ACCESS_INTERNAL_ERROR;

    default:
        return FWCOMPS_GENERAL_ERR;
    }
}

fw_comps_error_t FwCompsMgr::mccErrTrans(u_int8_t err)
{
    if (err != MCC_ERRCODE_OK)
    {
        DPRINTF(("\nMCC ERROR: %x\n", err));
    }

    switch (err) {
    case MCC_ERRCODE_OK:
        return FWCOMPS_SUCCESS;

    case MCC_ERRCODE_ERROR:
        return FWCOMPS_MCC_ERR_ERROR;

    case MCC_ERRCODE_REJECTED_DIGEST_ERR:
        return FWCOMPS_MCC_ERR_REJECTED_DIGEST_ERR;

    case MCC_ERRCODE_REJECTED_NOT_APPLICABLE:
        return FWCOMPS_MCC_ERR_REJECTED_NOT_APPLICABLE;

    case MCC_ERRCODE_REJECTED_UNKNOWN_KEY:
        return FWCOMPS_MCC_ERR_REJECTED_UNKNOWN_KEY;

    case MCC_ERRCODE_REJECTED_AUTH_FAILED:
        return FWCOMPS_MCC_ERR_REJECTED_AUTH_FAILED;

    case MCC_ERRCODE_REJECTED_UNSIGNED:
        return FWCOMPS_MCC_ERR_REJECTED_UNSIGNED;

    case MCC_ERRCODE_REJECTED_KEY_NOT_APPLICABLE:
        return FWCOMPS_MCC_ERR_REJECTED_KEY_NOT_APPLICABLE;

    case MCC_ERRCODE_REJECTED_BAD_FORMAT:
        return FWCOMPS_MCC_ERR_REJECTED_BAD_FORMAT;

    case MCC_ERRCODE_BLOCKED_PENDING_RESET:
        return FWCOMPS_MCC_ERR_BLOCKED_PENDING_RESET;

    case MCC_ERRCODE_REJECTED_NOT_A_SECURED_FW:
        return FWCOMPS_MCC_REJECTED_NOT_A_SECURED_FW;

    case MCC_ERRCODE_REJECTED_MFG_BASE_MAC_NOT_LISTED:
        return FWCOMPS_MCC_REJECTED_MFG_BASE_MAC_NOT_LISTED;

    case MCC_ERRCODE_REJECTED_NO_DEBUG_TOKEN:
        return FWCOMPS_MCC_REJECTED_NO_DEBUG_TOKEN;

    case MCC_ERRCODE_REJECTED_VERSION_NUM_MISMATCH:
        return FWCOMPS_MCC_REJECTED_VERSION_NUM_MISMATCH;

    case MCC_ERRCODE_REJECTED_USER_TIMESTAMP_MISMATCH:
        return FWCOMPS_MCC_REJECTED_USER_TIMESTAMP_MISMATCH;

    case MCC_ERRCODE_REJECTED_FORBIDDEN_VERSION:
        return FWCOMPS_MCC_REJECTED_FORBIDDEN_VERSION;

    case MCC_ERRCODE_FLASH_ERASE_ERROR:
        return FWCOMPS_MCC_FLASH_ERASE_ERROR;

    case MCC_ERRCODE_REJECTED_IMAGE_CAN_NOT_BOOT_FROM_PARTITION:
        return FWCOMPS_MCC_REJECTED_IMAGE_CAN_NOT_BOOT_FROM_PARTITION;

    case MCC_ERRCODE_REJECTED_LINKX_TYPE_NOT_SUPPORTED:
        return FWCOMPS_MCC_REJECTED_LINKX_TYPE_NOT_SUPPORTED;

    case MCC_ERRCODE_REJECTED_HOST_STORAGE_IN_USE:
        return FWCOMPS_MCC_REJECTED_HOST_STORAGE_IN_USE;

    case MCC_ERRCODE_REJECTED_LINKX_TRANSFER:
        return FWCOMPS_MCC_REJECTED_LINKX_TRANSFER;

    case MCC_ERRCODE_REJECTED_LINKX_ACTIVATE:
        return FWCOMPS_MCC_REJECTED_LINKX_ACTIVATE;

    case MCC_ERRCODE_REJECTED_INCOMPATIBLE_FLASH:
        return FWCOMPS_MCC_REJECTED_INCOMPATIBLE_FLASH;

    default:
        return FWCOMPS_GENERAL_ERR;
    }
}
