/* 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 <math.h>
#include "platform.h"
#include "sml_errcodes.h"
#include "sml_public.h"
#include "sml_pd.h"
#include "sml_common.h"
#include "histore/tool_lib.h"
#include "histore/lib_api.h"
#include "hs_misc.h"
#include "hs_pd_sas_log.h"
#include "json_api.h"
#include "hs_pd.h"

#define G_GUINT64_HEX_FORMAT "lx"

static PD_VENDOR_ID_VENDOR_NAME_S g_vendor_id_2_vendor_name[] = {
    {PD_VENDOR_ID_INTEL_1,          PD_VENDOR_NAME_INTEL},
    {PD_VENDOR_ID_INTEL_2,          PD_VENDOR_NAME_INTEL},
    {PD_VENDOR_ID_SAMSUNG,          PD_VENDOR_NAME_SAMSUNG},
    {PD_VENDOR_ID_HUAWEI_1,         PD_VENDOR_NAME_HUAWEI},
    {PD_VENDOR_ID_HUAWEI_2,         PD_VENDOR_NAME_HUAWEI},
    {PD_VENDOR_ID_HUAWEI_3,         PD_VENDOR_NAME_HUAWEI},
    {PD_VENDOR_ID_SEAGATE,          PD_VENDOR_NAME_SEAGATE},
    {PD_VENDOR_ID_WDC,              PD_VENDOR_NAME_WDC},
    {PD_VENDOR_ID_HGST,             PD_VENDOR_NAME_HITACHI},
    {PD_VENDOR_ID_SANDISK,          PD_VENDOR_NAME_SANDISK},
    {PD_VENDOR_ID_TOSHIBA,          PD_VENDOR_NAME_TOSHIBA},
    {PD_VENDOR_ID_MICRON,           PD_VENDOR_NAME_MICRON},
    {PD_VENDOR_ID_LITE_ON,          PD_VENDOR_NAME_LITE_ON},
    {PD_VENDOR_ID_SMI,              PD_VENDOR_NAME_SMI},
    {PD_VENDOR_ID_PHISON,           PD_VENDOR_NAME_PHISON},
    {PD_VENDOR_ID_SSSTC,            PD_VENDOR_NAME_SSSTC},
    {PD_VENDOR_ID_HYNIX,            PD_VENDOR_NAME_HYNIX},
    {PD_VENDOR_ID_YANGTZE_MEMORY,   PD_VENDOR_NAME_YANGTZE_MEMORY},
    {PD_VENDOR_ID_RAMAXEL,          PD_VENDOR_NAME_RAMAXEL},
    {PD_VENDOR_ID_UMIS,             PD_VENDOR_NAME_UMIS},
    {PD_VENDOR_ID_UMIS_2,           PD_VENDOR_NAME_UMIS},
    {PD_VENDOR_ID_DERA,             PD_VENDOR_NAME_DERA},
    {PD_VENDOR_ID_AL,               PD_VENDOR_NAME_AL},
    {PD_VENDOR_ID_SAGE,             PD_VENDOR_NAME_SAGE},
    {PD_VENDOR_ID_HIKSEMI,          PD_VENDOR_NAME_HIKSEMI},
    {PD_VENDOR_ID_INSPUR,           PD_VENDOR_NAME_INSPUR},
    {PD_VENDOR_ID_INNOGRIT,         PD_VENDOR_NAME_INNOGRIT},
    {PD_VENDOR_ID_SOLIDIGM,         PD_VENDOR_NAME_SOLIDIGM},
    {PD_VENDOR_ID_DATSSD,           PD_VENDOR_NAME_DATSSD},
    {PD_VENDOR_ID_DAPUSTOR,         PD_VENDOR_NAME_DAPUSTOR}
};

static PD_VENDOR_NAME_ATTR_ID_S g_vendor_name_2_spare_block_id[] = {
    {PD_VENDOR_NAME_INTEL,     ATA_SMART_ATTRIBUTE_ID_AVAILABLE_RESERVED_SPACE},        // INTEL
    {PD_VENDOR_NAME_SAMSUNG,   ATA_SMART_ATTRIBUTE_ID_UNUSED_RSVD_BLK_CNT_TOTAL},       // SAMSUNG
    {PD_VENDOR_NAME_HUAWEI,     ATA_SMART_ATTRIBUTE_ID_AVAILABLE_RESERVED_SPACE},       // HUAWEI
    {NULL}                                                                              // 必须放在最后
};

static PD_VENDOR_NAME_ATTR_ID_S g_vendor_nand_written_attr_id[] = {
    {PD_VENDOR_NAME_INTEL,     ATA_SMART_ATTRIBUTE_ID_NAND_WRITTEN},                    // INTEL
    {PD_VENDOR_NAME_SAMSUNG,   ATA_SMART_ATTRIBUTE_ID_FLASH_WRITTEN_OP_COUNT},          // SAMSUNG
    {PD_VENDOR_NAME_HUAWEI,    ATA_SMART_ATTRIBUTE_ID_DRIVE_LIFETIME_REMAINNING},       // HUAWEI
    {NULL}                                                                              // 必须放在最后
};

static PD_VENDOR_NAME_ATTR_ID_S g_vendor_host_written_attr_id[] = {
    {PD_VENDOR_NAME_INTEL,     ATA_SMART_ATTRIBUTE_ID_TOTAL_LBAS_WRITTEN},              // INTEL
    {PD_VENDOR_NAME_SAMSUNG,   ATA_SMART_ATTRIBUTE_ID_TOTAL_LBAS_WRITTEN},              // SAMSUNG
    {PD_VENDOR_NAME_HUAWEI,    ATA_SMART_ATTRIBUTE_ID_TOTAL_LBAS_WRITTEN},              // HUAWEI
    {NULL}                                                                              // 必须放在最后
};

/* 存放从storage传过来的映射数据 */
DRIVE_VENDOR_INFO_EXTEND_S *drive_info_list_his = NULL;
size_t drive_info_list_his_len = 0;

static gint32 get_pd_list(guint8 ctrl_id, struct cmd_pds_id *pd_list)
{
    struct lib_cmd_param lib_param;
    (void)memset_s(&lib_param, sizeof(lib_param), 0, sizeof(lib_param));
    lib_param.opcode = ADM_RAID_READ;
    lib_param.subopcode = ADM_CMD_SHOW_PDS_ID;
    lib_param.card_id = ctrl_id;
    lib_param.channel = PCIE_PHYSICAL_FUCTION0;
    lib_param.data = pd_list;
    lib_param.data_len = (guint16)sizeof(struct cmd_pds_id);
    return process_histore_cmd(&lib_param);
}

gint32 histore_get_ctrl_pd_list(guint32 ctrl_id, gpointer data)
{
    if (data == NULL) {
        return SML_ERR_NULL_DATA;
    }
    struct cmd_pds_id pd_list;
    (void)memset_s(&pd_list, sizeof(pd_list), 0, sizeof(pd_list));
    gint32 ret = get_pd_list(ctrl_id, &pd_list);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_ERROR, "%s get_pd_list failed ret = %d", __FUNCTION__, ret);
        return ret;
    }

    SML_PD_LIST_S *pPDlist = (SML_PD_LIST_S *)data;

    pPDlist->pd_count = pd_list.num;
    debug_log(DLOG_DEBUG, "%s pd_list.num=%d", __FUNCTION__, pd_list.num);
    for (guint16 i = 0; i < pd_list.num; i++) {
        pPDlist->device_ids[i] = pd_list.ids[i].did;
        pPDlist->slot_num[i] = pd_list.ids[i].slot_id;
        pPDlist->enclosure_ids[i] = pd_list.ids[i].enc_id;
    }
    return SML_SUCCESS;
}

/*  Description: 将storelib定义的硬盘接口类型定义转换为华为自定义的接口类型
 * History: 2021年08月14日 新生成函数
 */
static guint8 get_pd_interface_type(guint8 interface)
{
    guint8 pd_intf_type;
    // 解析硬盘接口类型
    switch (interface) {
        case ADM_DEVICE_TYPE_SAS: // SAS 接口类型值为 1
            pd_intf_type = PD_INTERFACE_TYPE_SAS;
            break;
        case ADM_DEVICE_TYPE_SATA: // SATA 接口类型值为 8
            pd_intf_type = PD_INTERFACE_TYPE_SATA;
            break;
        default:
            pd_intf_type = PD_INTERFACE_TYPE_UNKNOWN;
            break;
    }

    return pd_intf_type;
}

/*
 * Description: 解析物理盘的最大支持速率和协商速率
 */
static guint8 parse_device_and_disk_max_speed(guint8 speed)
{
    guint8 link_rate;

    switch (speed) {
        case ADM_SAS_LINK_RATE_1_5: // 8 表示1.5Gb/s
            link_rate = PD_SPEED_1P5G;
            break;
        case ADM_SAS_LINK_RATE_3_0:  // 9 表示3.0Gb/s
            link_rate = PD_SPEED_3G;
            break;
        case ADM_SAS_LINK_RATE_6_0: // 10 表示6.0Gb/s
            link_rate = PD_SPEED_6G;
            break;
        case ADM_SAS_LINK_RATE_12_0: // 11 表示12.0Gb/s
            link_rate = PD_SPEED_12G;
            break;
        default: // no link
            link_rate = PD_SPEED_UNKNOWN;
    }
    return link_rate;
}

/* Description: 解析介质类型
 */
static guint8 parse_media_type(guint8 media_type)
{
    if (media_type == ADM_DISK_MEDIUM_TYPE_HDD) {  // 介质类型0为HDD
        return PD_MEDIA_TYPE_ROTATIONAL;
    }
    if (media_type == ADM_DISK_MEDIUM_TYPE_SSD) { // 介质类型1为SSD
        return PD_MEDIA_TYPE_SSD;
    }
    return PD_MEDIA_TYPE_UNKNOWN;
}

/*
 * Description: 为使各个厂商的RAID卡读取的PD电源状态统一，将MR_PD_POWER_STATE转
 *              换为SML定义的PD_POWER_STATE
*/
static guint8 get_pd_power_state(guint8 hibernated_status)
{
    guint8 pd_powerstate;
    // 硬盘休眠状态
    switch (hibernated_status) {
        case 0: //  spinup
            pd_powerstate = PD_POWER_STATE_ACTIVE;
            break;

        case 1: // spindown
            pd_powerstate = PD_POWER_STATE_STOP;
            break;
        default:
            pd_powerstate = PD_POWER_STATE_UNKNOWN;
            break;
    }

    return pd_powerstate;
}

static void get_pd_progress_info(SML_PD_INFO_S *pPDinfo, const struct cmd_show_disk *pd_info)
{
    pPDinfo->pdinfo.proginfo.rebuild_state = (pd_info->action) & BIT(0);
    if (pPDinfo->pdinfo.proginfo.rebuild_state) { // 重构
        pPDinfo->pdinfo.proginfo.rebuild_progress = pd_info->progress; // 0 - 100
    } else {
        pPDinfo->pdinfo.proginfo.rebuild_progress = 0;
    }
    pPDinfo->pdinfo.proginfo.patrol_state = ((pd_info->action) & BIT(1)) ? TRUE : FALSE;  // 0 -- 关闭， 1 -- 开启
    if (pPDinfo->pdinfo.proginfo.patrol_state) { // 巡检
        pPDinfo->pdinfo.proginfo.patrol_progress = pd_info->progress;
    } else {
        pPDinfo->pdinfo.proginfo.patrol_progress = 0;
    }

    return;
}

static void get_pd_rotation_rate(SML_PD_INFO_S *pPDinfo, const struct cmd_show_disk *pd_info)
{
    if (pd_info->rotation_rate != 0 && pd_info->rotation_rate != 1) { // 0表示未上报, 1表示非旋转介质
        pPDinfo->pdinfo.rotation_speed = pd_info->rotation_rate;
    } else {
        pPDinfo->pdinfo.rotation_speed = STORAGE_INFO_INVALID_WORD;  // 非HDD转速设置为无效值
    }
    return;
}

static void set_sata_smart_loc_value(guint16 device_id, struct cmd_scsi_passthrough *scsi_passthru_cmd)
{
    struct multi_disk_location disk_location = { 0 };
    disk_location.did = device_id;
    disk_location.flag = DISK_LOC_DID;

    errno_t ret = memcpy_s(&scsi_passthru_cmd->loc, sizeof(scsi_passthru_cmd->loc),
        &disk_location, sizeof(disk_location));
    if (ret != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s failed, ret = %d", __FUNCTION__, ret);
    }
    return;
}

/*
 * Description : 读取SATA的wwn，即厂商ID
*/
static gint32 get_sata_device_wwn(guint32 ctrl_id, guint16 device_id, guint32 *vendor_id)
{
    struct cmd_scsi_passthrough scsi_passthru_cmd = { 0 };

    set_sata_smart_loc_value(device_id, &scsi_passthru_cmd);
    scsi_passthru_cmd.lun = 0;
    scsi_passthru_cmd.cdb_len = SCSI_CDB_LENGTH16;
    scsi_passthru_cmd.cdb[0] = 0x85;    // cdb[0]:operation code;   0x85:PASS-THROUGH(16)指定操作码
    scsi_passthru_cmd.cdb[1] = 0x08;    // cdb[1]:protocol;         0x09:Non-data command - Device Reset
    scsi_passthru_cmd.cdb[2] = 0x0e;    // cdb[2]:transfer type;
                                        // 0x0e:The number of ATA logical sector size blocks to be transferred
    scsi_passthru_cmd.cdb[6] = 0x01;    // cdb[6]:count(7:0);       0x01:sector num
    scsi_passthru_cmd.cdb[14] = 0xec;   // cdb[14]:COMMAND;         0xec:defined command

    guint8 *data = (guint8 *)g_malloc0(ATA_SMART_DATA_LENGTH);
    if (data == NULL) {
        debug_log(DLOG_ERROR, "%s, g_malloc0 failed.", __FUNCTION__);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    gint32 retval = send_scsi_passthru_cmd(ctrl_id, &scsi_passthru_cmd, data, ATA_SMART_DATA_LENGTH);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_ERROR,
            "Get SATA Device SMART data by SCSI PASSTHRU failed, DeviceId = %u, CtrlId = %u, return 0x%04X",
            device_id, SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        g_free(data);
        return retval;
    }
    // 拼接厂商ID
    *vendor_id = (guint32)((data[217] & 0x0F) << 20) | // 217：取217byte的低四位，然后左移20位
                 (guint32)(data[216] << 12) |   // 216：216byte; 12:左移12位
                 (guint32)(data[219] << 4) |    // 219：219byte; 4:左移4位
                 (guint32)((data[218] >> 4) & 0x0F); // 218：取218byte； 4：右移取高四位
    g_free(data);
    return retval;
}

/*
 * Description: 根据厂商ID匹配厂商名
*/
static const gchar *get_pd_vendor_name(guint32 vendor_id)
{
    for (guint32 i = 0; i < (sizeof(g_vendor_id_2_vendor_name)) / (sizeof(g_vendor_id_2_vendor_name[0])); i++) {
        if (vendor_id == g_vendor_id_2_vendor_name[i].vendor_id) {
            return g_vendor_id_2_vendor_name[i].vendor_name;
        }
    }
    if (drive_info_list_his_len != 0 && drive_info_list_his != NULL) {
        for (guint32 i = 0; i < drive_info_list_his_len; i++) {
            if (vendor_id == drive_info_list_his[i].vendor_id) {
                return drive_info_list_his[i].vendor_name;
            }
        }
    }
    return PD_VENDOR_NAME_DEFAULT;
}

/*
 * Description: 判断获取的是否为华为自定义Smart信息
 * Note: 条件：当透传获取到page数据且Smart头信息Byte[5:10]为指定标识符
*/
static gboolean is_support_hw_defined_smart(guint32 ctrl_id, guint16 device_id, guint8 *data)
{
    guint32 front_half = MAKE_DWORD(0, 0, data[10], data[9]);
    guint32 back_half = MAKE_DWORD(data[8], data[7], data[6], data[5]);
    guint64 identifier = (((guint64)front_half << 32) | ((guint64)back_half));
    if (identifier == SATA_DEVICE_HW_DEFINED_SMART_IDENTIFIER) {
        debug_log(DLOG_INFO, "SATA Device supports HW Defined SMART data, DeviceId = %u, CtrlId = %u",
            device_id, SML_CTRL_ID_VALID_BIT(ctrl_id));
        return TRUE;
    }
    return FALSE;
}

/*
 * Description: 发送scsi协议，读取HW Defined Sata盘的SMART信息
 * Note: 函数内部申请内存, 成功时外部进行释放, 失败时内部释放
*/
static gint32 send_scsi_passthru_cmd_with_param(guint32 ctrl_id, guint16 device_id, guint8 **data,
    guint8 log_addr, guint8 sector_num)
{
    struct cmd_scsi_passthrough scsi_passthru_cmd = { 0 };
    guint16 data_len = sector_num * ATA_SMART_DATA_LENGTH;
    *data = (guint8 *)g_malloc0(data_len);
    if (*data == NULL) {
        debug_log(DLOG_ERROR, "%s, g_malloc0 failed.", __FUNCTION__);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }
    set_sata_smart_loc_value(device_id, &scsi_passthru_cmd);
    scsi_passthru_cmd.lun = 0;
    scsi_passthru_cmd.cdb_len = SCSI_CDB_LENGTH16;
    scsi_passthru_cmd.cdb[0] = 0x85;        // cdb[0]:operation code;   0x85:PASS-THROUGH(16)指定操作码
    scsi_passthru_cmd.cdb[1] = 0x09;        // cdb[1]:protocol;         0x09:PIO
    scsi_passthru_cmd.cdb[2] = 0x0e;        // cdb[2]:transfer type
                                            // 0x0e:The number of ATA logical sector size blocks to be transferred
    scsi_passthru_cmd.cdb[6] = sector_num;  // cdb[6]:count(7:0):sector num;
    scsi_passthru_cmd.cdb[8] = log_addr;    // cdb[8]:LBA(7:0):Log Address;
    scsi_passthru_cmd.cdb[13] = 0xa0;       // cdb[13]:DEVICE;          0xa0:Obsolete
    scsi_passthru_cmd.cdb[14] = 0x2f;       // cdb[14]:COMMAND;         0x2f:pio command

    gint32 ret = send_scsi_passthru_cmd(ctrl_id, &scsi_passthru_cmd, *data, data_len);
    if (ret != SML_SUCCESS) {
        sleep(1);   // 等待1s后重试
        ret = send_scsi_passthru_cmd(ctrl_id, &scsi_passthru_cmd, *data, data_len);
        if (ret != SML_SUCCESS) {
            debug_log(DLOG_ERROR, "SATA Device get log page: 0x%2X fail, DeviceId = %u, CtrlId = %u",
                log_addr, device_id, SML_CTRL_ID_VALID_BIT(ctrl_id));
            g_free(*data);
            *data = NULL;
            return SML_ERR_CTRL_TOO_BUSY_TO_RESP_OOB;
        }
    }
    return SML_SUCCESS;
}

/*
 * 获取log page 0x00, 检查0xCF对应位置的page页长度, 明确是否支持0xCF
 * Note: 介质部明确0x00 page一定存在
 *      1、当0x00 page页请求失败, 不设置标志位, 允许继续探测, 即support_page_cf_flag = 0;
 *      2、当Word[0xCF] page页数为0时, 说明该盘不支持0xCF, 设置标志位x0x01, 不允许继续探测;
 *      3、当page页数不为0时, 说明该盘支持0xCF, 设置标志位为SUPPORT_PAGE_CF_FLAG, 不用继续探测;
*/
static void check_device_support_page_cf(guint32 ctrl_id, guint16 device_id, guint8 *sector_num,
    guint8 *support_page_cf_flag)
{
#define CF_LOG_PAGE_NUM 414     // page 0xCF支持的sector个数的固定位置
    guint8 *data = NULL;
    // 获取page 0x00的CDB的命令字:85 09 0e 00 00 00 01(sector_num) 00 00(log_addr) 00 00 00 00 a0 2f 00
    gint32 ret = send_scsi_passthru_cmd_with_param(ctrl_id, device_id, &data, 0x00, 0x01);
    if (ret != SML_SUCCESS) {
        return;   // 当0x00 page页请求失败, 不设置标志位, 允许继续探测
    }
    guint8 sectors = data[CF_LOG_PAGE_NUM];
    g_free(data);
    if (sectors == 0) {     // 当page页数为0时，说明该盘不支持0xCF
        debug_log(DLOG_INFO, "SATA Device does not support page 0xCF, DeviceId = %u, CtrlId = %u",
            device_id, SML_CTRL_ID_VALID_BIT(ctrl_id));
        *support_page_cf_flag = UNSUPPORT_PAGE_CF_FLAG;    // 已经明确不支持0xCF, 不用重复探测
        return;
    }
    *support_page_cf_flag = SUPPORT_PAGE_CF_FLAG;
    *sector_num = sectors;
}

/*
 * 获取log page 0xCF, 明确是否支持华为自定义Smart
*/
static void check_page_cf_support_hw_defined_smart(guint32 ctrl_id, guint16 device_id,
    SML_PD_HW_DEFINED_SMART_INFO_S *hw_smart_info)
{
    guint8 *data = NULL;
    // 获取0xcf的CDB的命令字:85 09 0e 00 00 00 05(sector_num) 00 cf(log_addr) 00 00 00 00 a0 2f 00
    gint32 ret = send_scsi_passthru_cmd_with_param(ctrl_id, device_id, &data, 0xCF, hw_smart_info->sector_num);
    if (ret != SML_SUCCESS) {
        hw_smart_info->support_flag = 0;
        return;
    }
    if (!is_support_hw_defined_smart(ctrl_id, device_id, data)) {
        hw_smart_info->support_flag = UNSUPPORT_HUAWEI_DEFINED_SMART;
        g_free(data);
        debug_log(DLOG_INFO, "SATA Device does not support HW Defined SMART data, DeviceId = %u, CtrlId = %u",
            device_id, SML_CTRL_ID_VALID_BIT(ctrl_id));
        return;
    }
    hw_smart_info->support_flag = SUPPORT_HUAWEI_DEFINED_SMART;
    g_free(data);
}

static gint32 check_device_support_hw_defined_smart(guint32 ctrl_id, guint16 device_id,
    SML_PD_HW_DEFINED_SMART_INFO_S *hw_smart_info)
{
    if (hw_smart_info->support_flag != 0) {
        return hw_smart_info->support_flag;
    }

    for (guint8 i = 0; i < 3; i++) {    // BMC起来后连续重试3次, 之后不再探测
        // 请求page0x00, 探测是否支持page 0xCF, 并记录sector_num, 成功后不再探测。
        if (hw_smart_info->support_page_cf_flag == 0) {   // 初次探测
            check_device_support_page_cf(ctrl_id, device_id, &hw_smart_info->sector_num,
                &hw_smart_info->support_page_cf_flag);
            if (hw_smart_info->support_page_cf_flag == 0) {    // 上次请求0x00 page页失败
                continue;   // 如果连续三次请求0x00失败, 未能达到判别目的, 允许下次继续探测
                            // 该场景只有当RAID卡或盘异常时出现, 与其他直通命令处理策略保持一致
            }
        }
        debug_log(DLOG_INFO, "Device support page cf flag: %d", hw_smart_info->support_page_cf_flag);
        if (hw_smart_info->support_page_cf_flag != SUPPORT_PAGE_CF_FLAG) { // 不支持0xCF直接退出
            hw_smart_info->support_flag = UNSUPPORT_HUAWEI_DEFINED_SMART;
            break;
        }
        check_page_cf_support_hw_defined_smart(ctrl_id, device_id, hw_smart_info); // 请求page 0xCF, 判断是否支持华为自定义
        debug_log(DLOG_INFO, "Device support HW Defined Smart support_flag: %d", hw_smart_info->support_flag);
        if (hw_smart_info->support_flag == 0) { // 上次请求0xCF page页失败
            hw_smart_info->support_flag = UNSUPPORT_HUAWEI_DEFINED_SMART;
            continue;
        }
        break;
    }

    return hw_smart_info->support_flag;
}

/*
 * Description: 发送scsi协议，读取Sata盘的华为自定义SMART信息
*/
static gint32 get_sata_device_hw_defined_smart_data(guint32 ctrl_id, guint16 device_id,
    SML_PD_HW_DEFINED_SMART_INFO_S *hw_smart_info)
{
    if (check_device_support_hw_defined_smart(ctrl_id, device_id, hw_smart_info) != SUPPORT_HUAWEI_DEFINED_SMART) {
        return SML_ERR_PD_LOG_PAGE_UNSUPPORT;
    }
    // 获取华为自定义
    guint8 *data = NULL;
    gint32 ret = send_scsi_passthru_cmd_with_param(ctrl_id, device_id, &data, 0xCF, hw_smart_info->sector_num);
    if (ret != SML_SUCCESS) {
        return ret;
    }
    guint16 smart_data_len = hw_smart_info->sector_num * ATA_SMART_DATA_LENGTH;
    ret = memcpy_s(hw_smart_info->smart_data, ATA_HW_DEFINED_SMART_DATA_LENGTH, data, smart_data_len);
    if (ret != RET_OK) {
        debug_log(DLOG_ERROR, "memcpy_s failed, ret: %d", ret);
    }
    g_free(data);
    return ret;
}

/*
 * Description: 从厂商自定义Smart信息中获取SAS接口SSD硬盘的磨损情况
*/
static void get_pd_wearout_by_pd_info(SML_PD_INFO_S *pPDinfo, struct cmd_show_disk *pd_info)
{
#define REMNANT_ONE_HUNDRED 100
    if (pd_info->wearout <= REMNANT_ONE_HUNDRED) {
        pPDinfo->pdinfo.remnant_media_wearout = pd_info->wearout;
    }
}

/*
 * Description: 从华为自定义Smart信息中获取SATA接口SSD硬盘的磨损情况, 即被擦写次数的剩余百分比，
 *              百分比从100到1的线性下降就相当于平均擦写次数从0到最大值
*/
static void get_pd_wearout_by_hw_defined(SML_PD_INFO_S *pPDinfo)
{
    guint8 media_wearout = STORAGE_INFO_INVALID_BYTE;
    guint8 slc_wearout_val = STORAGE_INFO_INVALID_BYTE;
    guint8 tlc_wearout_val = STORAGE_INFO_INVALID_BYTE;
    guint8 slc_wearout_spare_val = STORAGE_INFO_INVALID_BYTE;
    guint8 tlc_wearout_spare_val = STORAGE_INFO_INVALID_BYTE;
    ATA_SMART_DATA_HW_DEFINED_S *smart_data =
        (ATA_SMART_DATA_HW_DEFINED_S *)pPDinfo->hw_defined_smartinfo.smart_data;
    guint16 attr_len = G_N_ELEMENTS(smart_data->smartAttribute);
    for (guint16 idx = 0; idx < attr_len; idx++) {
        ATA_SMART_ATTRIBUTE_S *smart_attr = &(smart_data->smartAttribute[idx]);
        if (smart_attr->id == HW_DEFINED_SMART_ATTRIBUTE_ID_SLC_WEAROUT) {
            slc_wearout_val = smart_attr->raw[0];
            debug_log(DLOG_INFO, "SATA SLC Remnant Media WearOut raw[0] = %u", smart_attr->raw[0]);
        }
        if (smart_attr->id == HW_DEFINED_SMART_ATTRIBUTE_ID_TLC_WEAROUT) {
            tlc_wearout_val = smart_attr->raw[0];
            debug_log(DLOG_INFO, "SATA TLC Remnant Media WearOut raw[0] = %u", smart_attr->raw[0]);
        }
        // 支持从0x4E,0x4F获取静态寿命，由于不能保证id的排序，获取到0x4E,0x4F后不停止遍历
        if (smart_attr->id == HW_DEFINED_SMART_ATTRIBUTE_ID_SLC_LIFESPAN) {
            slc_wearout_spare_val = smart_attr->current;
            debug_log(DLOG_INFO, "SATA SLC Remnant Media WearOut current = %u", smart_attr->current);
        }
        if (smart_attr->id == HW_DEFINED_SMART_ATTRIBUTE_ID_TLC_LIFESPAN) {
            tlc_wearout_spare_val = smart_attr->current;
            debug_log(DLOG_INFO, "SATA TLC Remnant Media WearOut current = %u", smart_attr->current);
        }
        if (slc_wearout_val != STORAGE_INFO_INVALID_BYTE && tlc_wearout_val != STORAGE_INFO_INVALID_BYTE) {
            break;  // 当都已经匹配到的时候直接退出, 不在遍历后边的smart项
        }
    }

    if (slc_wearout_spare_val != STORAGE_INFO_INVALID_BYTE || tlc_wearout_spare_val != STORAGE_INFO_INVALID_BYTE) {
        media_wearout = slc_wearout_spare_val > tlc_wearout_spare_val ? tlc_wearout_spare_val : slc_wearout_spare_val;
    }
    // 优先采用0x5C和0x69的数据
    if (slc_wearout_val != STORAGE_INFO_INVALID_BYTE || tlc_wearout_val != STORAGE_INFO_INVALID_BYTE) {
        media_wearout = slc_wearout_val > tlc_wearout_val ? tlc_wearout_val : slc_wearout_val;
    }

    pPDinfo->pdinfo.remnant_media_wearout = media_wearout;
}

/*
 * Description: 获取SSD硬盘的磨损情况
 * Note: 当SSD SATA硬盘支持华为自定义Smart时，优先使用自定义Smart信息获取剩余磨损率
         当不支持华为自定义时，从1880raid卡中获取的pdinfo中提取磨损情况
*/
static void get_pd_wearout_info(SML_PD_INFO_S *pPDInfo, struct cmd_show_disk *pd_info)
{
    pPDInfo->pdinfo.remnant_media_wearout = STORAGE_INFO_INVALID_BYTE;  // 设置为无效值0xFF
 
    if (pd_info->media_type == ADM_DISK_MEDIUM_TYPE_SSD) {
        if (pPDInfo->pdinfo.interface_type == PD_INTERFACE_TYPE_SATA &&
            pPDInfo->hw_defined_smartinfo.valid_flag == TRUE) {
            get_pd_wearout_by_hw_defined(pPDInfo);
        } else {
            get_pd_wearout_by_pd_info(pPDInfo, pd_info);
        }
    }
}

/*
 * Description: 从Smart信息中获取指定项的current值
*/
static guint8 get_smart_attr_by_attr_id(ATA_SMART_DATA_S *smart_data, guint8 attr_id)
{
    guint8 attr_value = STORAGE_INFO_INVALID_BYTE;
    ATA_SMART_ATTRIBUTE_S *smart_attr = NULL;
    guint8 attr_len = G_N_ELEMENTS(smart_data->smartAttribute);
    for (guint8 idx = 0; idx < attr_len; idx++) {
        smart_attr = &(smart_data->smartAttribute[idx]);
        if (smart_attr->id == attr_id) {
            attr_value = smart_attr->current;
        }
    }
    return attr_value;
}

/*
 * Description: 从厂商自定义Smart信息中获取用户区的有效冗余块情况
*/
static guint8 get_sata_spare_block_by_vendor(SML_PD_INFO_S *pPDInfo)
{
    guint8 tlc_spare_block = STORAGE_INFO_INVALID_BYTE; // 0xFF indicates not support
    guint8 spare_block_attr_id;
    ATA_SMART_DATA_S *smart_data = (ATA_SMART_DATA_S *)pPDInfo->smartinfo.SATADevice.smart_data;

    for (guint8 idx = 0; g_vendor_name_2_spare_block_id[idx].vendor_name != NULL; idx++) {
        if (strncasecmp(pPDInfo->pdinfo.manufacturer, g_vendor_name_2_spare_block_id[idx].vendor_name,
            strlen(g_vendor_name_2_spare_block_id[idx].vendor_name))  == 0 ||
            strstr(pPDInfo->pdinfo.manufacturer, g_vendor_name_2_spare_block_id[idx].vendor_name) != NULL ||
            strncasecmp(pPDInfo->pdinfo.model, g_vendor_name_2_spare_block_id[idx].vendor_name,
            strlen(g_vendor_name_2_spare_block_id[idx].vendor_name))  == 0 ||
            strstr(pPDInfo->pdinfo.model, g_vendor_name_2_spare_block_id[idx].vendor_name) != NULL) {
            spare_block_attr_id = g_vendor_name_2_spare_block_id[idx].attr_id;
            tlc_spare_block = get_smart_attr_by_attr_id(smart_data, spare_block_attr_id);
            break;
        }
    }
    return tlc_spare_block;
}

/*
 * Description: 从华为自定义Smart信息中获取非用户区的有效冗余块情况
*/
static guint8 get_sata_spare_block_by_hw_defined(guint8 valid_id, guint8 total_id, SML_PD_INFO_S *pPDInfo)
{
    guint8 spare_block_percent = STORAGE_INFO_INVALID_BYTE;
    guint32 valid_spare_block = STORAGE_INFO_INVALID_DWORD;
    guint32 total_spare_block = STORAGE_INFO_INVALID_DWORD;
    ATA_SMART_DATA_HW_DEFINED_S *smart_data =
        (ATA_SMART_DATA_HW_DEFINED_S *)pPDInfo->hw_defined_smartinfo.smart_data;
    guint16 attr_len = G_N_ELEMENTS(smart_data->smartAttribute);
    for (guint16 idx = 0; idx < attr_len; idx++) {
        ATA_SMART_ATTRIBUTE_S *smart_attr = &(smart_data->smartAttribute[idx]);
        if (smart_attr->id == valid_id) {
            valid_spare_block = MAKE_DWORD(0, 0, smart_attr->raw[1], smart_attr->raw[0]);
        }
        if (smart_attr->id == total_id) {
            total_spare_block = MAKE_DWORD(0, 0, smart_attr->raw[1], smart_attr->raw[0]);
        }
        if (valid_spare_block != STORAGE_INFO_INVALID_DWORD && total_spare_block != STORAGE_INFO_INVALID_DWORD) {
            break;  // 当都已经匹配到的时候直接退出, 不在遍历后边的smart项
        }
    }

    if (valid_spare_block != STORAGE_INFO_INVALID_DWORD && total_spare_block != STORAGE_INFO_INVALID_DWORD &&
        total_spare_block != 0) {
        spare_block_percent = (valid_spare_block * 100) / total_spare_block; // 100: 转换为百分比
    }
    return spare_block_percent;
}

/*
 * Description: 获取SATA接口硬盘的有效冗余块情况
 * Note: 当硬盘支持华为自定义Smart时，优先使用自定义Smart信息获取用户区和非用户的有效冗余块
         当不支持华为自定义时，从厂商自定义Smart信息中各spare block的smart_id获取
*/
static void get_sata_spare_block(SML_PD_INFO_S *pPDInfo)
{
    guint8 slc_spare_block = STORAGE_INFO_INVALID_BYTE;
    guint8 tlc_spare_block = STORAGE_INFO_INVALID_BYTE;

    if (pPDInfo->hw_defined_smartinfo.valid_flag == TRUE) {
        slc_spare_block = get_sata_spare_block_by_hw_defined(HW_DEFINED_SMART_ATTRIBUTE_ID_SLC_VALID_SPARE_BLOCK,
            HW_DEFINED_SMART_ATTRIBUTE_ID_SLC_TOTAL_SPARE_BLOCK, pPDInfo);
        tlc_spare_block = get_sata_spare_block_by_hw_defined(HW_DEFINED_SMART_ATTRIBUTE_ID_TLC_VALID_SPARE_BLOCK,
            HW_DEFINED_SMART_ATTRIBUTE_ID_TLC_TOTAL_SPARE_BLOCK, pPDInfo);
        debug_log(DLOG_INFO, "Smart from HW defined, SLC spare block percent = %u, TLC spare block percent = %u",
            slc_spare_block, tlc_spare_block);
    } else if (pPDInfo->smartinfo.valid_flag == TRUE) {
        // 由于厂商自定义的Smart信息只有用户区冗余块剩余比例，故非用户区的直接赋值无效值
        tlc_spare_block = get_sata_spare_block_by_vendor(pPDInfo);
        debug_log(DLOG_INFO, "Smart from vendor, TLC spare block percent = %u", tlc_spare_block);
    }

    pPDInfo->pdinfo.spare_block.slc_value = slc_spare_block;
    pPDInfo->pdinfo.spare_block.tlc_value = tlc_spare_block;
}

/*
 * Description: 获取SSD硬盘的有效冗余块信息
*/
static void get_ssd_spare_block_info(SML_PD_INFO_S *pPDInfo)
{
    pPDInfo->pdinfo.spare_block.slc_value = STORAGE_INFO_INVALID_BYTE;
    pPDInfo->pdinfo.spare_block.tlc_value = STORAGE_INFO_INVALID_BYTE;

    if (pPDInfo->pdinfo.media_type == ADM_DISK_MEDIUM_TYPE_SSD) {
        if (pPDInfo->pdinfo.interface_type == PD_INTERFACE_TYPE_SATA) {
            // SATA SSD盘
            get_sata_spare_block(pPDInfo);
        }
    }
}

/*
 * Description: 更新硬盘的有效冗余块情况，间隔24h一次
*/
static void get_pd_spare_block_info(SML_PD_INFO_S *pPDinfo)
{
    guint32 cur_timestamp = (guint32)vos_tick_get();
    guint32 interval;

    if (cur_timestamp >= pPDinfo->pdinfo.spare_block.last_update_timestamp) {
        interval = cur_timestamp - pPDinfo->pdinfo.spare_block.last_update_timestamp;
    } else {
        interval = cur_timestamp + (G_MAXUINT32 - pPDinfo->pdinfo.spare_block.last_update_timestamp);
    }
    // 24小时更新一次
    if (interval > UPDATE_INTERVAL_24_HOURS || pPDinfo->pdinfo.spare_block.last_update_timestamp == 0 ||
        pPDinfo->pdinfo.spare_block.slc_value == 0 || pPDinfo->pdinfo.spare_block.tlc_value == 0) {
        get_ssd_spare_block_info(pPDinfo);
        pPDinfo->pdinfo.spare_block.last_update_timestamp = cur_timestamp;
    }
}

/*
 * Description: 从厂商自定义Smart信息中获取指定项的Raw值
*/
static guint64 get_vendor_smart_raw_by_attr_id(SML_PD_INFO_S *pPDInfo, guint8 attr_id)
{
    guint64 attr_raw_val = STORAGE_INFO_INVALID_DWORD; // indicates not support
    ATA_SMART_DATA_S *smart_data = (ATA_SMART_DATA_S *)pPDInfo->smartinfo.SATADevice.smart_data;

    guint8 attr_len = G_N_ELEMENTS(smart_data->smartAttribute);
    ATA_SMART_ATTRIBUTE_S *smart_attr;

    for (guint8 idx = 0; idx < attr_len; idx++) {
        smart_attr = &(smart_data->smartAttribute[idx]);
        if (smart_attr->id == attr_id) {
            // Smart信息中的RAW值为6个bytes, 一次全部捞取, 高两个bytes需要填充0。在使用的时候进行截断操作。
            guint32 raw_h = MAKE_DWORD(0, 0, smart_attr->raw[5], smart_attr->raw[4]);   // 取raw值的第4、5个byte
            // 取raw值的第0、1、2、3 bytes进行拼接
            guint32 raw_l = MAKE_DWORD(smart_attr->raw[3], smart_attr->raw[2], smart_attr->raw[1], smart_attr->raw[0]);
            attr_raw_val = (((guint64)raw_h << 32) | ((guint64)raw_l)); // 右移32位
            break;
        }
    }

    return attr_raw_val;
}

/*
 * Description: 从厂商自定义Smart信息中获取SATA接口SSD硬盘的磨损情况
*/
static guint64 get_sata_nand_flash_written_by_vendor(SML_PD_INFO_S *pPDInfo)
{
    guint64 nand_written = STORAGE_INFO_INVALID_QWORD; // indicates not support
    guint8 attr_id;

    for (guint8 idx = 0; g_vendor_nand_written_attr_id[idx].vendor_name != NULL; idx++) {
        if (strncasecmp(pPDInfo->pdinfo.manufacturer, g_vendor_nand_written_attr_id[idx].vendor_name,
            strlen(g_vendor_nand_written_attr_id[idx].vendor_name)) == 0 ||
            strstr(pPDInfo->pdinfo.manufacturer, g_vendor_nand_written_attr_id[idx].vendor_name) != NULL ||
            strncasecmp(pPDInfo->pdinfo.model, g_vendor_nand_written_attr_id[idx].vendor_name,
            strlen(g_vendor_nand_written_attr_id[idx].vendor_name)) == 0  ||
            strstr(pPDInfo->pdinfo.model, g_vendor_nand_written_attr_id[idx].vendor_name) != NULL) {
            attr_id = g_vendor_nand_written_attr_id[idx].attr_id;
            nand_written = get_vendor_smart_raw_by_attr_id(pPDInfo, attr_id);
            break;
        }
    }

    return nand_written;
}

/*
 * Description: 从厂商自定义Smart信息中获取SATA接口SSD硬盘的磨损情况
*/
static guint64 get_sata_host_written_by_vendor(SML_PD_INFO_S *pPDInfo)
{
    guint64 host_written = STORAGE_INFO_INVALID_QWORD; // indicates not support
    guint8 attr_id;

    for (guint8 idx = 0; g_vendor_host_written_attr_id[idx].vendor_name != NULL; idx++) {
        if (strncasecmp(pPDInfo->pdinfo.manufacturer, g_vendor_host_written_attr_id[idx].vendor_name,
            strlen(g_vendor_host_written_attr_id[idx].vendor_name)) == 0 ||
            strstr(pPDInfo->pdinfo.manufacturer, g_vendor_host_written_attr_id[idx].vendor_name) != NULL ||
            strncasecmp(pPDInfo->pdinfo.model, g_vendor_host_written_attr_id[idx].vendor_name,
            strlen(g_vendor_host_written_attr_id[idx].vendor_name)) == 0  ||
            strstr(pPDInfo->pdinfo.model, g_vendor_host_written_attr_id[idx].vendor_name) != NULL) {
            attr_id = g_vendor_host_written_attr_id[idx].attr_id;
            host_written = get_vendor_smart_raw_by_attr_id(pPDInfo, attr_id);
            break;
        }
    }

    return host_written;
}

/*
 * Description: 从华为自定义Smart信息中获取指定的ID的RAW值
*/
static guint64 get_hw_defined_smart_raw_by_attr_id(SML_PD_INFO_S *pPDInfo, guint8 attr_id)
{
    guint64 attr_raw_val = STORAGE_INFO_INVALID_QWORD;
    ATA_SMART_DATA_HW_DEFINED_S *smart_data =
        (ATA_SMART_DATA_HW_DEFINED_S *)pPDInfo->hw_defined_smartinfo.smart_data;
    guint16 attr_len = G_N_ELEMENTS(smart_data->smartAttribute);
    for (guint16 idx = 0; idx < attr_len; idx++) {
        ATA_SMART_ATTRIBUTE_S *attr = &(smart_data->smartAttribute[idx]);
        if (attr->id == attr_id) {
            // Smart信息中的RAW值为6个bytes, 一次全部捞取, 高两个bytes需要填充0。在使用的时候进行截断操作。
            guint32 raw_high = MAKE_DWORD(0, 0, attr->raw[5], attr->raw[4]);    // 取raw值的第4、5个byte
            // 取raw值的第0、1、2、3 bytes进行拼接
            guint32 raw_low = MAKE_DWORD(attr->raw[3], attr->raw[2], attr->raw[1], attr->raw[0]);
            attr_raw_val = (((guint64)raw_high << 32) | ((guint64)raw_low));    // 右移32位
            break;
        }
    }
    return attr_raw_val;
}

static gboolean check_manufacture_statisfied_top3(gchar *manufacture)
{
    if (strncasecmp(manufacture, PD_VENDOR_NAME_INTEL, strlen(PD_VENDOR_NAME_INTEL)) == 0 ||
        strncasecmp(manufacture, PD_VENDOR_NAME_SAMSUNG, strlen(PD_VENDOR_NAME_SAMSUNG)) == 0 ||
        strncasecmp(manufacture, PD_VENDOR_NAME_HUAWEI, strlen(PD_VENDOR_NAME_HUAWEI)) == 0) {
        return TRUE;
    }
    return FALSE;
}

/*
 * Description: 获取SATA接口硬盘的预估剩余寿命情况
*/
static void get_sata_est_lifespan(SML_PD_INFO_S *pPDInfo)
{
    if (pPDInfo->hw_defined_smartinfo.valid_flag == TRUE) {
        pPDInfo->pdinfo.estimated_lifespan.hw_defined.valid_flag = TRUE;
        pPDInfo->pdinfo.estimated_lifespan.hw_defined.slc_poh = pPDInfo->pdinfo.power_on_hours;
        pPDInfo->pdinfo.estimated_lifespan.hw_defined.tlc_poh = pPDInfo->pdinfo.power_on_hours;
        pPDInfo->pdinfo.estimated_lifespan.hw_defined.slc_pe_cycle =(guint32)(0xFFFFFFFF &
            get_hw_defined_smart_raw_by_attr_id(pPDInfo, HW_DEFINED_SMART_ATTRIBUTE_ID_SLC_PE_CYCLE));
        pPDInfo->pdinfo.estimated_lifespan.hw_defined.tlc_pe_cycle = (guint32)(0xFFFFFFFF &
            get_hw_defined_smart_raw_by_attr_id(pPDInfo, HW_DEFINED_SMART_ATTRIBUTE_ID_TLC_PE_CYCLE));
        pPDInfo->pdinfo.estimated_lifespan.hw_defined.slc_avg_ec = (guint32)(0xFFFFFFFF & (  // 右移32位
            get_hw_defined_smart_raw_by_attr_id(pPDInfo, HW_DEFINED_SMART_ATTRIBUTE_ID_SLC_ERASE_COUNT) >> 32));
        pPDInfo->pdinfo.estimated_lifespan.hw_defined.tlc_avg_ec = (guint32)(0xFFFFFFFF & (  // 右移32位
            get_hw_defined_smart_raw_by_attr_id(pPDInfo, HW_DEFINED_SMART_ATTRIBUTE_ID_TLC_ERASE_COUNT) >> 32));
        pPDInfo->pdinfo.estimated_lifespan.hw_defined.tlc_used_lifespan = (guint32)(0xFFFFFFFF &
            get_hw_defined_smart_raw_by_attr_id(pPDInfo, HW_DEFINED_SMART_ATTRIBUTE_ID_TLC_LIFESPAN));
        pPDInfo->pdinfo.estimated_lifespan.hw_defined.slc_used_lifespan = (guint32)(0xFFFFFFFF &
            get_hw_defined_smart_raw_by_attr_id(pPDInfo, HW_DEFINED_SMART_ATTRIBUTE_ID_SLC_LIFESPAN));
        // 大于等于30天, update_support_flag为True表明支持计算利用当前值计算剩余寿命
        if (pPDInfo->pdinfo.power_on_hours >= POWER_ON_HOURS_LIMIT_30_DAYS) {
            pPDInfo->pdinfo.estimated_lifespan.update_support_flag = TRUE;
        }
    } else if (pPDInfo->smartinfo.valid_flag == TRUE) {
        // 记录当前的累计上电时长和剩余磨损率
        if (check_manufacture_statisfied_top3(pPDInfo->pdinfo.manufacturer) == FALSE) {
            return;
        }
        pPDInfo->pdinfo.estimated_lifespan.vendor.valid_flag = TRUE;
        pPDInfo->pdinfo.estimated_lifespan.vendor.power_on_hours = pPDInfo->pdinfo.power_on_hours;
        pPDInfo->pdinfo.estimated_lifespan.vendor.remn_wearout = pPDInfo->pdinfo.remnant_media_wearout;
        if (pPDInfo->pdinfo.power_on_hours >= POWER_ON_HOURS_LIMIT_30_DAYS) {
            pPDInfo->pdinfo.estimated_lifespan.update_support_flag = TRUE;
        }
    }
}

/*
 * Description: 获取SSD硬盘的预估剩余寿命信息
*/
static void get_ssd_est_remaining_lifespan(SML_PD_INFO_S *pPDInfo)
{
    pPDInfo->pdinfo.estimated_lifespan.update_support_flag = FALSE;

    if (pPDInfo->pdinfo.media_type == ADM_DISK_MEDIUM_TYPE_SSD) {
        if (pPDInfo->pdinfo.interface_type == PD_INTERFACE_TYPE_SATA) {
            // SATA SSD盘
            get_sata_est_lifespan(pPDInfo);
        }
    }
}

/*
 * Description: 获取SATA接口硬盘的预估剩余寿命情况
*/
static void get_sata_write_amplification(SML_PD_INFO_S *pPDInfo)
{
    if (pPDInfo->hw_defined_smartinfo.valid_flag == TRUE) {
        pPDInfo->pdinfo.write_amp.hw_defined.valid_flag = TRUE;
        pPDInfo->pdinfo.write_amp.hw_defined.nand_write_l =
            get_hw_defined_smart_raw_by_attr_id(pPDInfo, HW_DEFINED_SMART_ATTRIBUTE_ID_TLC_NAND_WRITTEN_L);
        pPDInfo->pdinfo.write_amp.hw_defined.nand_write_h =
            get_hw_defined_smart_raw_by_attr_id(pPDInfo, HW_DEFINED_SMART_ATTRIBUTE_ID_TLC_NAND_WRITTEN_H);
        pPDInfo->pdinfo.write_amp.hw_defined.host_write_l =
            get_hw_defined_smart_raw_by_attr_id(pPDInfo, HW_DEFINED_SMART_ATTRIBUTE_ID_TLC_HOST_WRITTEN_L);
        pPDInfo->pdinfo.write_amp.hw_defined.host_write_h =
            get_hw_defined_smart_raw_by_attr_id(pPDInfo, HW_DEFINED_SMART_ATTRIBUTE_ID_TLC_HOST_WRITTEN_H);
        // 大于等于30天, update_support_flag为True表明支持计算利用当前值计算剩余寿命
        if (pPDInfo->pdinfo.power_on_hours >= POWER_ON_HOURS_LIMIT_30_DAYS) {
            pPDInfo->pdinfo.write_amp.update_support_flag = TRUE;
        }
    } else if (pPDInfo->smartinfo.valid_flag == TRUE) {
        if (check_manufacture_statisfied_top3(pPDInfo->pdinfo.manufacturer) == FALSE) {
            return;
        }
        pPDInfo->pdinfo.write_amp.vendor.valid_flag = TRUE;
        pPDInfo->pdinfo.write_amp.vendor.nand_write = get_sata_nand_flash_written_by_vendor(pPDInfo);
        pPDInfo->pdinfo.write_amp.vendor.host_write = get_sata_host_written_by_vendor(pPDInfo);
        if (pPDInfo->pdinfo.power_on_hours >= POWER_ON_HOURS_LIMIT_30_DAYS) {
            pPDInfo->pdinfo.write_amp.update_support_flag = TRUE;
        }
    }
}

/*
 * Description: 获取华为自研SAS接口SSD硬盘的写放大情况
*/
LOCAL void get_sas_write_amp_factor(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pPDInfo)
{
    guint8 *buf = NULL;
    guint32 buf_size = 0;
    gint32 ret = send_read_hssd_io_info_scsi_command(ctrl_id, device_id, &buf, &buf_size, NULL);
    if (ret != SML_SUCCESS) {
        return;
    }
    SML_PD_READ_WRITE_DATA_STATISTICS_S write_data = { 0 };
    ret = memcpy_s(&write_data, HUAWEI_SPECIFIC_C0H_PAGE_RESP_LENGTH, buf, buf_size);
    g_free(buf);
    if (ret != EOK) {
        debug_log(DLOG_ERROR, "memcpy_s failed, ret: %d", ret);
        return;
    }
    pPDInfo->pdinfo.write_amp.vendor.nand_write = (guint64)(write_data.nm_write_data + write_data.gc_write_data);
    pPDInfo->pdinfo.write_amp.vendor.host_write = write_data.host_write_data;
    debug_log(DLOG_INFO, "nand_write = 0x%"G_GUINT64_HEX_FORMAT", host_write = 0x%"G_GUINT64_HEX_FORMAT"",
        pPDInfo->pdinfo.write_amp.vendor.nand_write, pPDInfo->pdinfo.write_amp.vendor.host_write);
}

/*
 * Description: 获取SAS接口SSD硬盘的写放大量需要的信息情况, 仅华为自研盘支持
 * Note: 由于SAS SSD盘支持预估寿命, 需要进行亚健康文件记录, 故将标志位置为TRUE。但支持获取写放大信息的厂商只有HUAWEI
*/
LOCAL void get_sas_write_amplification(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pPDInfo)
{
    if (check_manufacture_statisfied_top3(pPDInfo->pdinfo.manufacturer) == FALSE) {
        return;
    }
    pPDInfo->pdinfo.write_amp.vendor.valid_flag = TRUE;
    pPDInfo->pdinfo.write_amp.vendor.nand_write = STORAGE_INFO_INVALID_DWORD;
    pPDInfo->pdinfo.write_amp.vendor.host_write = STORAGE_INFO_INVALID_DWORD;

    if (pPDInfo->pdinfo.power_on_hours >= POWER_ON_HOURS_LIMIT_30_DAYS) {
        pPDInfo->pdinfo.write_amp.update_support_flag = TRUE;
    }
    if (strncasecmp(pPDInfo->pdinfo.manufacturer, PD_VENDOR_NAME_HUAWEI, strlen(PD_VENDOR_NAME_HUAWEI)) != 0) {
        return;
    }

    // 获取厂商自定义Smart信息中nand\host数据
    get_sas_write_amp_factor(ctrl_id, device_id, pPDInfo);
}

/*
 * Description: 获取SSD硬盘的预估剩余寿命信息
*/
static void get_ssd_write_amp_factor_info(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pPDInfo)
{
    pPDInfo->pdinfo.write_amp.update_support_flag = FALSE;

    if (pPDInfo->pdinfo.media_type == ADM_DISK_MEDIUM_TYPE_SSD) {
        if (pPDInfo->pdinfo.interface_type == PD_INTERFACE_TYPE_SATA) {
            // SATA SSD盘
            get_sata_write_amplification(pPDInfo);
        } else if (pPDInfo->pdinfo.interface_type == PD_INTERFACE_TYPE_SAS) {
            // SAS SSD盘
            get_sas_write_amplification(ctrl_id, device_id, pPDInfo);
        }
    }
}

/*
 * Description: 更新硬盘的剩余预估寿命情况，上电累计时间超30天后，间隔24h一次
*/
static void get_pd_est_lifespan_and_write_amp(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pPDinfo)
{
    pPDinfo->pdinfo.estimated_lifespan.manage_support_flag = TRUE;

    guint32 cur_timestamp = (guint32)vos_tick_get();
    guint32 interval;

    if (cur_timestamp >= pPDinfo->pdinfo.estimated_lifespan.last_update_timestamp) {
        interval = cur_timestamp - pPDinfo->pdinfo.estimated_lifespan.last_update_timestamp;
    } else {
        interval = cur_timestamp + (G_MAXUINT32 - pPDinfo->pdinfo.estimated_lifespan.last_update_timestamp);
    }

    if (interval > UPDATE_INTERVAL_24_HOURS || pPDinfo->pdinfo.estimated_lifespan.last_update_timestamp == 0) {
        get_ssd_est_remaining_lifespan(pPDinfo);
        get_ssd_write_amp_factor_info(ctrl_id, device_id, pPDinfo);

        pPDinfo->pdinfo.estimated_lifespan.last_update_timestamp = cur_timestamp;
    }
}
/*
 * Description: 解析物理盘的固件状态
 */
static guint16 parse_pd_fw_state(guint8 logi_status)
{
    switch (logi_status) {
        case ADM_PD_STATUS_ONLINE:
            return PD_STATE_ONLINE;
        case ADM_PD_STATUS_OFFLINE:
            return PD_STATE_OFFLINE;
        case ADM_PD_STATUS_CFG_FAULT:
            return PD_STATE_FAILED;
        case ADM_PD_STATUS_UCFG_GOOD:
            return PD_STATE_UNCONFIGURED_GOOD;
        case ADM_PD_STATUS_UCFG_FAULT:
            return PD_STATE_UNCONFIGURED_BAD;
        case ADM_PD_STATUS_HOT_SPARE:
            return PD_STATE_HOT_SPARE;
        case ADM_PD_STATUS_FOREIGN:
            return PD_STATE_FOREIGN;
        case ADM_PD_STATUS_DIAGNOSING:
            return PD_STATE_DIAGNOSING;
        case ADM_PD_STATUS_RECONSTRUCTING:
            return PD_STATE_REBUILD;
        case ADM_PD_STATUS_COPYBACK:
            return PD_STATE_COPYBACK;
        case ADM_PD_STATUS_INCOMPAT:
            return PD_STATE_INCOMPATIBLE;
        case ADM_PD_STATUS_UNSUPPORTE:
            return PD_STATE_NOT_SUPPORTED;
        default:
            return PD_STATE_UNKNOWN;
    }
}

/*
 * Description: 解析物理盘的尺寸大小
 * Note:通过histore lib获取到的物理盘尺寸大小与1880部分不匹配，需转换
 *      1-5类型相同无需转换，其他类型统一返回PD_FORM_FACTOR_UNKNOWN
 */
static guint8 get_pd_drive_size(guint8 drive_size)
{
    if ((drive_size >= PD_FORM_FACTOR_5_25_INCH) && (drive_size <= PD_FORM_FACTOR_LESS_THAN_1_8_INCH)) {
        return drive_size;
    }
    return PD_FORM_FACTOR_UNKNOWN;
}

typedef enum {
    IDENTIFY_DONE = 1, // 已获取wwn
    IDENTIFY_ERROR, // 获取wwn错误
} pd_identify_status_type;

LOCAL gint32 GetSasDeviceIdentifyInfo(guint32 ctrl_id, guint16 device_id, IDE_IDENTIFY_DEVICE_T *identify)
{
    if (identify == NULL) {
        return SML_ERR_NULL_DATA;
    }
    struct cmd_scsi_passthrough scsi_passthru_cmd = {0};

    set_sata_smart_loc_value(device_id, &scsi_passthru_cmd);
    scsi_passthru_cmd.lun = 0;
    scsi_passthru_cmd.cdb_len = SCSI_CDB_LENGTH6;
    scsi_passthru_cmd.cdb[NUM_0] = 0x12;
    scsi_passthru_cmd.cdb[NUM_1] = 0x00;
    scsi_passthru_cmd.cdb[NUM_2] = 0x00;
    scsi_passthru_cmd.cdb[NUM_3] = 0x00;
    scsi_passthru_cmd.cdb[NUM_4] = 0x40;
    scsi_passthru_cmd.cdb[NUM_5] = 0x00;

    guint8 *data = (guint8 *)g_malloc0(SAS_SMART_DATA_LENGTH);
    if (data == NULL) {
        debug_log(DLOG_ERROR, "%s, g_malloc0 failed.", __FUNCTION__);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    gint32 retval = send_scsi_passthru_cmd(ctrl_id, &scsi_passthru_cmd, data, SAS_SMART_DATA_LENGTH);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_ERROR,
            "Get SAS Device Identity data by SCSI PASSTHRU failed, DeviceId = %u, CtrlId = %u, return 0x%04X",
            device_id, SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        g_free(data);
        return retval;
    }

    // SAS使用的 SCSI INQUIRY 命令查询，只有4字节
    identify->data.firmwareRevision[NUM_0] = (data[33] << 0x8) | data[32]; // 第32,33,34,35位硬盘固件版本
    identify->data.firmwareRevision[NUM_1] = (data[35] << 0x8) | data[34]; // 第32,33,34,35位硬盘固件版本
    identify->data.firmwareRevision[NUM_2] = 0;
    identify->data.firmwareRevision[NUM_3] = 0;

    g_free(data);
    return retval;
}

/*
 * Description: 填充读取盘固件的参数
 */
LOCAL void fill_scsi_hddver_cmd_cdb_info(struct cmd_scsi_passthrough *scsi_passthru_cmd)
{
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->cdb_len = SCSI_CDB_LENGTH16;
    scsi_passthru_cmd->cdb[0] = 0x85;   // cdb[0]:operation code; 0x85:PASS-THROUGH(16)指定操作码
    scsi_passthru_cmd->cdb[1] = 0x09;   // cdb[1]:protocol;       0x09:None-data command - Device Reset
    scsi_passthru_cmd->cdb[2] = 0x0e;   // cdb[2]:transfer type;
                                        // 0x0e:The number of ATA logical sector size blocks to be transferred
    scsi_passthru_cmd->cdb[3] = 0xff;   // cdb[3]
    scsi_passthru_cmd->cdb[6] = 0x01;   // cdb[6]:count(7:0);     0x01:sector num
    scsi_passthru_cmd->cdb[8] = 0x01;   // cdb[8]:count(15:8);
    scsi_passthru_cmd->cdb[13] = 0xa0;   // cdb[13]
    scsi_passthru_cmd->cdb[14] = 0xec;   // cdb[14]:COMMAND;      0Xec:defined command
}

/*
 * Description: 读取SATA的盘信息
 */
LOCAL gint32 GetSataDeviceIdentifyInfo(guint32 ctrl_id, guint16 device_id, guint8 *buf, guint32 buf_size)
{
    if (buf == NULL) {
        return SML_ERR_NULL_DATA;
    }
    struct cmd_scsi_passthrough scsi_passthru_cmd = {0};

    set_sata_smart_loc_value(device_id, &scsi_passthru_cmd);
    fill_scsi_hddver_cmd_cdb_info(&scsi_passthru_cmd);

    guint8 *data = (guint8 *)g_malloc0(ATA_SMART_DATA_LENGTH);
    if (data == NULL) {
        debug_log(DLOG_ERROR, "%s, g_malloc0 failed.", __FUNCTION__);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    gint32 retval = send_scsi_passthru_cmd(ctrl_id, &scsi_passthru_cmd, data, ATA_SMART_DATA_LENGTH);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_ERROR,
            "Get SATA Device Identity data by SCSI PASSTHRU failed, DeviceId = %u, CtrlId = %u, return 0x%04X",
            device_id, SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        g_free(data);
        return retval;
    }
    // 解析盘固件信息
    guint16 *pU16_data = (guint16 *)g_malloc0(ATA_SMART_DATA_LENGTH);
    if (pU16_data == NULL) {
        g_free(data);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }
    memcpy_s(pU16_data, ATA_SMART_DATA_LENGTH, data, ATA_SMART_DATA_LENGTH);

    guint16 *pU16_tmp = pU16_data;
    guint16 u16_data = 0;

    for (guint32 idx = 0; idx < ATA_SMART_DATA_LENGTH / NUM_2; idx++) {
        swapBytes((void *)pU16_tmp, (void *)&u16_data, sizeof(u16_data));
        *pU16_tmp = u16_data;
        pU16_tmp++;
    }
    if (buf_size >= ATA_SMART_DATA_LENGTH) {
        errno_t safe_fun_ret = memcpy_s(buf, buf_size, pU16_data, ATA_SMART_DATA_LENGTH);
        if (safe_fun_ret != EOK) {
            debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d.", __FUNCTION__, safe_fun_ret);
        }
    } else {
        retval = SML_ERR_BUF_NOT_ENOUGH;
    }

    g_free(pU16_data);
    g_free(data);
    return retval;
}

static void fill_sata_pd_info_manufacturer(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pPDinfo,
    struct cmd_show_disk *pd_info)
{
    guint32 vendor_id = 0;
    gint32 secure_rv = EOK;
    gint32 retval = SML_SUCCESS;
    if (pPDinfo->pdinfo.interface_type != PD_INTERFACE_TYPE_SATA) {
        pPDinfo->pdinfo.identify_status = IDENTIFY_ERROR;
        return;
    }
    // 如果“盘不处于active状态”或“sn未变化且已获取过wwn”，则不更新wwn，也不更新status
    if (pPDinfo->pdinfo.power_state != PD_POWER_STATE_ACTIVE ||
        (g_strcmp0(pPDinfo->pdinfo.serial_num, (const gchar *)pd_info->serial_num) == 0 &&
        pPDinfo->pdinfo.identify_status == IDENTIFY_DONE)) {
        return;
    }
    pPDinfo->pdinfo.identify_status = IDENTIFY_DONE;
    retval = get_sata_device_wwn(ctrl_id, device_id, &vendor_id);
    debug_log(DLOG_INFO, "%s get wwn, vendor_id=%u, retval=%d", __FUNCTION__, vendor_id, retval);
    if (retval != SML_SUCCESS) {
        pPDinfo->pdinfo.identify_status = IDENTIFY_ERROR;
        return;
    }
    pPDinfo->pdinfo.vendor_id = vendor_id;
    secure_rv = strcpy_s(pPDinfo->pdinfo.manufacturer, sizeof(pPDinfo->pdinfo.manufacturer),
        get_pd_vendor_name(vendor_id));
    if (secure_rv != EOK) {
        debug_log(DLOG_ERROR, "strcpy_s failed. secure_rv = %d", secure_rv);
        pPDinfo->pdinfo.identify_status = IDENTIFY_ERROR;
    }
    return;
}

static void fill_pd_info(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pPDinfo, struct cmd_show_disk *pd_info)
{
    pPDinfo->pdinfo.device_speed = parse_device_and_disk_max_speed(pd_info->disk_max_speed); // 盘的最大速率
    pPDinfo->pdinfo.link_speed = parse_device_and_disk_max_speed(pd_info->device_speed); // 盘的协商速率
    pPDinfo->pdinfo.encl_device_id = pd_info->enc_id;

    pPDinfo->pdinfo.slot_num = pd_info->slot_id;
    pPDinfo->pdinfo.media_type = parse_media_type(pd_info->media_type);
    pPDinfo->pdinfo.interface_type = get_pd_interface_type(pd_info->interface);
    pPDinfo->pdinfo.temperature = pd_info->drive_temperature;
    pPDinfo->pdinfo.media_err_count = pd_info->media_error_count;
    pPDinfo->pdinfo.other_err_count = pd_info->other_error_count;
    pPDinfo->pdinfo.halflife = pd_info->halflife; // 置 1 认为有故障

    pPDinfo->pdinfo.health = 0;
    ASSERT_BIT_IF_TRUE(pd_info->media_error_count != 0, pPDinfo->pdinfo.health, 0); // 设置0和博通保持一致
    ASSERT_BIT_IF_TRUE(pd_info->halflife != 0, pPDinfo->pdinfo.health, 1);  // 设置1和博通保持一致
    ASSERT_BIT_IF_TRUE(pd_info->other_error_count != 0, pPDinfo->pdinfo.health, 2); // 设置2和博通保持一致
    (void)strncpy_s(pPDinfo->pdinfo.serial_num, sizeof(pPDinfo->pdinfo.serial_num), (const gchar *)pd_info->serial_num,
        strlen((gchar *)pd_info->serial_num));

    (void)strncpy_s(pPDinfo->pdinfo.model, sizeof(pPDinfo->pdinfo.model), (const gchar *)pd_info->model,
        strlen((const gchar *)pd_info->model));
    fill_sata_pd_info_manufacturer(ctrl_id, device_id, pPDinfo, pd_info);
    if (pPDinfo->pdinfo.identify_status != IDENTIFY_DONE) {
        (void)strncpy_s(pPDinfo->pdinfo.manufacturer, sizeof(pPDinfo->pdinfo.manufacturer),
        (const gchar *)pd_info->vendor, strlen((gchar *)pd_info->vendor)); // Manufacturer
    }
    (void)strncpy_s(pPDinfo->pdinfo.firmware_version, sizeof(pPDinfo->pdinfo.firmware_version),
        (const gchar *)pd_info->fw_version, strlen((gchar *)pd_info->fw_version));
    gint32 ret = snprintf_s(pPDinfo->pdinfo.sas_addr1, sizeof(pPDinfo->pdinfo.sas_addr1),
        sizeof(pPDinfo->pdinfo.sas_addr1) - 1, "%llX", pd_info->sas_address);
    if (ret <= 0) {
        debug_log(DLOG_ERROR, "%s: snprintf_s fail, ret = %d", __FUNCTION__, ret);
    }
    pPDinfo->pdinfo.power_on_hours = pd_info->power_on_time[0]; // 取数组第一个值
    pPDinfo->pdinfo.coerced_size = pd_info->raw_capacity / (1024 * 1024); // 1024 Byte转换
    pPDinfo->pdinfo.power_state = get_pd_power_state(pd_info->hibernated_status);
    pPDinfo->pdinfo.block_size = pd_info->lbs; // Byte
    pPDinfo->pdinfo.fw_state_raw = pd_info->physi_status; // 未经转换从raid卡读出来的物理盘状态
    pPDinfo->pdinfo.fde_capable = pd_info->is_sed;
    pPDinfo->pdinfo.bootable = pd_info->is_boot;
    pPDinfo->pdinfo.boot_priority = ((pd_info->is_boot == TRUE) ? 1 : 0); // 只有一个优先级 1
    pPDinfo->pdinfo.hot_spare = ((pd_info->hsp_status > HOT_SPARE_LOCAL) ? PD_HOT_SPARE_UNKNOWN : pd_info->hsp_status);
    pPDinfo->pdinfo.fw_state = parse_pd_fw_state(pd_info->logi_status);
    pPDinfo->pdinfo.form_factor = get_pd_drive_size(pd_info->drive_size);
    if (pd_info->support_flag & BIT(1)) { // 取BIT(1)位为慢盘标志位
        pPDinfo->pdinfo.health |= PD_HEALTH_CODE_SLOW_DISK;
    } else {
        pPDinfo->pdinfo.health &= ~PD_HEALTH_CODE_SLOW_DISK;
    }
    pPDinfo->pdinfo.last_prefail_event_seq_num = STORAGE_INFO_INVALID_DWORD;
}

/*
 * Description: 检查本地查询的SMART数据是否过期，避免查询过于频繁，导致硬盘性能下降
 * History: 2022年10月11日  新生成函数
*/
static guint8 check_hs_pd_smart_expired(SML_PD_SMART_INFO_S *smart_info)
{
    guint32 interval = 0;
    if (smart_info->last_update_timestamp == 0) {
        return TRUE;
    }

    guint32 current_timestamp = (guint32)time(0);
    if (current_timestamp >= smart_info->last_update_timestamp) {
        interval = current_timestamp - smart_info->last_update_timestamp;
    } else {
        interval = G_MAXUINT32 - smart_info->last_update_timestamp + current_timestamp;
    }

    if (interval > 3600) {  // 3600: SMART信息检测周期3600秒
        return TRUE;
    }
    return FALSE;
}

/*
 * Description: 发送scsi协议，读取Sata盘的SMART信息
 * History: 2022年10月14日  新生成函数
*/
static gint32 get_sata_device_smart_data(guint32 ctrl_id, guint16 device_id, SML_PD_SMART_INFO_S *smart_info)
{
    struct cmd_scsi_passthrough scsi_passthru_cmd;
    (void)memset_s(&scsi_passthru_cmd, sizeof(scsi_passthru_cmd), 0, sizeof(scsi_passthru_cmd));

    set_sata_smart_loc_value(device_id, &scsi_passthru_cmd);
    scsi_passthru_cmd.lun = 0;
    scsi_passthru_cmd.cdb_len = SCSI_CDB_LENGTH16;
    scsi_passthru_cmd.cdb[0] = 0x85;
    scsi_passthru_cmd.cdb[1] = 0x09;
    scsi_passthru_cmd.cdb[2] = 0x0e;
    scsi_passthru_cmd.cdb[3] = 0xff;
    scsi_passthru_cmd.cdb[4] = 0xd0;
    scsi_passthru_cmd.cdb[6] = 0x01;
    scsi_passthru_cmd.cdb[8] = 0x01;
    scsi_passthru_cmd.cdb[10] = 0x4f;
    scsi_passthru_cmd.cdb[12] = 0xc2;
    scsi_passthru_cmd.cdb[13] = 0xa0;
    scsi_passthru_cmd.cdb[14] = 0xb0;

    guint8 *data = (guint8 *)g_malloc0(ATA_SMART_DATA_LENGTH);
    if (data == NULL) {
        debug_log(DLOG_ERROR, "%s, g_malloc0 failed.", __FUNCTION__);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    gint32 retval = send_scsi_passthru_cmd(ctrl_id, &scsi_passthru_cmd, data, ATA_SMART_DATA_LENGTH);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_ERROR,
            "Get SATA Device SMART data by SCSI PASSTHRU failed, DeviceId = %u, CtrlId = %u, return 0x%04X",
            device_id, SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        g_free(data);
        return retval;
    }

    errno_t secure_rv = memcpy_s(smart_info->SATADevice.smart_data, sizeof(smart_info->SATADevice.smart_data),
        data, ATA_SMART_DATA_LENGTH);
    g_free(data);
    if (secure_rv != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d", __FUNCTION__, secure_rv);
        return SML_ERR_SEC_FUNC_FAILED;
    }

    return SML_SUCCESS;
}

/*
 * Description: 读取Sata盘的SMART threshold信息，并将其拷贝至smart_threshold结构体中
 * History: 2022年10月14日  新生成函数
*/
static gint32 get_sata_device_smart_threshold(guint32 ctrl_id, guint16 device_id, SML_PD_SMART_INFO_S *smart_info)
{
    struct cmd_scsi_passthrough scsi_passthru_cmd;
    (void)memset_s(&scsi_passthru_cmd, sizeof(scsi_passthru_cmd), 0, sizeof(scsi_passthru_cmd));

    set_sata_smart_loc_value(device_id, &scsi_passthru_cmd);
    scsi_passthru_cmd.lun = 0;
    scsi_passthru_cmd.cdb_len = SCSI_CDB_LENGTH16;
    scsi_passthru_cmd.cdb[0] = 0x85;
    scsi_passthru_cmd.cdb[1] = 0x09;
    scsi_passthru_cmd.cdb[2] = 0x0e;
    scsi_passthru_cmd.cdb[3] = 0xff;
    scsi_passthru_cmd.cdb[4] = 0xd1;
    scsi_passthru_cmd.cdb[6] = 0x01;
    scsi_passthru_cmd.cdb[7] = 0x01;
    scsi_passthru_cmd.cdb[8] = 0x01;
    scsi_passthru_cmd.cdb[10] = 0x4f;
    scsi_passthru_cmd.cdb[12] = 0xc2;
    scsi_passthru_cmd.cdb[13] = 0xa0;
    scsi_passthru_cmd.cdb[14] = 0xb0;

    guint8 *data = (guint8 *)g_malloc0(ATA_SMART_DATA_LENGTH);
    if (data == NULL) {
        debug_log(DLOG_ERROR, "%s, g_malloc0 failed.", __FUNCTION__);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    gint32 retval = send_scsi_passthru_cmd(ctrl_id, &scsi_passthru_cmd, data, ATA_SMART_DATA_LENGTH);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_ERROR,
            "Get SATA Device SMART Threshold by SCSI PASSTHRU failed, DeviceId = %u, CtrlId = %u, return 0x%04X",
            device_id, SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        g_free(data);
        return retval;
    }

    errno_t secure_rv = memcpy_s(smart_info->SATADevice.smart_threshold,
        sizeof(smart_info->SATADevice.smart_threshold), data, ATA_SMART_DATA_LENGTH);
    g_free(data);
    if (secure_rv != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d", __FUNCTION__, secure_rv);
        return SML_ERR_SEC_FUNC_FAILED;
    }

    return SML_SUCCESS;
}

/*
 * Description: 读取Sata盘的SMART信息
 * History: 2022年10月11日  新生成函数
*/
static void get_sata_device_smart_info(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pPDinfo)
{
    if (check_hs_pd_smart_expired(&pPDinfo->smartinfo) == FALSE) {
        return;
    }

    // 读取SATA硬盘厂商自定义的SMART信息
    if (get_sata_device_smart_data(ctrl_id, device_id, &pPDinfo->smartinfo) == SML_SUCCESS &&
        get_sata_device_smart_threshold(ctrl_id, device_id, &pPDinfo->smartinfo) == SML_SUCCESS) {
        pPDinfo->smartinfo.valid_flag = TRUE;
        pPDinfo->smartinfo.last_update_timestamp = (guint32)vos_get_cur_time_stamp();
    } else {
        debug_log(DLOG_ERROR, "get sata smart data or smart threshold error");
        pPDinfo->smartinfo.valid_flag = FALSE;
    }

    if (pPDinfo->pdinfo.media_type != ADM_DISK_MEDIUM_TYPE_SSD) {
        return;
    }
    // 读取SATA硬盘华为自定义的SMART信息
    pPDinfo->hw_defined_smartinfo.valid_flag = FALSE;
    if (get_sata_device_hw_defined_smart_data(ctrl_id, device_id, &pPDinfo->hw_defined_smartinfo) == SML_SUCCESS) {
        pPDinfo->hw_defined_smartinfo.valid_flag = TRUE;
    }

    return;
}

static gint8 parse_pd_sense_code(guint8 *sense_data, guint32 data_len, SCSI_SENSE_DISECT_S *sense_info)
{
    if (sense_data == NULL || data_len < 32 || sense_info == NULL) {    // 32：scsi最大sense长度
        return RET_ERR;
    }

    sense_info->error_code = sense_data[0] & 0x7F;
    sense_info->asc = 0;
    sense_info->ascq = 0;
    // formate is fixed
    if ((sense_info->error_code == SCSI_FIXED_SENSE_DATA_RESP_CUR_INFO) ||
        (sense_info->error_code == SCSI_FIXED_SENSE_DATA_RESP_DEFERRD_ERR)) {
        sense_info->sense_key = sense_data[2] & 0x0F;
        // sense_data[7]: ADDITIONAL SENSE LENGTH; 5: 12/13要有值，后续长度必须>5
        if (sense_data[7] > 5) {
            sense_info->asc = sense_data[12];
            sense_info->ascq = sense_data[13];
        }
    // formate is descriptor
    } else if ((sense_info->error_code == SCSI_DESC_SENSE_DATA_RESP_CUR_INFO) ||
        (sense_info->error_code == SCSI_DESC_SENSE_DATA_RESP_DEFERRD_ERR)) {
        sense_info->sense_key = sense_data[1] & 0x0F;
        sense_info->asc = sense_data[2];
        sense_info->ascq = sense_data[3];   // 3：根据标准协议ascq取值sense_data[3]
    }
    return 0;
}

/*
 * Description: 发送SCSI RequestSense命令
 * History: 2022年10月18日  新生成函数
*/
static gint32 send_scsi_request_sense_command(guint32 ctrl_id, guint16 device_id, SCSI_SENSE_DISECT_S *sense_info)
{
    struct cmd_scsi_passthrough scsi_passthru_cmd;
    (void)memset_s(&scsi_passthru_cmd, sizeof(scsi_passthru_cmd), 0, sizeof(scsi_passthru_cmd));

    scsi_passthru_cmd.sense_buffer = (guint8 *)g_malloc0(SCSI_LOG_PAGE_RESP_LENGTH);
    if (scsi_passthru_cmd.sense_buffer == NULL) {
        debug_log(DLOG_ERROR, "%s, g_malloc0 failed.", __FUNCTION__);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    set_sata_smart_loc_value(device_id, &scsi_passthru_cmd);
    scsi_passthru_cmd.lun = 0;
    scsi_passthru_cmd.cdb_len = SCSI_CDB_LENGTH6;
    scsi_passthru_cmd.cdb[0] = SCSI_CMD_REQUEST_SENSE;
    scsi_passthru_cmd.cdb[4] = SCSI_LOG_PAGE_RESP_LENGTH;
    scsi_passthru_cmd.sense_buffer_len = SCSI_LOG_PAGE_RESP_LENGTH;

    (void)send_scsi_passthru_cmd(ctrl_id, &scsi_passthru_cmd,
        scsi_passthru_cmd.sense_buffer, SCSI_LOG_PAGE_RESP_LENGTH);
    (void)parse_pd_sense_code(scsi_passthru_cmd.sense_buffer, SCSI_LOG_PAGE_RESP_LENGTH, sense_info);

    g_free(scsi_passthru_cmd.sense_buffer);
    return SML_SUCCESS;
}

/*
 * Description: 给Sas盘的赋值数据
 * History: 2022年10月11日  新生成函数
*/
static gint32 set_sas_smart_value(guint32 ctrl_id, guint16 device_id,
    guint8 *buf, SML_PD_SMART_INFO_S *smart_info, guint32 buf_size)
{
    SCSI_SENSE_DISECT_S senInfo = { 0 };
    guint16 offset = SCSI_LOG_PAGE_HEADER_SIZE;
    guint16 page_length = (buf[2] << 8) + buf[3];

#define LOG_PAGE_INFORMATIONAL_EXCEPTIONS_PARAM_CODE 0x0000

    // 数到ASCQ至少要偏移5字节
    while ((offset < MIN(page_length + SCSI_LOG_PAGE_HEADER_SIZE, buf_size)) && (offset + 5 < buf_size)) {
        guint16 page_param_code = (buf[offset] << 8) + buf[offset + 1]; // 8：buf[offset]值左移8位

        if (page_param_code != LOG_PAGE_INFORMATIONAL_EXCEPTIONS_PARAM_CODE) {
            debug_log(DLOG_DEBUG, "SCSI Log Sense command responsed with incorrect status [0x%04x]",
                page_param_code);
            smart_info->valid_flag = FALSE;
            offset += buf[offset + 3] + SCSI_LOG_PAGE_HEADER_SIZE;  // buf[offset + 3]：parameter length
            continue;
        }

        if (buf[offset + 3] > 1) {  // buf[offset + 3]：parameter length
            senInfo.asc = buf[offset + 4];  // 4: 赋值给SMART信息asc
            senInfo.ascq = buf[offset + 5]; // 5: 赋值给SMART信息ascq
        }

        if (senInfo.asc == 0) {
            gint32 retval = send_scsi_request_sense_command(ctrl_id, device_id, &senInfo);
            debug_log(DLOG_DEBUG, "Send SCSI %u.%u request sense return 0x%x",
                SML_CTRL_ID_VALID_BIT(ctrl_id), device_id, retval);
            if (retval != SML_SUCCESS) {
                return retval;
            }
        }

        smart_info->valid_flag = TRUE;
        smart_info->last_update_timestamp = (guint32)time(0);
        smart_info->SASDevice.ASC = senInfo.asc;
        smart_info->SASDevice.ASCQ = senInfo.ascq;

        break;
    }
    return SML_SUCCESS;
}

/*
 * Description: 读取Sas盘的SMART信息
 * History: 2022年10月11日  新生成函数
*/
static gint32 get_sas_device_smart_info(guint32 ctrl_id, guint16 device_id, SML_PD_SMART_INFO_S *smart_info)
{
    guint8 smart_lp_support = FALSE;
    guint8 *buf = NULL;
    guint32 buf_size = 0;

    if (check_hs_pd_smart_expired(smart_info) == FALSE) {
        return SML_SUCCESS;
    }

    gint32 retval = get_scsi_device_support_log_pages(ctrl_id, device_id, SCSI_LOG_PAGE_IE, &smart_lp_support);
    if (retval != SML_SUCCESS || smart_lp_support != TRUE) {
        debug_log(DLOG_ERROR, "Get SCSI %u.%u Support LogPages return 0x%x, Flag is %s",
            SML_CTRL_ID_VALID_BIT(ctrl_id), device_id, retval, smart_lp_support ? "TRUE" : "FALSE");
        return retval;
    }

    page_code_info_req req = { 0 };
    req.ctrl_id = ctrl_id;
    req.device_id = device_id;
    req.page_code = SCSI_LOG_PAGE_IE;
    req.sub_page_code = 0;

    retval = send_scsi_log_sense_command(&req, &buf, &buf_size, NULL);
    if (retval != SML_SUCCESS || buf == NULL) {
        debug_log(DLOG_ERROR, "Send SCSI %u.%u LogSense return 0x%x", SML_CTRL_ID_VALID_BIT(ctrl_id),
            device_id, retval);
        return retval;
    }
    
    if (buf_size <= SCSI_LOG_PAGE_HEADER_SIZE) {
        retval = SML_ERR_DATA_LEN_INVALID;
    } else {
        retval = set_sas_smart_value(ctrl_id, device_id, buf, smart_info, buf_size);
        if (retval != SML_SUCCESS) {
            debug_log(DLOG_ERROR, "Set sas value failed, %u.%u LogSense return 0x%x.",
                SML_CTRL_ID_VALID_BIT(ctrl_id), device_id, retval);
        }
    }

    g_free(buf);
    
    if (smart_info->valid_flag == FALSE) {
        smart_info->SASDevice.ASC = 0xFF;
        smart_info->SASDevice.ASCQ = 0xFF;
    }
    return retval;
}

gint32 histore_get_pd_info(guint32 ctrl_id, guint16 device_id, gpointer data)
{
    struct cmd_show_disk pd_info;
    if (data == NULL) {
        return SML_ERR_NULL_DATA;
    }
    SML_PD_INFO_S *pPDinfo = (SML_PD_INFO_S *)data;

    (void)memset_s(&pd_info, sizeof(pd_info), 0, sizeof(pd_info));

    gint32 ret = get_pd_basic_info(ctrl_id, device_id, &pd_info);
    if (ret != SML_SUCCESS) {
        return ret;
    }

    pPDinfo->pdinfo.device_id = device_id;
    fill_pd_info(ctrl_id, device_id, pPDinfo, &pd_info);

    // 只有在硬盘spun up的时候才读取SMART信息，避免由于读取SMART信息唤醒硬盘，导致无法进入休眠状态
    if (pPDinfo->pdinfo.power_state == PD_POWER_STATE_ACTIVE) {
        if (pPDinfo->pdinfo.interface_type == PD_INTERFACE_TYPE_SATA) {
            (void)get_sata_device_smart_info(ctrl_id, device_id, pPDinfo);
        } else if (pPDinfo->pdinfo.interface_type == PD_INTERFACE_TYPE_SAS) {
            (void)get_sas_device_smart_info(ctrl_id, device_id, &pPDinfo->smartinfo);
        }
    }

    get_pd_progress_info(pPDinfo, &pd_info);
    get_pd_rotation_rate(pPDinfo, &pd_info);
    get_pd_wearout_info(pPDinfo, &pd_info);
    get_pd_spare_block_info(pPDinfo);
    get_pd_est_lifespan_and_write_amp(ctrl_id, device_id, pPDinfo);
    return ret;
}

gint32 histore_get_pd_firmware_version(guint32 ctrl_id, guint16 device_id, gpointer data)
{
    debug_log(DLOG_INFO, "[%s] smlib: GetPDFWVersion begin", __FUNCTION__);
    struct cmd_show_disk pd_info;
    if (data == NULL) {
        return SML_ERR_NULL_DATA;
    }
    SML_PD_FIRMWARE_VERSION_S *pd_fw_version_info = (SML_PD_FIRMWARE_VERSION_S *)data;

    (void)memset_s(&pd_info, sizeof(pd_info), 0, sizeof(pd_info));

    gint32 ret = get_pd_basic_info(ctrl_id, device_id, &pd_info);
    if (ret != SML_SUCCESS) {
        return ret;
    }

    guint8 pd_power_state = get_pd_power_state(pd_info.hibernated_status);
    guint8 pd_interface_type = get_pd_interface_type(pd_info.interface);
    if (pd_interface_type != PD_INTERFACE_TYPE_SATA &&
        pd_interface_type != PD_INTERFACE_TYPE_SAS) {
        (void)strncpy_s(pd_fw_version_info->firmware_version, sizeof(pd_fw_version_info->firmware_version),
            (const gchar *)pd_info.fw_version, strlen((gchar *)pd_info.fw_version));
        return SML_SUCCESS;
    }

    errno_t safe_fun_ret = EOK;
    IDE_IDENTIFY_DEVICE_T identify = {0};
    gint32 retval = SML_SUCCESS;

    // 只有在硬盘spun up的时候才读取SMART信息，避免由于读取SMART信息唤醒硬盘，导致无法进入休眠状态
    if (pd_power_state == PD_POWER_STATE_ACTIVE) {
        if (pd_interface_type == PD_INTERFACE_TYPE_SATA) {
            retval = GetSataDeviceIdentifyInfo(ctrl_id, device_id, (guint8 *)&identify, IDE_IDENTIFY_DEVICE_S);
        } else if (pd_interface_type == PD_INTERFACE_TYPE_SAS) {
            retval = GetSasDeviceIdentifyInfo(ctrl_id, device_id, &identify);
        }
    }
    if (retval == SML_SUCCESS) {
        (void)memset_s(pd_fw_version_info->firmware_version, sizeof(pd_fw_version_info->firmware_version), 0,
                sizeof(pd_fw_version_info->firmware_version));
        safe_fun_ret = memcpy_s(pd_fw_version_info->firmware_version, sizeof(pd_fw_version_info->firmware_version),
                (const gchar *)(identify.data.firmwareRevision), sizeof(identify.data.firmwareRevision));
        if (safe_fun_ret != EOK) {
            debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d.", __FUNCTION__, safe_fun_ret);
        }
        pd_fw_version_info->firmware_version[sizeof(pd_fw_version_info->firmware_version) - 1] = '\0';
        remove_string_space(pd_fw_version_info->firmware_version, strlen(pd_fw_version_info->firmware_version) + 1);
    }
    return retval;
}

gint32 histore_get_pd_sata_hwdefined_smart_info(guint32 ctrl_id, guint16 device_id, gpointer data)
{
    struct cmd_show_disk pd_info;
    if (data == NULL) {
        return SML_ERR_NULL_DATA;
    }
    ATA_SMART_DATA_HW_DEFINED_S *smart_info = (ATA_SMART_DATA_HW_DEFINED_S *)data;
    SML_PD_INFO_S* pPDinfo = (SML_PD_INFO_S *)g_malloc0(sizeof(SML_PD_INFO_S));

    (void)memset_s(&pd_info, sizeof(pd_info), 0, sizeof(pd_info));

    gint32 ret = get_pd_basic_info(ctrl_id, device_id, &pd_info);
    if (ret != SML_SUCCESS) {
        return ret;
    }

    pPDinfo->pdinfo.device_id = device_id;
    fill_pd_info(ctrl_id, device_id, pPDinfo, &pd_info);

    if (pPDinfo->pdinfo.interface_type == PD_INTERFACE_TYPE_SATA) {
        if (get_sata_device_hw_defined_smart_data(ctrl_id, device_id, &pPDinfo->hw_defined_smartinfo) == SML_SUCCESS) {
                pPDinfo->hw_defined_smartinfo.valid_flag = TRUE;
        }
    }

    if (pPDinfo->hw_defined_smartinfo.valid_flag == FALSE) {
        return SML_ERR_DATA_INVALID;
    }
    ret = memcpy_s(smart_info, sizeof(ATA_SMART_DATA_HW_DEFINED_S), pPDinfo->hw_defined_smartinfo.smart_data,
        sizeof(ATA_SMART_DATA_HW_DEFINED_S));
    g_free(pPDinfo);
    return ret;
}

static gint32 locate_pd_led(guint32 ctrl_id, guint16 device_id, guint8 sw)
{
    struct lib_cmd_param lib_param;
    struct cmd_set_disk_led disk_led;
    (void)memset_s(&lib_param, sizeof(lib_param), 0, sizeof(lib_param));
    (void)memset_s(&disk_led, sizeof(disk_led), 0, sizeof(disk_led));
    disk_led.led_type = CMD_LED_TYPE_LOCATE;
    disk_led.sw = sw; // switch 0 表示关闭，1 表示打开
    disk_led.loc.did = device_id;
    disk_led.loc.flag = DISK_LOC_DID;
    lib_param.opcode = ADM_RAID_SET;
    lib_param.subopcode = ADM_CMD_SET_DISK_LED;
    lib_param.card_id = ctrl_id;
    lib_param.channel = PCIE_PHYSICAL_FUCTION0;
    lib_param.param_len = (guint16)sizeof(struct cmd_set_disk_led);
    errno_t securec_rv = memcpy_s(lib_param.cmd_param, sizeof(lib_param.cmd_param), &disk_led, sizeof(disk_led));
    if (securec_rv != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s failed, ret = %d", __FUNCTION__, securec_rv);
    }
    return process_histore_cmd(&lib_param);
}

/*
 * Description: 硬盘点灯
 */
static gint32 start_locate_pd(guint32 ctrl_id, guint16 device_id)
{
    return locate_pd_led(ctrl_id, device_id, CMD_LED_STATUES_ON);
}

/*
 * Description: 停止硬盘点灯
 */
static gint32 stop_locate_pd(guint32 ctrl_id, guint16 device_id)
{
    return locate_pd_led(ctrl_id, device_id, CMD_LED_STATUES_OFF);
}

/*
 * Description: 设置物理启动盘
 */
static gint32 set_bootable_pd_cmd(guint32 ctrl_id, guint16 device_id, guint8 boot_param)
{
    struct lib_cmd_param lib_param;
    struct cmd_disk_boot disk_boot;
    (void)memset_s(&lib_param, sizeof(lib_param), 0, sizeof(lib_param));
    (void)memset_s(&disk_boot, sizeof(disk_boot), 0, sizeof(disk_boot));
    disk_boot.loc.did = device_id;
    disk_boot.loc.flag = DISK_LOC_DID; // flag为1 ，表示根据did 进行定位
    disk_boot.boot_status = boot_param;        // 0:关；1:开
    lib_param.opcode = ADM_RAID_SET;
    lib_param.subopcode = ADM_CMD_SET_DISK_BOOT;
    lib_param.card_id = ctrl_id;
    lib_param.channel = PCIE_PHYSICAL_FUCTION0;
    lib_param.param_len = (guint16)sizeof(struct cmd_disk_boot);
    errno_t securec_rv = memcpy_s(lib_param.cmd_param, sizeof(lib_param.cmd_param), &disk_boot, sizeof(disk_boot));
    if (securec_rv != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s failed, ret = %d", __FUNCTION__, securec_rv);
    }

    return process_histore_cmd(&lib_param);
}

/*
 * Description: 设置物理启动盘
 */
static gint32 set_bootable_pd(guint32 ctrl_id, guint16 device_id, guint8 boot_param)
{
    struct cmd_show_disk pd_info;
    (void)memset_s(&pd_info, sizeof(pd_info), 0, sizeof(pd_info));
    gint32 ret = get_pd_basic_info(ctrl_id, device_id, &pd_info);
    if (ret != SML_SUCCESS) {
        return ret;
    }

    /* 暂不支持启动优先级 */
    if (boot_param > 1) {
        boot_param = 1;
    }

    if (boot_param == pd_info.is_boot) {
        return SML_SUCCESS;
    }

    return set_bootable_pd_cmd(ctrl_id, device_id, boot_param);
}

/*
 * Description: 发送命令给histore lib设置热备盘
 */
static gint32 add_hot_spare(guint32 ctrl_id, guint16 device_id, guint8 spare_type, guint8 rg_id)
{
    struct lib_cmd_param lib_param;
    struct cmd_disk_hotspare disk_hotspare;
    (void)memset_s(&lib_param, sizeof(lib_param), 0, sizeof(lib_param));
    (void)memset_s(&disk_hotspare, sizeof(disk_hotspare), 0, sizeof(disk_hotspare));
    disk_hotspare.loc.did = device_id;
    disk_hotspare.loc.flag = DISK_LOC_DID; // flag为1 ，表示根据did 进行定位
    disk_hotspare.hsp_type = spare_type;
    disk_hotspare.rg_id = rg_id;

    lib_param.opcode = ADM_RAID_SET;
    lib_param.subopcode = ADM_CMD_SET_DISK_HSP;
    lib_param.card_id = ctrl_id;
    lib_param.channel = PCIE_PHYSICAL_FUCTION0;
    lib_param.param_len = (guint16)sizeof(struct cmd_disk_hotspare);
    errno_t securec_rv = memcpy_s(lib_param.cmd_param, sizeof(lib_param.cmd_param), &disk_hotspare,
                                  sizeof(disk_hotspare));
    if (securec_rv != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s failed, ret = %d", __FUNCTION__, securec_rv);
    }

    return process_histore_cmd(&lib_param);
}

/*
 * Description: 获取逻辑盘RAID组rg_id
 */
static gint32 get_ld_rg_id(guint32 ctrl_id, guint16 ld_target_id, guint8 *rg_id)
{
    gint32 ret;

    struct cmd_vd_info vd_info;
    (void)memset_s(&vd_info, sizeof(vd_info), 0, sizeof(vd_info));
    // 获取逻辑盘的信息
    ret = get_vd_info(ctrl_id, ld_target_id, &vd_info);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_ERROR, "[%s]: get_vd_info fail ret %x ctrl_id %d ld_target_id %d",
                  __FUNCTION__, ret, ctrl_id, ld_target_id);
        return ret;
    }

    // 输出raid组id
    *rg_id = vd_info.rg_id;

    return ret;
}

/*
 * Description: 添加热备盘
 */
static gint32 set_hot_spare(guint32 ctrl_id, guint16 device_id, guint8 operation, guint16 ld_target_id)
{
#define HOTSPARE_TYPE_GLOBAL 1
#define HOTSPARE_TYPE_DEDICATED 0

    gint32 ret;
    guint8 spare_type;
    guint8 rg_id = 0;

    if (operation == PD_OPERATION_SET_GLOBAL_HOTSPARE) {
        spare_type = HOTSPARE_TYPE_GLOBAL; // 1 全局热备盘
    } else if (operation == PD_OPERATION_SET_DEDICATED_HOTSPARE) {
        ret = get_ld_rg_id(ctrl_id, ld_target_id, &rg_id);
        if (ret != SML_SUCCESS) {
            return ret;
        }
        spare_type = HOTSPARE_TYPE_DEDICATED; // 0 局部热备盘
    } else {
        return SML_ERR_PD_OPERATION_NOT_SUPPORT;
    }

    ret = add_hot_spare(ctrl_id, device_id, spare_type, rg_id);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_ERROR, "[%s]: set_hot_spare fail ret %x ctrl_id %d device_id %d spare_type %d rg_id %d",
                  __FUNCTION__, ret, ctrl_id, device_id, spare_type, rg_id);
    }

    return ret;
}

/*
 * Description: 设置指定物理盘为未配置盘的命令
 */
static gint32 set_pd_free_cmd(guint32 ctrl_id, guint16 device_id)
{
    struct lib_cmd_param lib_param;
    struct multi_disk_location disk_location;

    (void)memset_s(&lib_param, sizeof(lib_param), 0, sizeof(lib_param));
    (void)memset_s(&disk_location, sizeof(disk_location), 0, sizeof(disk_location));

    disk_location.did = device_id;
    disk_location.flag = DISK_LOC_DID;  // flag为1 ，表示根据did进行定位

    lib_param.opcode = ADM_RAID_SET;
    lib_param.subopcode = ADM_CMD_SET_DISK_FREE;
    lib_param.card_id = ctrl_id;
    lib_param.channel = PCIE_PHYSICAL_FUCTION0;
    lib_param.param_len = (guint16)sizeof(struct multi_disk_location);
    errno_t securec_rv = memcpy_s(lib_param.cmd_param, sizeof(lib_param.cmd_param), &disk_location,
                                  sizeof(disk_location));
    if (securec_rv != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s failed, ret = %d", __FUNCTION__, securec_rv);
    }

    return process_histore_cmd(&lib_param);
}

/*
 * Description: 取消热备盘
 */

static gint32 cancel_hot_spare(guint32 ctrl_id, guint16 device_id)
{
    gint32 ret;

    struct cmd_show_disk pd_info;
    (void)memset_s(&pd_info, sizeof(pd_info), 0, sizeof(pd_info));

    // 获取物理盘的信息
    ret = get_pd_basic_info(ctrl_id, device_id, &pd_info);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_ERROR, "[%s]: get_pd_basic_info fail ret %x ctrl_id %d device_id %d",
                  __FUNCTION__, ret, ctrl_id, device_id);
        return ret;
    }

    // 非热备状态，直接返回错误
    if (pd_info.hsp_status != HOT_SPARE_GLOBAL && pd_info.hsp_status != HOT_SPARE_LOCAL) {
        return SML_ERR_PD_STATE_UNSUPPORTED_TO_SET;
    }

    ret = set_pd_free_cmd(ctrl_id, device_id);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_ERROR, "[%s]: cancel_hot_spare fail ret %x ctrl_id %d device_id %d",
                  __FUNCTION__, ret, ctrl_id, device_id);
    }

    return ret;
}

/*
 * Description: 设置指定物理盘为直通盘的命令
 */
static gint32 set_state_pd_passthru_cmd(guint32 ctrl_id, guint16 device_id)
{
    struct lib_cmd_param lib_param;
    struct cmd_disk_passthru disk_state;
    (void)memset_s(&lib_param, sizeof(lib_param), 0, sizeof(lib_param));
    (void)memset_s(&disk_state, sizeof(disk_state), 0, sizeof(disk_state));

    disk_state.loc.did = device_id;
    disk_state.loc.flag = DISK_LOC_DID;  // flag为1 ，表示根据did进行定位
    disk_state.map_type = ADM_RAID_SCSI; // 映射类型当前默认为 SCSI: 0
    disk_state.pf = PF_TYPE_PF0;         // 默认写0

    lib_param.opcode = ADM_RAID_SET;
    lib_param.subopcode = ADM_CMD_SET_DISK_PASSTHRU;
    lib_param.card_id = ctrl_id;
    lib_param.channel = PCIE_PHYSICAL_FUCTION0;
    lib_param.param_len = (guint16)sizeof(struct cmd_disk_passthru);
    errno_t securec_rv = memcpy_s(lib_param.cmd_param, sizeof(lib_param.cmd_param), &disk_state, sizeof(disk_state));
    if (securec_rv != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s failed, ret = %d", __FUNCTION__, securec_rv);
    }

    return process_histore_cmd(&lib_param);
}

/*
 * Description: 设置指定物理盘的固件状态
 */
static gint32 set_state_pd(guint32 ctrl_id, guint16 device_id, guint8 state_param)
{
    struct cmd_show_disk pd_info;
    (void)memset_s(&pd_info, sizeof(pd_info), 0, sizeof(pd_info));
    gint32 ret = get_pd_basic_info(ctrl_id, device_id, &pd_info);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_ERROR, "[%s]: get_pd_basic_info fail ret %x ctrl_id %d device_id %d",
            __FUNCTION__, ret, ctrl_id, device_id);
        return ret;
    }
    guint8 current_state = parse_pd_fw_state(pd_info.logi_status); // 获取当前的状态值
    // 物理盘当前的状态和需要设置的状态一致的时候不需要进行实际的设置动作
    if (current_state == state_param) {
        return SML_SUCCESS;
    }

    if (state_param == PD_STATE_UNCONFIGURED_GOOD && current_state == PD_STATE_ONLINE &&
        (get_ctrl_jbod_enabled(ctrl_id))) {
        ret = set_pd_free_cmd(ctrl_id, device_id); // 设置物理盘为UNCONFIGURED_GOOD的状态
    } else if (state_param == PD_STATE_ONLINE && current_state == PD_STATE_UNCONFIGURED_GOOD &&
        (get_ctrl_jbod_enabled(ctrl_id))) {
        ret = set_state_pd_passthru_cmd(ctrl_id, device_id); // 设置物理盘为RAWDISK模式,ONLINE的状态
    }  else {
        debug_log(DLOG_ERROR, "%s: unknown operation = %d, current_state = %d",
            __FUNCTION__, state_param, current_state);
        return SML_ERR_PD_STATE_UNSUPPORTED_TO_SET;
    }
    // 异常状态的返回值转换
    if (ret == SML_ERR_CTRL_STATUS_INVALID) {
        return SML_ERR_PD_STATE_UNSUPPORTED_TO_SET;
    }

    return ret;
}

/*
 * Description: 设置物理盘巡检开关
 */
static gint32 set_patrolread_pd_cmd(guint32 ctrl_id, guint16 device_id, guint8 patrol_param)
{
    struct lib_cmd_param lib_param;
    struct cmd_set_disk_patrolread patrol_read;
    (void)memset_s(&lib_param, sizeof(lib_param), 0, sizeof(lib_param));
    (void)memset_s(&patrol_read, sizeof(patrol_read), 0, sizeof(patrol_read));

    patrol_read.loc.did = device_id;
    patrol_read.loc.flag = DISK_LOC_DID;
    patrol_read.sw = patrol_param;   // 0-off 关闭， 1-on 打开
    patrol_read.rate = ADM_BGTASK_RATE_LOW; // 1-low, 2-middle, 3-high. 默认为 low
    patrol_read.delay = 0;  // 默认为0

    lib_param.opcode = ADM_RAID_SET;
    lib_param.subopcode = ADM_CMD_SET_DISK_PATROLREAD;
    lib_param.card_id = ctrl_id;
    lib_param.channel = PCIE_PHYSICAL_FUCTION0;
    lib_param.param_len = (guint16)sizeof(struct cmd_set_disk_patrolread);
    errno_t securec_rv = memcpy_s(lib_param.cmd_param, sizeof(lib_param.cmd_param), &patrol_read, sizeof(patrol_read));
    if (securec_rv != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s failed, ret = %d", __FUNCTION__, securec_rv);
    }

    return process_histore_cmd(&lib_param);
}

/*
 * Description: 判断物理盘巡检是否支持
 */
static gint32 is_patrolread_supported(guint32 ctrl_id, struct cmd_show_disk *pd_info, guint16 device_id)
{
    /* 加入巡检开关设置不支持的情景判断:
       1.非成员盘不支持，2.硬盘非HDD介质不支持，3.raid0不支持
       4.热备空闲盘不支持, 5.成员盘为故障盘 */
    if ((pd_info->rg_id == STORAGE_INFO_INVALID_BYTE) || (pd_info->media_type != ADM_DISK_MEDIUM_TYPE_HDD)
        || (pd_info->rg_level == CMD_RAID_LEVEL_RAID0) || (pd_info->logi_status == ADM_PD_STATUS_HOT_SPARE)
        || (pd_info->logi_status == ADM_PD_STATUS_CFG_FAULT)) {
        debug_log(DLOG_ERROR, "%s:unknown operation.", __FUNCTION__);
        return SML_ERR_PD_STATE_UNSUPPORTED_TO_SET;
    }

    // 获取raid组的信息
    struct cmd_rg_info rg_info;
    (void)memset_s(&rg_info, sizeof(rg_info), 0, sizeof(rg_info));
    gint32 ret = get_rg_info(ctrl_id, pd_info->rg_id, &rg_info);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_ERROR, "[%s]: get_rg_info fail ret 0x%x ctrl_id %u device_id %u",
            __FUNCTION__, ret, ctrl_id, device_id);
        return ret;
    }
    // 6. raid组状态fault不支持
    if (rg_info.status == ADM_RAID_STATUS_FAULT) {
        return SML_ERR_PD_STATE_UNSUPPORTED_TO_SET;
    }

    // 遍历raid组所在的逻辑盘的信息
    guint8 i;
    struct cmd_vd_info vd_info;
    for (i = 0; i < rg_info.vd_num; i++) {
        (void)memset_s(&vd_info, sizeof(vd_info), 0, sizeof(vd_info));
        ret = get_vd_info(ctrl_id, rg_info.vd_list[i], &vd_info);
        if (ret != SML_SUCCESS) {
            debug_log(DLOG_ERROR, "[%s]: get_vd_info fail ret 0x%x ctrl_id %u device_id %u",
                __FUNCTION__, ret, ctrl_id, device_id);
            return ret;
        }
        // 7. 逻辑盘状态不为NORMAL不支持
        if (vd_info.vd_status != ADM_LUN_STATUS_NORMAL) {
            return SML_ERR_PD_STATE_UNSUPPORTED_TO_SET;
        }
    }
    return SML_SUCCESS;
}

/*
 * Description: 设置物理盘巡检开关
 */
static gint32 set_patrolread_pd(guint32 ctrl_id, guint16 device_id, guint8 patrol_param)
{
    struct cmd_show_disk pd_info;
    (void)memset_s(&pd_info, sizeof(pd_info), 0, sizeof(pd_info));
    gint32 ret = get_pd_basic_info(ctrl_id, device_id, &pd_info);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_ERROR, "[%s]: get_pd_basic_info fail ret 0x%x ctrl_id %d device_id %d",
            __FUNCTION__, ret, ctrl_id, device_id);
        return ret;
    }
    // 判断当前的巡检状态和设置的值是否一致
    guint8 current_param = ((pd_info.action) & BIT(1)) ? TRUE : FALSE;
    if (patrol_param == current_param) {
        return SML_SUCCESS;
    }

    ret = is_patrolread_supported(ctrl_id, &pd_info, device_id);
    if (ret != SML_SUCCESS) {
        return ret;
    }

    return set_patrolread_pd_cmd(ctrl_id, device_id, patrol_param);
}

/*
 * Description: 物理盘操作函数入口
 */
gint32 histore_pd_operations(guint32 ctrl_id, guint16 device_id, guint8 operation, gpointer param, guint32 param_length)
{
    gint32 ret = SML_ERR_PD_OPERATION_NOT_SUPPORT;

    switch (operation) {
        case PD_OPERATION_LOCATE:
            ret = start_locate_pd(ctrl_id, device_id);
            break;
        case PD_OPERATION_STOP_LOCATE:
            ret = stop_locate_pd(ctrl_id, device_id);
            break;
        case PD_OPERATION_SET_STATE:
            if (param == NULL || param_length != sizeof(SML_PD_STATE_PARAM_S)) {
                return SML_ERR_NULL_DATA;
            }
            SML_PD_STATE_PARAM_S *state_param = (SML_PD_STATE_PARAM_S *)param;
            ret = set_state_pd(ctrl_id, device_id, state_param->state);
            if (ret != SML_SUCCESS) {
                debug_log(DLOG_ERROR, "%s: set pd state %d failed, ret = %d", __FUNCTION__, state_param->state, ret);
            }
            break;
        case PD_OPERATION_SET_BOOTABLE:
            if (param == NULL || param_length != sizeof(guint8)) {
                return SML_ERR_NULL_DATA;
            }
            /* 暂不支持多启动优先级 */
            ret = set_bootable_pd(ctrl_id, device_id, *(guint8 *)param);
            break;
        case PD_OPERATION_SET_DEDICATED_HOTSPARE:
            if (param == NULL || param_length != sizeof(guint16)) {
                return SML_ERR_NULL_DATA;
            }
            guint16 ld_target_id = *((guint16 *)param);
            ret = set_hot_spare(ctrl_id, device_id, operation, ld_target_id);
            break;
        case PD_OPERATION_SET_GLOBAL_HOTSPARE:
            ret = set_hot_spare(ctrl_id, device_id, operation, STORAGE_INFO_INVALID_BYTE);
            break;
        case PD_OPERATION_CANCEL_HOTSPARE:
            ret = cancel_hot_spare(ctrl_id, device_id);
            break;
        case PD_OPERATION_SET_PATROLREAD_STATE:
            if (param == NULL || param_length != sizeof(guint8)) {
                return SML_ERR_NULL_DATA;
            }
            ret = set_patrolread_pd(ctrl_id, device_id, *(guint8 *)param);
            break;
        default:
            debug_log(DLOG_ERROR, "%s: unknown operation = %d", __FUNCTION__, operation);
    }

    return ret;
}

/* 释放为c结构体申请的内存 */
static void free_drive_struct_info(void)
{
    if (drive_info_list_his == NULL) {
        drive_info_list_his_len = 0;
        return;
    }
    
    for (size_t i = 0; i < drive_info_list_his_len; i++) {
        if (drive_info_list_his[i].vendor_name != NULL) {
            g_free(drive_info_list_his[i].vendor_name);
            drive_info_list_his[i].vendor_name = NULL;
        }
    }

    g_free(drive_info_list_his);
    drive_info_list_his = NULL;
    drive_info_list_his_len = 0;
}

/* 为单个结构体变量赋值 */
static gint32 assign_drive_item(Json *array_item, size_t index)
{
    Json *name_obj = NULL;
    Json *id_obj = NULL;
    Json *attr_obj = NULL;
    char *name_val = NULL;
    gint64 id_val = 0;
    gint64 attr_val = 0;
    gint32 ret = SML_SUCCESS;

    ret = (gint32)JsonObjectItemGet(array_item, "vendor_name", &name_obj);
    if (ret != JSON_OK || !JsonIsString(name_obj)) {
        debug_log(DLOG_ERROR, "%s: JSON parse vendor_name failed", __FUNCTION__);
        return SML_ERR_DATA_INVALID;
    }
    JsonItemStringValueGet(name_obj, &name_val);
    drive_info_list_his[index].vendor_name = g_strdup(name_val);
    if (drive_info_list_his[index].vendor_name == NULL) {
        debug_log(DLOG_ERROR, "%s: Memory allocation failed for vendor_name", __FUNCTION__);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    ret = (gint32)JsonObjectItemGet(array_item, "vendor_id", &id_obj);
    if (ret != JSON_OK || !JsonIsInteger(id_obj)) {
        debug_log(DLOG_ERROR, "%s: JSON parse vendor_id failed", __FUNCTION__);
        return SML_ERR_DATA_INVALID;
    }
    JsonItemIntegerValueGet(id_obj, &id_val);
    drive_info_list_his[index].vendor_id = GUINT32_TO_LE((guint32)id_val);

    ret = (gint32)JsonObjectItemGet(array_item, "attr_id_wear", &attr_obj);
    if (ret != JSON_OK || !JsonIsInteger(attr_obj)) {
        debug_log(DLOG_ERROR, "%s: JSON parse attr_id_wear failed", __FUNCTION__);
        return SML_ERR_DATA_INVALID;
    }
    JsonItemIntegerValueGet(attr_obj, &attr_val);
    drive_info_list_his[index].attr_id_wear = GUINT32_TO_LE((guint32)attr_val);

    return SML_SUCCESS;
}

/* 根据传递的字符串生成json数组 */
static gint32 parse_json_str_to_array(const char* json_raw_str, Json **root, guint32 *len)
{
    if (json_raw_str == NULL || root == NULL || len == NULL) {
        debug_log(DLOG_ERROR, "%s: Invalid parameters", __FUNCTION__);
        return SML_ERR_DATA_INVALID;
    }
    
    guint32 ret = JsonParse(json_raw_str, root);
    if (ret != JSON_OK) {
        debug_log(DLOG_ERROR, "%s: JSON parse failed, ret is %d", __FUNCTION__, ret);
        return SML_ERR_DATA_INVALID;
    }

    if (JsonIsArray(*root) != TRUE) {
        debug_log(DLOG_ERROR, "%s: Root is not an array", __FUNCTION__);
        JsonDelete(*root);
        *root = NULL;
        return SML_ERR_DATA_INVALID;
    }

    ret = JsonArraySizeGet(*root, len);
    if (ret != JSON_OK) {
        debug_log(DLOG_ERROR, "%s: Get array size failed", __FUNCTION__);
        JsonDelete(*root);
        *root = NULL;
        return SML_ERR_DATA_INVALID;
    }

    if (*len == 0) {
        debug_log(DLOG_ERROR, "%s: Empty array", __FUNCTION__);
        JsonDelete(*root);
        *root = NULL;
        return SML_ERR_DATA_INVALID;
    }

    return SML_SUCCESS;
}

/* 处理从storage传上来的json字符串 */
gint32 histore_trans_drive_data(const char* json_raw_data)
{
    gint32 ret = SML_SUCCESS;
    Json *json_root = NULL;
    guint32 drive_vendor_len = 0;

    if (json_raw_data == NULL) {
        return SML_ERR_DATA_INVALID;
    }
    free_drive_struct_info();
    ret = parse_json_str_to_array(json_raw_data, &json_root, &drive_vendor_len);
    if (ret != SML_SUCCESS) {
        goto cleanup;
    }

    drive_info_list_his = g_malloc0_n(drive_vendor_len, sizeof(DRIVE_VENDOR_INFO_EXTEND_S));
    if (drive_info_list_his == NULL) {
        debug_log(DLOG_ERROR, "%s: Memory alloc failed for %u items", __FUNCTION__, drive_vendor_len);
        ret = SML_ERR_CANNOT_ALLOC_MEM;
        goto cleanup;
    }
    drive_info_list_his_len = drive_vendor_len;

    for (guint32 i = 0; i < drive_vendor_len; i++) {
        Json *array_item = NULL;
        
        ret = (gint32)JsonArrayItemGet(json_root, i, &array_item);
        if (ret != JSON_OK) {
            goto item_cleanup;
        }

        ret = assign_drive_item(array_item, i);
        if (ret != SML_SUCCESS) {
            goto item_cleanup;
        }
    }

    ret = SML_SUCCESS;
    goto cleanup;

item_cleanup:
    debug_log(DLOG_ERROR, "%s: process json data failed", __FUNCTION__);
    free_drive_struct_info();
cleanup:
    if (json_root != NULL) {
        JsonDelete(json_root);
    }
    return ret;
}