/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
 *
 * this file licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 * http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include "sml_errcodes.h"
#include "sml.h"
#include "stdlib.h"
#include "stdio.h"
#include "unistd.h"
#include "sys/stat.h"
#include "openssl/evp.h"
#include "histore/tool_lib.h"
#include "hs_misc.h"
#include "hs_ctrl_upgrade.h"

LOCAL guint32 g_aui_crc32table[CRC_TABLE_SIZE] = {
    0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
    0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD,
    0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75,
    0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A, 0x745E66CD,
    0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039, 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5,
    0xBE2B5B58, 0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D,
    0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95,
    0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D,
    0x34867077, 0x30476DC0, 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072,
    0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA,
    0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02,
    0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
    0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC, 0xB6238B25, 0xB2E29692,
    0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A,
    0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2,
    0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34, 0xDC3ABDED, 0xD8FBA05A,
    0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB,
    0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53,
    0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C, 0x3B5A6B9B,
    0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF, 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623,
    0xF12F560E, 0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B,
    0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3,
    0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B,
    0x9B3660C6, 0x9FF77D71, 0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3,
    0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C,
    0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24,
    0x119B4BE9, 0x155A565E, 0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
    0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A, 0x2D15EBE3, 0x29D4F654,
    0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C,
    0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4,
    0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB, 0x97FFAD0C,
    0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4
};

LOCAL gint32 get_buf_hash(guint32 hash_algo, guint8* src_data, guint32 src_len, guint8* hash_buf, guint32 *hash_len)
{
    guint32 dst_len;

    if ((hash_len == NULL) || (*hash_len < EVP_MAX_MD_SIZE)) {
        return -EINVAL;
    }

    (void)EVP_add_digest(EVP_sm3());
    if (hash_algo == RAIDADM_UPDATE_ALGO_SHA256) {
        (void)EVP_Digest(src_data, (guint64)src_len, hash_buf, &dst_len, EVP_sha256(), NULL);
    } else if (hash_algo == RAIDADM_UPDATE_ALGO_SM3) {
        (void)EVP_Digest(src_data, (guint64)src_len, hash_buf, &dst_len, EVP_sm3(), NULL);
    } else {
        return -EINVAL;
    }

    *hash_len = dst_len;

    return RET_OK;
}

/*
 * Description : 校验升级镜像文件的header
 */
LOCAL gint32 update_fw_check_header(RAIDADM_IMG_HEADER_INFO_S *pheader, guint8 *pdata, guint32 len)
{
    guint8 shabuf[EVP_MAX_MD_SIZE] = {0};
    guint32 hash_len = EVP_MAX_MD_SIZE;

    if (pheader == NULL || pdata == NULL) {
        debug_log(DLOG_ERROR, "%s: The input param is corrupted!", __FUNCTION__);
        return -EINVAL;
    }

    if (get_buf_hash(pheader->algo, pdata, len, shabuf, &hash_len)) {
        debug_log(DLOG_ERROR, "%s: Get data hash failed!", __FUNCTION__);
        return -EINVAL;
    }

    if (memcmp(pheader->header_checksum, shabuf, (guint64)hash_len)) {
        debug_log(DLOG_ERROR, "%s: The img file header is corrupted!", __FUNCTION__);
        return -EINVAL;
    }

    return RET_OK;
}

/*
 * Description : 校验升级镜像文件的targets
 */
LOCAL gint32 update_fw_check_targets(struct raidadm_img_header_info *pheader, guint8 *pdata, guint32 len)
{
    guint8 shabuf[EVP_MAX_MD_SIZE] = {0};
    guint32 hash_len = EVP_MAX_MD_SIZE;

    if (pheader == NULL || pdata == NULL) {
        debug_log(DLOG_ERROR, "%s: The input param is corrupted!", __FUNCTION__);
        return -EINVAL;
    }

    if (get_buf_hash(pheader->algo, pdata, len, shabuf, &hash_len)) {
        debug_log(DLOG_ERROR, "%s: Get data hash failed!", __FUNCTION__);
        return -EINVAL;
    }

    if (memcmp(pheader->packet_checksum, shabuf, (guint64)hash_len)) {
        debug_log(DLOG_ERROR, "%s: The img file targets is corrupted!", __FUNCTION__);
        return -EINVAL;
    }

    return RET_OK;
}

/*
 * Description : 校验升级镜像文件的header和targets
 */
LOCAL gint32 check_header_and_targets(FILE *fp, struct stat *statinfo, RAIDADM_IMG_HEADER_INFO_S **pheader)
{
    guint8 *pdata = (guint8 *)(*pheader);

    // 获取img文件header
    if (fread(pdata, 1, RAIDADM_UPDATE_IMG_HEADER_LEN, fp) != RAIDADM_UPDATE_IMG_HEADER_LEN) {
        debug_log(DLOG_ERROR, "%s: Can not read file header!", __FUNCTION__);
        return -EPERM;
    }

    if (update_fw_check_header(*pheader, pdata, RAIDADM_UPDATE_IMG_HEADER_LEN - RAIDADM_UPDATE_CHECKSUM_LEN)) {
        debug_log(DLOG_ERROR, "%s: img file header is corrupted!", __FUNCTION__);
        return -EINVAL;
    }

    if ((statinfo->st_size <= RAIDADM_UPDATE_IMG_HEADER_LEN) ||
        (statinfo->st_size > RAIDADM_UPDATE_IMG_FILE_MAX_SIZE)) {
        debug_log(DLOG_ERROR, "%s: img file size error(%lu)!", __FUNCTION__, statinfo->st_size);
        return -EINVAL;
    }

    guint8 *ptgt = malloc((guint64)(statinfo->st_size - RAIDADM_UPDATE_IMG_HEADER_LEN));
    if (ptgt == NULL) {
        debug_log(DLOG_ERROR, "%s: No space to read img file!", __FUNCTION__);
        return -ENOSPC;
    }

    // 获取img文件targets
    gint32 ret = (int)fread(ptgt, 1UL, (size_t)(statinfo->st_size - RAIDADM_UPDATE_IMG_HEADER_LEN), fp);
    if (ret != (statinfo->st_size - RAIDADM_UPDATE_IMG_HEADER_LEN)) {
        debug_log(DLOG_ERROR, "%s: Can not read file targets!", __FUNCTION__);
        g_free(ptgt);
        return -EINVAL;
    }

    if (update_fw_check_targets(*pheader, ptgt, (guint32)(statinfo->st_size - RAIDADM_UPDATE_IMG_HEADER_LEN))) {
        debug_log(DLOG_ERROR, "%s: img file targets is corrupted!", __FUNCTION__);
        g_free(ptgt);
        return -EINVAL;
    }
    g_free(ptgt);

    return RET_OK;
}

/*
 * Description : 校验升级的镜像文件
 */
LOCAL gint32 update_fw_check_img(FILE *fp, RAIDADM_IMG_HEADER_INFO_S **pheader,
    SML_CTRL_UPGRADE_PARAM* param)
{
    struct stat statinfo = {0};

    if (pheader == NULL || fp == NULL) {
        debug_log(DLOG_ERROR, "%s: Input param invalid!", __FUNCTION__);
        return RET_ERR;
    }

    if (sizeof(RAIDADM_IMG_HEADER_INFO_S) != RAIDADM_UPDATE_IMG_HEADER_LEN) {
        debug_log(DLOG_ERROR, "%s: Header struct is corrupted!", __FUNCTION__);
        return RET_ERR;
    }

    if (stat(param->file_path, &statinfo) < 0) {
        debug_log(DLOG_ERROR, "%s: Get img file stat information failed!", __FUNCTION__);
        return RET_ERR;
    }
    param->file_size = (size_t)statinfo.st_size;
    gint32 ret = fseek(fp, (long int)0, SEEK_SET);
    if (ret != 0) {
        debug_log(DLOG_ERROR, "%s: Change read file location fail!", __FUNCTION__);
        return ret;
    }

    ret = check_header_and_targets(fp, &statinfo, pheader);
    if (ret != 0) {
        return RET_ERR;
    }
    return RET_OK;
}

LOCAL void *get_pagesize_memalign(void)
{
    void *addr = NULL;

    gint32 ret = posix_memalign(&addr, (size_t)(long)getpagesize(), (size_t)HISTORE_ADM_MAX_DATA_SIZE);
    if (ret != RET_OK) {
        debug_log(DLOG_ERROR, "%s: malloc is NULL, ret = %d", __FUNCTION__, ret);
        return NULL;
    }
    ret = memset_s(addr, HISTORE_ADM_MAX_DATA_SIZE, 0, HISTORE_ADM_MAX_DATA_SIZE);
    if (ret != RET_OK) {
        debug_log(DLOG_ERROR, "%s: Init memory fail, ret = %d", __FUNCTION__, ret);
        g_free(addr);
        return NULL;
    }
    return addr;
}

LOCAL guint32 crc_create_buffer_crc(const guchar *puc_buffer_info, guint32 buffer_len_info)
{
    guint32 old_crc;
    gint32 i;
    guchar in_byte;
    guchar out_byte;
    guint32 tmp_buffer_len_info = buffer_len_info;
    /* 参数合法性判断 */
    if (puc_buffer_info == NULL) {
        debug_log(DLOG_ERROR, "%s: buff is NULL!", __FUNCTION__);
        return 0;
    }
    if (tmp_buffer_len_info == 0) {
        return 0;
    }

    guint32 old_crc32 = 0x00000000; /* 初值为0 */
    guint32 char_cnt = 0;
    while (tmp_buffer_len_info-- != 0) {
        out_byte = (old_crc32 >> CRC_OFFSET_24_BITS) & 0xff; /* 要移出的字节的值 */
        old_crc = g_aui_crc32table[out_byte]; /* 根据移出的字节的值查表 */
        in_byte = puc_buffer_info[char_cnt]; /* 新移进来的字节值 */
        in_byte = in_byte & 0xff;
        old_crc32 = (old_crc32 << CRC_OFFSET_8_BITS) | in_byte; /* 将新移进来的字节添加在寄存器末字节中 */
        old_crc32 = old_crc32 ^ old_crc; /* 将寄存器与查出的值进行XOR运算 */
        char_cnt++;
    }
    /*
     * 最后4个字节的数据也要校验移出，这样做是因为uiOldCrc32初值
     * 为0占用了4字节移出，导致少移出校验4字节
     */
    for (i = 0; i < TRAS_TIME_4; i++) {
        out_byte = (old_crc32 >> CRC_OFFSET_24_BITS) & 0xff; /* 要移出的字节的值 */
        old_crc = g_aui_crc32table[out_byte]; /* 根据移出的字节的值查表 */
        old_crc32 = (old_crc32 << CRC_OFFSET_8_BITS) | 0x00; /* 将新移进来的字节添加在寄存器末字节中 */
        old_crc32 = old_crc32 ^ old_crc; /* 将寄存器与查出的值进行XOR运算 */
    }

    return old_crc32;
}

/*
 * Description : 校验升级文件传输是否完成
 */
LOCAL gint32 update_fw_set_piece_attr(guint32 seq, guint32 total_len, CMD_UPDATE_FIRMWARE_S *pcmd_param)
{
    guint32 last_piece_len = total_len % HISTORE_ADM_MAX_DATA_SIZE;

    if (pcmd_param->trans_flag & DATA_TRANS_END_FLAG) {
        return TRUE; // 传输target已结束
    }

    pcmd_param->seq = (guint16)seq;
    if (total_len <= HISTORE_ADM_MAX_DATA_SIZE) {
        pcmd_param->cur_slice_len = total_len;
        pcmd_param->trans_flag = (DATA_TRANS_START_FLAG | DATA_TRANS_END_FLAG);
        return TRUE;
    }

    if (seq == 0) {
        pcmd_param->trans_flag = DATA_TRANS_START_FLAG;
        pcmd_param->cur_slice_len = HISTORE_ADM_MAX_DATA_SIZE;
    } else if ((seq * HISTORE_ADM_MAX_DATA_SIZE + HISTORE_ADM_MAX_DATA_SIZE) < total_len) {
        pcmd_param->trans_flag = DATA_TRANS_ING_FLAG;
        pcmd_param->cur_slice_len = HISTORE_ADM_MAX_DATA_SIZE;
    } else {
        pcmd_param->trans_flag = DATA_TRANS_END_FLAG;
        pcmd_param->cur_slice_len = (last_piece_len == 0) ? HISTORE_ADM_MAX_DATA_SIZE : last_piece_len;
    }

    return FALSE;
}

LOCAL gint32 update_fw_read_img_data(FILE* fp, guchar *file_data, guint32 offset, guint32 read_len)
{
    gint32 ret = fseek(fp, (gint32)offset, SEEK_SET);
    if (ret != RET_OK) {
        debug_log(DLOG_ERROR, "%s: change read file locat fail!", __FUNCTION__);
        return ret;
    }
    ret = (int)fread(file_data, 1, read_len, fp);
    if (ret != (int)read_len) {
        debug_log(DLOG_ERROR, "%s: Can not read file data right!", __FUNCTION__);
        return -EINVAL;
    }

    return RET_OK;
}

/*
 * Description : 获取分片传输的数据及其crc校验码
 */
LOCAL guint32 raidadm_crc32(const guchar *buf, guint32 len)
{
    if ((buf == NULL) || (len == 0)) {
        debug_log(DLOG_ERROR, "%s: buf is null or len is zero!", __FUNCTION__);
        return EINVAL;
    }

    return crc_create_buffer_crc(buf, len);
}

/*
* Description : 使能RAID卡升级
*/
LOCAL gint32 histore_active_ctrl_upgrade(guint32 ctrl_id)
{
    struct lib_cmd_param lib_param;
    struct cmd_active_firmware para;
    (void)memset_s(&lib_param, sizeof(lib_param), 0, sizeof(lib_param));
    (void)memset_s(&para, sizeof(para), 0, sizeof(para));

    lib_param.opcode = ADM_RAID_SET;
    lib_param.subopcode = ADM_CMD_ACTIVE_FW;
    lib_param.card_id = ctrl_id;
    lib_param.channel = PCIE_PHYSICAL_FUCTION0;
    lib_param.param_len = sizeof(struct cmd_active_firmware);
    lib_param.timeout_ms = USER_CMD_DEFAULT_TIMEOUT_MS; // raid卡热升级

    para.act_bitmap = 0x3ff; // 0x3ff为固定值
    para.is_force = 0;
    para.type = 1; // 默认发送热升级，1为热升级，0为冷升级
    if (memcpy_s(lib_param.cmd_param, LIB_PARAM_SIZE, &para, sizeof(para)) != EOK) {
        debug_log(DLOG_ERROR, "Copy cmd param to lib failed!");
        return SML_ERR_SEC_FUNC_FAILED;
    }
    return process_histore_cmd(&lib_param);
}

/*
* Description : 传输升级文件到RAID卡
*/
LOCAL gint32 histore_send_ctrl_upgrade_file(guint32 ctrl_id, gpointer param, gpointer data)
{
    struct lib_cmd_param lib_param;
    (void)memset_s(&lib_param, sizeof(lib_param), 0, sizeof(lib_param));
    if (param == NULL || data == NULL) {
        return SML_ERR_NULL_DATA;
    }
    struct cmd_update_firmware *cmd_param = (struct cmd_update_firmware *)param;

    lib_param.opcode = ADM_RAID_WRITE;
    lib_param.subopcode = ADM_CMD_UPDATE_FW;
    lib_param.card_id = ctrl_id;
    lib_param.channel = PCIE_PHYSICAL_FUCTION0;
    lib_param.param_len = sizeof(struct cmd_update_firmware);
    lib_param.data = data;
    lib_param.data_len = (guint16)cmd_param->cur_slice_len;
    lib_param.timeout_ms = USER_CMD_TIMEOUT_MS; // 升级需要擦除大块flash空间，耗时较长，需指定超时时间

    /* 将命令参数拷贝到lib_cmd_param */
    if (memcpy_s(lib_param.cmd_param, LIB_PARAM_SIZE, cmd_param, sizeof(struct cmd_update_firmware))) {
        debug_log(DLOG_ERROR, "Copy cmd param to lib fail!");
        return SML_ERR_SEC_FUNC_FAILED;
    }
    return process_histore_cmd(&lib_param);
}

  /*
 * Description : 分片传输升级文件到RAID
 */
LOCAL gint32 update_fw_transport_tgt(FILE *fp, guint32 offset, guint32 len, CMD_UPDATE_FIRMWARE_S * pcmd_param,
    SML_CTRL_UPGRADE_PARAM* param)
{
    gint32 ret = 0;
    guint32 i;

    void *file_data = get_pagesize_memalign();
    if (file_data == NULL) {
        debug_log(DLOG_ERROR, "%s: Malloc file_data failed!", __FUNCTION__);
        return -ENXIO;
    }

    pcmd_param->trans_flag = 0;
    guint32 pieces_num = len / HISTORE_ADM_MAX_DATA_SIZE;

    for (i = 0; i <= pieces_num; i++) {
        if (memset_s(file_data, HISTORE_ADM_MAX_DATA_SIZE, 0, HISTORE_ADM_MAX_DATA_SIZE)) {
            debug_log(DLOG_ERROR, "%s: memset file_data failed!", __FUNCTION__);
            g_free(file_data);
            return -errno;
        }

        if (update_fw_set_piece_attr(i, len, pcmd_param)) {
            break; // 已经传输完成
        }

        guint32 pieces_offset = i * HISTORE_ADM_MAX_DATA_SIZE;
        ret = update_fw_read_img_data(fp, file_data, offset + pieces_offset, pcmd_param->cur_slice_len);
        if (ret != 0) {
            debug_log(DLOG_ERROR, "%s: Read target date from img failed! ret = %d!", __FUNCTION__, ret);
            break;
        }

        pcmd_param->data_crc = raidadm_crc32(file_data, pcmd_param->cur_slice_len); // 设置crc校验值
        ret = histore_send_ctrl_upgrade_file(param->controller_index, (gpointer)pcmd_param, (gpointer)file_data);
        if (ret != RET_OK) {
            debug_log(DLOG_ERROR, "%s: Call update_fw_send_cmd failed!, ret = 0x%04x", __FUNCTION__, ret);
            break;
        }

        if (pcmd_param->trans_flag & DATA_TRANS_END_FLAG) {
            break;
        }
    }
    g_free(file_data);
    return ret;
}

  /*
 * Description : 传输升级文件到RAID
 */
LOCAL gint32 transport_data_slice(SML_CTRL_UPGRADE_PARAM* param, RAIDADM_IMG_HEADER_INFO_S *pheader, FILE* read_fp)
{
    gint32 ret;
    CMD_UPDATE_FIRMWARE_S cmd_param = {0};
    const guint16 g_bitmap = 0x3ff; // 固定值

    cmd_param.algo_type = (guchar)pheader->algo;
    cmd_param.tgt_bit_map = g_bitmap;
    debug_log(DLOG_INFO, "tgt_num = %d!", pheader->tgt_num);

    for (guint32 i = 0; i < pheader->tgt_num; i++) {
        if (!(cmd_param.tgt_bit_map & (1U << (pheader->tgt_desc[i].type)))) {
            continue; // 只传输bitmap中指定的target
        }

        // 分片传输target
        cmd_param.fw_type = (guchar)pheader->tgt_desc[i].type;
        cmd_param.tgt_len = pheader->tgt_desc[i].len;
        ret = update_fw_transport_tgt(read_fp, pheader->tgt_desc[i].offset, pheader->tgt_desc[i].len,
            &cmd_param, param);
        if (ret != RET_OK) {
            debug_log(DLOG_ERROR, "Transport some target failed. ret = %d", ret);
            return ret;
        }
    }
    return ret;
}

/*
 * Description : 发送升级固件到RAID
 */
LOCAL gint32 update_ctrl_firmware_send(SML_CTRL_UPGRADE_PARAM* param)
{
    RAIDADM_IMG_HEADER_INFO_S *pheader = (RAIDADM_IMG_HEADER_INFO_S *)g_malloc0(sizeof(RAIDADM_IMG_HEADER_INFO_S));
    if (pheader == NULL) {
        debug_log(DLOG_ERROR, "%s: g_malloc0 failed", __FUNCTION__);
        return RET_ERR;
    }

    (void)memset_s(pheader, sizeof(RAIDADM_IMG_HEADER_INFO_S), 0, sizeof(RAIDADM_IMG_HEADER_INFO_S));

    gchar *resolved_path = realpath(param->file_path, NULL);
    if (resolved_path == NULL) {
        g_free(pheader);
        return RET_ERR;
    }
    FILE *read_fp = fopen(resolved_path, "rb");
    if (read_fp == NULL) {
        g_free(pheader);
        debug_log(DLOG_ERROR, "open %s file fail!", resolved_path);
        g_free(resolved_path);
        return RET_ERR;
    }

    /* 检查文件合法性 */
    gint32 ret = update_fw_check_img(read_fp, &pheader, param);
    if (ret != RET_OK) {
        debug_log(DLOG_ERROR, "%s: check img file failed. ret = %d", __FUNCTION__, ret);
        (void)fclose(read_fp);
        g_free(pheader);
        g_free(resolved_path);
        return ret;
    }

    /* 分片传输升级文件到RAID */
    ret = transport_data_slice(param, pheader, read_fp);
    if (ret != RET_OK) {
        debug_log(DLOG_ERROR, "update_ctrl_firmware_send failed. ret = %d", ret);
    }
    (void)fclose(read_fp);
    g_free(pheader);
    g_free(resolved_path);
    return ret;
}

/*
 * Description : 执行升级RAID控制器的方法
 */
gint32 histore_upgrade_ctrl_process(guint32 ctrl_id, const gchar *file_path)
{
    gint32 ret;
    gint32 try_count;
    gint32 max_retry_count = 4; /* 失败最多重试次数 */

    SML_CTRL_UPGRADE_PARAM param = {0};
    param.controller_index = ctrl_id;
    errno_t securec_rv = strncpy_s(param.file_path, sizeof(param.file_path), file_path, strlen(file_path));
    if (securec_rv != RET_OK) {
        debug_log(DLOG_ERROR, "%s: strncpy_s failed, ret = %d", __FUNCTION__, securec_rv);
        return SML_ERR_SEC_FUNC_FAILED;
    }
    param.file_path[strlen(file_path)] = '\0';

    /* 发送升级固件到RAID，最多重试4次，raid */
    for (try_count = 0; try_count < max_retry_count; try_count++) {
        ret = update_ctrl_firmware_send(&param);
        if (ret == RET_OK) {
            debug_log(DLOG_ERROR, "update_ctrl_firmware_send successfully, try %d", try_count + 1);
            break;
        }
        debug_log(DLOG_ERROR, "update_ctrl_firmware_send failed, try %d, ret = %d", try_count + 1, ret);
    }

    if (ret != RET_OK) {
        return ret;
    }
    /* 激活升级，最多重试4次 */
    for (try_count = 0; try_count < max_retry_count; try_count++) {
        ret = histore_active_ctrl_upgrade(param.controller_index);
        if (ret == RET_OK) {
            debug_log(DLOG_ERROR, "histore_active_ctrl_upgrade successfully, try %d", try_count + 1);
            break;
        }
        debug_log(DLOG_ERROR, "histore_active_ctrl_upgrade failed, try %d, ret = 0x%04x", try_count + 1, ret);
    }

    if (ret != RET_OK) {
        return ret;
    }
    return ret;
}
