/* Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
 * openUBMC is licensed under 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 <dlfcn.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/time.h>
#include "platform.h"
#include "sml_errcodes.h"
#include "sml.h"
#include "sml_common.h"

// include LSI storelib header files start
#include "lsi/storelib.h"
#include "mfi.h"

#include "sl_misc.h"

/* 解决包含mpi2.h、mpi2_cnfg.h的编译问题 */
#define MPI2_POINTER *

#include "lsi/mpi2.h"
#include "lsi/mpi2_cnfg.h"
// include LSI storelib header files end

#include <errno.h>

/*
 * Description: 判断给定物理硬盘数是否能够创建指定级别的CacheCade逻辑盘
 * History: 2016年11月16日  ()  新生成函数
*/
gint32 IsValidRaidLevelForSSCD(guint8 raid_level, guint8 num_drives, const SML_CREATE_LD_CTRL_INFO_S *pCtrlInfo)
{
    gint32 valid = FALSE;

    if (NULL == pCtrlInfo) {
        return FALSE;
    }

    switch (raid_level) {
        case RAID_LEVEL_0:
            if (!pCtrlInfo->ssc_raid0_unsupported && (num_drives >= pCtrlInfo->min_pd_raid0) &&
                (num_drives <= pCtrlInfo->max_pd_raid0)) {
                valid = TRUE;
            }
            break;

        case RAID_LEVEL_1:
            if (pCtrlInfo->ssc_raid1_supported && (num_drives >= pCtrlInfo->min_pd_raid1) &&
                (num_drives <= pCtrlInfo->max_pd_raid1) && ((num_drives % 2) == 0)) {
                valid = TRUE;
            }
            break;

        case RAID_LEVEL_5:
            if (pCtrlInfo->ssc_raid5_supported && (num_drives >= pCtrlInfo->min_pd_raid5) &&
                (num_drives <= pCtrlInfo->max_pd_raid5)) {
                valid = TRUE;
            }
            break;

        default:
            break;
    }

    return valid;
}

/*
 * Description: 判断指定的RAID级别是否被控制器支持，并且选择的硬盘数是否满足级别要求
 * History: 2016年11月16日  ()  新生成函数
*/
gint32 IsValidRaidLevel(guint8 raid_level, guint8 num_drives, guint8 span_depth,
    const SML_CREATE_LD_CTRL_INFO_S *pCtrlInfo)
{
    gint32 valid = FALSE;
    guint16 total_drives = 0;

    if (NULL == pCtrlInfo) {
        return FALSE;
    }

    if (((raid_level == RAID_LEVEL_0) || (raid_level == RAID_LEVEL_1) || (raid_level == RAID_LEVEL_5) ||
        (raid_level == RAID_LEVEL_6)) &&
        (span_depth != 1)) {
        return FALSE;
    }
    // Raidçº§åˆ«10/50/60ä¸‹ç¡¬ç›˜ä¸ªæ•°ä¸?èƒ½å°‘äº?ä¸?
    if (((raid_level == RAID_LEVEL_10) || (raid_level == RAID_LEVEL_50) || (raid_level == RAID_LEVEL_60)) &&
        (span_depth < 2)) {
        return FALSE;
    }

    total_drives = num_drives * span_depth;

    switch (raid_level) {
        case RAID_LEVEL_0:
            if (pCtrlInfo->raid0_supported && (total_drives >= pCtrlInfo->min_pd_raid0) &&
                (total_drives <= pCtrlInfo->max_pd_raid0)) {
                valid = TRUE;
            }
            break;

        case RAID_LEVEL_1:
            if (pCtrlInfo->raid1_supported && (total_drives >= pCtrlInfo->min_pd_raid1) &&
                (total_drives <= pCtrlInfo->max_pd_raid1) && ((total_drives % 2) == 0)) {
                valid = TRUE;
            }
            break;

        case RAID_LEVEL_5:
            if (pCtrlInfo->raid5_supported && (total_drives >= pCtrlInfo->min_pd_raid5) &&
                (total_drives <= pCtrlInfo->max_pd_raid5)) {
                valid = TRUE;
            }
            break;

        case RAID_LEVEL_6:
            if (pCtrlInfo->raid6_supported && (total_drives >= pCtrlInfo->min_pd_raid6) &&
                (total_drives <= pCtrlInfo->max_pd_raid6)) {
                valid = TRUE;
            }
            break;

        case RAID_LEVEL_10:
            if (pCtrlInfo->raid10_supported && (num_drives >= pCtrlInfo->min_pd_raid1) &&
                (num_drives <= pCtrlInfo->max_pd_raid1) &&
                (total_drives >= pCtrlInfo->min_pd_raid10) && (total_drives <= pCtrlInfo->max_pd_raid10) &&
                ((total_drives % 2) == 0) && ((num_drives % 2) == 0)) {
                valid = TRUE;
            }
            break;

        case RAID_LEVEL_50:
            if (pCtrlInfo->raid50_supported && (num_drives >= pCtrlInfo->min_pd_raid5) &&
                (num_drives <= pCtrlInfo->max_pd_raid5) && (total_drives >= pCtrlInfo->min_pd_raid50) &&
                (total_drives <= pCtrlInfo->max_pd_raid50)) {
                valid = TRUE;
            }
            break;

        case RAID_LEVEL_60:
            if (pCtrlInfo->raid60_supported && (num_drives >= pCtrlInfo->min_pd_raid6) &&
                (num_drives <= pCtrlInfo->max_pd_raid6) && (total_drives >= pCtrlInfo->min_pd_raid60) &&
                (total_drives <= pCtrlInfo->max_pd_raid60)) {
                valid = TRUE;
            }
            break;

        default:
            break;
    }

    return valid;
}

/*
 * Description: 删除字符串前后的空格
 * History: 2016年4月8日   新生成函数
*/
void remove_string_space(gchar *src, guint32 src_length)
{
    errno_t safe_fun_ret = EOK;
    gchar *tmp_buf = NULL;
    guint32 start = 0;
    guint32 end = 0;

    if (src == NULL || src_length == 0) {
        return;
    }

    for (start = 0; start < src_length; start++) {
        if (src[start] == ' ') {
            continue;
        } else {
            break;
        }
    }

    if (start == src_length) {
        return;
    }

    for (end = src_length - 1; end > 0; end--) {
        if (src[end] == ' ' || src[end] == '\0') {
            continue;
        } else {
            break;
        }
    }

    if (end == 0) {
        return;
    }

    tmp_buf = (gchar *)g_malloc(src_length);
    if (tmp_buf == NULL) {
        return;
    }

    (void)memset_s(tmp_buf, src_length, 0, src_length);

    safe_fun_ret = strncpy_s(tmp_buf, src_length, src + start, end - start + 1);
    if (safe_fun_ret != EOK) {
        debug_log(DLOG_ERROR, "%s: strncpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
    }
    safe_fun_ret = strncpy_s(src, src_length, tmp_buf, src_length - 1);
    if (safe_fun_ret != EOK) {
        debug_log(DLOG_ERROR, "%s: strncpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
    }

    g_free(tmp_buf);
    return;
}

void swapBytes(const void *src, void *dest, guint32 len)
{
    errno_t safe_fun_ret = EOK;
    guint32 start, end;
    guint32 dest_size = 1;

    if (len == 0) {
        debug_log(DLOG_ERROR, "%s failed:input param error, len is 0.", __FUNCTION__);
        return;
    }
    if (src == NULL || dest == NULL) {
        return;
    }

    (void)memset_s(dest, len, 0, len);

    for (start = 0, end = len - 1; start < end; start++, end--) {
        safe_fun_ret = memcpy_s(((guint8 *)dest) + start, dest_size, ((const guint8 *)src) + end, 1);
        if (safe_fun_ret != EOK) {
            debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
            return;
        }
        safe_fun_ret = memcpy_s(((guint8 *)dest) + end, dest_size, ((const guint8 *)src) + start, 1);
        if (safe_fun_ret != EOK) {
            debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
            return;
        }
    }

    return;
}

/*
 * Description: 检查是否存在重复的pd id
 * History: 2019年7月17日   新生成函数
 *          2019年9月20日
 *          函数优化，可支持pd list和pd in ld list中的pd id查重。
*/
gint32 check_duplicate_pd_id(const guint16 *id, const gsize id_count, const gsize id_max_count)
{
    gsize i;
    guint8 *id_flag_array = NULL;
    guint16 current_id;

    if (id == NULL || id_count > id_max_count) {
        debug_log(DLOG_ERROR, "%s: invalid input.", __FUNCTION__);
        return SML_ERR_DATA_INVALID;
    }

    /* 分配0x10000个字节的空间，以id作为数组下标，可支持id为0~0xffff */
    id_flag_array = (guint8 *)g_malloc0(G_MAXUINT16 + 1);
    if (id_flag_array == NULL) {
        debug_log(DLOG_ERROR, "%s: g_malloc0 failed.", __FUNCTION__);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    for (i = 0; i < id_count; i++) {
        current_id = id[i];

        /* 当前id的标志位已被置位，说明id重复了 */
        if (id_flag_array[current_id] == 1) {
            debug_log(DLOG_DEBUG,
                "%s: deviceID[%" G_GSIZE_FORMAT "] = %d is not unique. Total count = %" G_GSIZE_FORMAT,
                __FUNCTION__, i, current_id, id_count);
            g_free(id_flag_array);
            return SML_ERR_DATA_INVALID;
        }

        /* 当前id的标志位未被置位，将其置位 */
        id_flag_array[current_id] = 1;
    }

    g_free(id_flag_array);
    return SML_SUCCESS;
}

 /*
  * Description: 检查是ld_list否存在重复的id
  */
gint32 check_duplicate_ld_id(const guint8 *id, const gsize id_count, const gsize id_max_count)
{
    gsize i;
    guint8 *id_flag_array = NULL;
    guint8 current_id;

    if (id == NULL || id_count > id_max_count) {
        debug_log(DLOG_ERROR, "%s: invalid input.", __FUNCTION__);
        return SML_ERR_DATA_INVALID;
    }

    /* 分配0x100个字节的空间，以id作为数组下标，可支持id为0~0xff */
    id_flag_array = (guint8 *)g_malloc0(G_MAXUINT8 + 1);
    if (id_flag_array == NULL) {
        debug_log(DLOG_ERROR, "%s: g_malloc0 failed.", __FUNCTION__);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    for (i = 0; i < id_count; i++) {
        current_id = id[i];

        /* 当前id的标志位已被置位，说明id重复了 */
        if (id_flag_array[current_id] == 1) {
            debug_log(DLOG_DEBUG,
                "%s: target ID[%"G_GSIZE_FORMAT"] = %d is not unique. Total count = %"G_GSIZE_FORMAT".",
                __FUNCTION__, i, current_id, id_count);
            g_free(id_flag_array);
            return SML_ERR_DATA_INVALID;
        }

        /* 当前id的标志位未被置位，将其置位 */
        id_flag_array[current_id] = 1;
    }

    g_free(id_flag_array);
    return SML_SUCCESS;
}

