/* 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 <stdio.h>
#include "platform.h"
#include "utils/file_securec.h"
#include "sml.h"
#include "sml_errcodes.h"
#include "pd_log_process.h"
#include "sas_log.h"

#define PD_LOG_SAS_LOG_FILE "SAS_Log"

#define PD_LOG_SAS_TEMPERATURE_LOG_MAX_BYTES 512
#define PD_LOG_SAS_BMS_LOG_MAX_BYTES 512
#define LOG_COLLECT_OK 0
#define LOG_COLLECT_ERR 1
#define LOG_COLLECT_TIMEOUT 2
#define IO_LATENCY_RAW_DATA_BUFF 1568 // 8 * 98(读写时延返回数据每8bytes一组，共计98组，即98个统计档位) * 2(读和写) 单位：字节

/*
 * Description : 收集SAS硬盘的Selftest Log
 * History：2021-01-12  新生成函数
 */
static gint32 pd_log_collect_sas_selftest_log_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    pd_log->SASDevice.selftest.log_type = PD_LOG_SAS_SELF_TEST;
    pd_log->SASDevice.selftest.max_raw_data_size.bytes = PD_LOG_SAS_SELF_TEST_MAX_BYTES;

    // 收集原始数据，如果SCSI命令超时，则不再收集其它的日志
    pd_log_collect_raw_data_from_oob(ctrl_index, pd_device_id, &pd_log->SASDevice.selftest, PD_LOG_COLLECT_TIMEOUT);
    if (pd_log->SASDevice.selftest.result == SML_ERR_PD_SCSI_TIMEOUT) {
        return LOG_COLLECT_TIMEOUT;
    }

    return LOG_COLLECT_OK;
}

/*
 * Description : 收集SAS硬盘的Read Error Count Log
 * History：2021-01-12  新生成函数
 */
static gint32 pd_log_collect_sas_read_error_cnt_log_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    pd_log->SASDevice.read_error_cnt.log_type = PD_LOG_SAS_READ_ERROR_CNT;
    pd_log->SASDevice.read_error_cnt.max_raw_data_size.bytes = PD_LOG_SAS_ERR_COUNT_LOG_MAX_BYTES;

    // 收集原始数据，如果SCSI命令超时，则不再收集其它的日志
    pd_log_collect_raw_data_from_oob(ctrl_index, pd_device_id, &pd_log->SASDevice.read_error_cnt,
        PD_LOG_COLLECT_TIMEOUT);
    if (pd_log->SASDevice.read_error_cnt.result == SML_ERR_PD_SCSI_TIMEOUT) {
        return LOG_COLLECT_TIMEOUT;
    }

    return LOG_COLLECT_OK;
}

/*
 * Description : 收集SAS硬盘的Write Error Count Log
 * History：2021-01-12  新生成函数
 */
static gint32 pd_log_collect_sas_write_error_cnt_log_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    pd_log->SASDevice.write_error_cnt.log_type = PD_LOG_SAS_WRITE_ERROR_CNT;
    pd_log->SASDevice.write_error_cnt.max_raw_data_size.bytes = PD_LOG_SAS_ERR_COUNT_LOG_MAX_BYTES;

    // 收集原始数据，如果SCSI命令超时，则不再收集其它的日志
    pd_log_collect_raw_data_from_oob(ctrl_index, pd_device_id, &pd_log->SASDevice.write_error_cnt,
        PD_LOG_COLLECT_TIMEOUT);
    if (pd_log->SASDevice.write_error_cnt.result == SML_ERR_PD_SCSI_TIMEOUT) {
        return LOG_COLLECT_TIMEOUT;
    }

    return LOG_COLLECT_OK;
}

/*
 * Description : 收集SAS硬盘的Verify Error Count Log
 * History：2021-01-12  新生成函数
 */
static gint32 pd_log_collect_sas_verify_error_cnt_log_from_oob(guint8 ctrl_index, guint16 pd_device_id,
    PD_LOG_S *pd_log)
{
    pd_log->SASDevice.verify_error_cnt.log_type = PD_LOG_SAS_VERIFY_ERROR_CNT;
    pd_log->SASDevice.verify_error_cnt.max_raw_data_size.bytes = PD_LOG_SAS_ERR_COUNT_LOG_MAX_BYTES;

    // 收集原始数据，如果SCSI命令超时，则不再收集其它的日志
    pd_log_collect_raw_data_from_oob(ctrl_index, pd_device_id, &pd_log->SASDevice.verify_error_cnt,
        PD_LOG_COLLECT_TIMEOUT);
    if (pd_log->SASDevice.verify_error_cnt.result == SML_ERR_PD_SCSI_TIMEOUT) {
        return LOG_COLLECT_TIMEOUT;
    }

    return LOG_COLLECT_OK;
}

/*
 * Description : 收集SAS硬盘的Non-medium Error Count Log
 * History：2021-01-12  新生成函数
 */
static gint32 pd_log_collect_sas_nonmedium_error_cnt_log_from_oob(guint8 ctrl_index, guint16 pd_device_id,
    PD_LOG_S *pd_log)
{
    pd_log->SASDevice.nonmedium_error_cnt.log_type = PD_LOG_SAS_NONMEDIUM_ERROR_CNT;
    pd_log->SASDevice.nonmedium_error_cnt.max_raw_data_size.bytes = PD_LOG_SAS_ERR_COUNT_LOG_MAX_BYTES;

    // 收集原始数据，如果SCSI命令超时，则不再收集其它的日志
    pd_log_collect_raw_data_from_oob(ctrl_index, pd_device_id, &pd_log->SASDevice.nonmedium_error_cnt,
        PD_LOG_COLLECT_TIMEOUT);
    if (pd_log->SASDevice.nonmedium_error_cnt.result == SML_ERR_PD_SCSI_TIMEOUT) {
        return LOG_COLLECT_TIMEOUT;
    }

    return LOG_COLLECT_OK;
}

/*
 * Description : 收集SAS硬盘的PHY Error Count Log
 * History：2021-01-12  新生成函数
 */
static gint32 pd_log_collect_sas_phy_error_cnt_log_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    pd_log->SASDevice.phy_error_cnt.log_type = PD_LOG_SAS_PHY_ERROR_CNT;
    pd_log->SASDevice.phy_error_cnt.max_raw_data_size.bytes = PD_LOG_SAS_ERR_COUNT_LOG_MAX_BYTES;

    // 收集原始数据，如果SCSI命令超时，则不再收集其它的日志
    pd_log_collect_raw_data_from_oob(ctrl_index, pd_device_id, &pd_log->SASDevice.phy_error_cnt,
        PD_LOG_COLLECT_TIMEOUT);
    if (pd_log->SASDevice.phy_error_cnt.result == SML_ERR_PD_SCSI_TIMEOUT) {
        return LOG_COLLECT_TIMEOUT;
    }

    return LOG_COLLECT_OK;
}

/*
 * Description : 收集SAS硬盘的Glist
 * History：2021-01-12  新生成函数
 */
static gint32 pd_log_collect_sas_glist_log_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    pd_log->SASDevice.glist.log_type = PD_LOG_SAS_GLIST;
    pd_log->SASDevice.glist.max_raw_data_size.bytes = PD_LOG_SAS_GLIST_MAX_BYTES;

    // 收集原始数据，如果SCSI命令超时，则不再收集其它的日志
    pd_log_collect_raw_data_from_oob(ctrl_index, pd_device_id, &pd_log->SASDevice.glist, PD_LOG_COLLECT_TIMEOUT);
    if (pd_log->SASDevice.glist.result == SML_ERR_PD_SCSI_TIMEOUT) {
        return LOG_COLLECT_TIMEOUT;
    }

    return LOG_COLLECT_OK;
}

/*
 * Description : 收集SAS硬盘的Temperature Log
 * History：2021-01-12  新生成函数
 */
static gint32 pd_log_collect_sas_temperature_log_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    pd_log->SASDevice.temperature.log_type = PD_LOG_SAS_TEMPERATURE;
    pd_log->SASDevice.temperature.max_raw_data_size.bytes = PD_LOG_SAS_TEMPERATURE_LOG_MAX_BYTES;

    // 收集原始数据，如果SCSI命令超时，则不再收集其它的日志
    pd_log_collect_raw_data_from_oob(ctrl_index, pd_device_id, &pd_log->SASDevice.temperature, PD_LOG_COLLECT_TIMEOUT);
    if (pd_log->SASDevice.temperature.result == SML_ERR_PD_SCSI_TIMEOUT) {
        return LOG_COLLECT_TIMEOUT;
    }

    return LOG_COLLECT_OK;
}

/*
 * Description : 收集SAS硬盘的IE Log
 * History：2021-01-12  新生成函数
 */
static gint32 pd_log_collect_sas_ie_log_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    pd_log->SASDevice.ie.log_type = PD_LOG_SAS_INTERNAL_EXCEPTION;
    pd_log->SASDevice.ie.max_raw_data_size.bytes = PD_LOG_SAS_IE_LOG_MAX_BYTES;

    // 收集原始数据，如果SCSI命令超时，则不再收集其它的日志
    pd_log_collect_raw_data_from_oob(ctrl_index, pd_device_id, &pd_log->SASDevice.ie, PD_LOG_COLLECT_TIMEOUT);
    if (pd_log->SASDevice.ie.result == SML_ERR_PD_SCSI_TIMEOUT) {
        return LOG_COLLECT_TIMEOUT;
    }

    return LOG_COLLECT_OK;
}

/*
 * Description : 收集SAS硬盘的BMS Log
 * History：2021-01-12  新生成函数
 */
static gint32 pd_log_collect_sas_bms_log_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    pd_log->SASDevice.bms.log_type = PD_LOG_SAS_BACKGORUN_MEDIA_SCAN;
    pd_log->SASDevice.bms.max_raw_data_size.bytes = PD_LOG_DATA_MAX_LEN;

    // 收集原始数据，如果SCSI命令超时，则不再收集其它的日志
    pd_log_collect_raw_data_from_oob(ctrl_index, pd_device_id, &pd_log->SASDevice.bms, PD_LOG_COLLECT_TIMEOUT);
    if (pd_log->SASDevice.bms.result == SML_ERR_PD_SCSI_TIMEOUT) {
        return LOG_COLLECT_TIMEOUT;
    }

    return LOG_COLLECT_OK;
}

/*
 * Description : 带外SAS盘标准日志
 * Notes：SAS硬盘的solid state media Log, 由于该log的endurance已经在raid信息管理中查询，此处不再收集
 * History：2021-1-12  新生成函数
 */
static gint32 pd_log_collect_sas_standard_log_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    gint32 retval = 0;

    do {
        /* 1. 收集SAS硬盘的Selftest Log */
        retval = pd_log_collect_sas_selftest_log_from_oob(ctrl_index, pd_device_id, pd_log);
        if (retval != LOG_COLLECT_OK) {
            break;
        }

        /* 2. 收集SAS硬盘的Read Error Count Log */
        retval = pd_log_collect_sas_read_error_cnt_log_from_oob(ctrl_index, pd_device_id, pd_log);
        if (retval != LOG_COLLECT_OK) {
            break;
        }

        /* 3. 收集SAS硬盘的Write Error Count Log */
        retval = pd_log_collect_sas_write_error_cnt_log_from_oob(ctrl_index, pd_device_id, pd_log);
        if (retval != LOG_COLLECT_OK) {
            break;
        }

        /* 4. 收集SAS硬盘的Verify Error Count Log */
        retval = pd_log_collect_sas_verify_error_cnt_log_from_oob(ctrl_index, pd_device_id, pd_log);
        if (retval != LOG_COLLECT_OK) {
            break;
        }

        /* 5. 收集SAS硬盘的Non-medium Error Count Log */
        retval = pd_log_collect_sas_nonmedium_error_cnt_log_from_oob(ctrl_index, pd_device_id, pd_log);
        if (retval != LOG_COLLECT_OK) {
            break;
        }

        /* 6. 收集SAS硬盘的PHY Error Count Log */
        retval = pd_log_collect_sas_phy_error_cnt_log_from_oob(ctrl_index, pd_device_id, pd_log);
        if (retval != LOG_COLLECT_OK) {
            break;
        }

        /* 7. 收集SAS硬盘的Glist */
        retval = pd_log_collect_sas_glist_log_from_oob(ctrl_index, pd_device_id, pd_log);
        if (retval != LOG_COLLECT_OK) {
            break;
        }

        /* 8. 收集SAS硬盘的Temperature Log */
        retval = pd_log_collect_sas_temperature_log_from_oob(ctrl_index, pd_device_id, pd_log);
        if (retval != LOG_COLLECT_OK) {
            break;
        }

        /* 9. 收集SAS硬盘的IE Log */
        retval = pd_log_collect_sas_ie_log_from_oob(ctrl_index, pd_device_id, pd_log);
        if (retval != LOG_COLLECT_OK) {
            break;
        }

        /* 10. 收集SAS硬盘的BMS Log */
        retval = pd_log_collect_sas_bms_log_from_oob(ctrl_index, pd_device_id, pd_log);
        if (retval != LOG_COLLECT_OK) {
            break;
        }
    } while (0);

    return retval;
}

/*
 * Description : 带外获取单个SAS盘厂商General Statistics and Performance Log
 * History：2020-11-18  新生成函数
 */
static gint32 pd_log_collect_sas_gsp_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    pd_log->SASDevice.general_statistics.log_type = PD_LOG_SAS_GENERAL_STATISTICS;
    pd_log->SASDevice.general_statistics.max_raw_data_size.bytes = PD_LOG_DATA_MAX_LEN;
    pd_log_collect_raw_data_from_oob(ctrl_index, pd_device_id, &pd_log->SASDevice.general_statistics,
        PD_LOG_COLLECT_TIMEOUT);
    if (pd_log->SASDevice.general_statistics.result == SML_ERR_PD_SCSI_TIMEOUT) {
        return LOG_COLLECT_TIMEOUT;
    }

    return LOG_COLLECT_OK;
}

/*
 * Description : 带外获取huawei SAS SSD Vendor specific log (32h)
 * History：2020-11-18  新生成函数
 */
static gint32 pd_log_collect_huawei_sas_specific32h_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    pd_log->SASDevice.huawei_specific32h.log_type = PD_LOG_SAS_HUAWEI_SPECIFIC32H;
    pd_log->SASDevice.huawei_specific32h.max_raw_data_size.bytes = PD_LOG_DATA_MAX_LEN;
    pd_log_collect_raw_data_from_oob(ctrl_index, pd_device_id, &pd_log->SASDevice.huawei_specific32h,
        PD_LOG_COLLECT_TIMEOUT);
    if (pd_log->SASDevice.huawei_specific32h.result == SML_ERR_PD_SCSI_TIMEOUT) {
        return LOG_COLLECT_TIMEOUT;
    }

    return LOG_COLLECT_OK;
}

/*
 * Description : 带外获取huawei SAS SSD Vendor specific log (34h)
 * History：2020-11-18  新生成函数
 */
static gint32 pd_log_collect_huawei_sas_specific34h_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    pd_log->SASDevice.huawei_specific34h.log_type = PD_LOG_SAS_HUAWEI_SPECIFIC34H;
    pd_log->SASDevice.huawei_specific34h.max_raw_data_size.bytes = PD_LOG_DATA_MAX_LEN;
    pd_log_collect_raw_data_from_oob(ctrl_index, pd_device_id, &pd_log->SASDevice.huawei_specific34h,
        PD_LOG_COLLECT_TIMEOUT);
    if (pd_log->SASDevice.huawei_specific34h.result == SML_ERR_PD_SCSI_TIMEOUT) {
        return LOG_COLLECT_TIMEOUT;
    }

    return LOG_COLLECT_OK;
}

/*
 * Description : 带外获取huawei SAS SSD Vendor specific log (35h)
 * History：2020-11-18  新生成函数
 */
static gint32 pd_log_collect_huawei_sas_specific35h_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    pd_log->SASDevice.huawei_specific35h.log_type = PD_LOG_SAS_HUAWEI_SPECIFIC35H;
    pd_log->SASDevice.huawei_specific35h.max_raw_data_size.bytes = PD_LOG_DATA_MAX_LEN;
    pd_log_collect_raw_data_from_oob(ctrl_index, pd_device_id, &pd_log->SASDevice.huawei_specific35h,
        PD_LOG_COLLECT_TIMEOUT);
    if (pd_log->SASDevice.huawei_specific35h.result == SML_ERR_PD_SCSI_TIMEOUT) {
        return LOG_COLLECT_TIMEOUT;
    }

    return LOG_COLLECT_OK;
}

/*
 * Description : 带外获取huawei SAS SSD IO Info日志信息
 * History：2020-11-18  新生成函数
 */
static gint32 pd_log_collect_huawei_sas_io_info_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    pd_log->SASDevice.huawei_io_info.log_type = PD_LOG_SAS_HUAWEI_IO_INFO;
    pd_log->SASDevice.huawei_io_info.max_raw_data_size.bytes = PD_LOG_DATA_MAX_LEN;
    pd_log_collect_raw_data_from_oob(ctrl_index, pd_device_id, &pd_log->SASDevice.huawei_io_info,
        PD_LOG_COLLECT_TIMEOUT);
    if (pd_log->SASDevice.huawei_io_info.result == SML_ERR_PD_SCSI_TIMEOUT) {
        return LOG_COLLECT_TIMEOUT;
    }

    return LOG_COLLECT_OK;
}

/*
 * Description : 带外获取huawei SAS SSD自定义日志
 * History：2020-10-27  新生成函数
 */
static gint32 pd_log_collect_huawei_sas_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    gint32 retval;
    do {
        /* 收集General Statistics and Performance Log */
        retval = pd_log_collect_sas_gsp_from_oob(ctrl_index, pd_device_id, pd_log);
        if (retval != LOG_COLLECT_OK) {
            break;
        }

        /* 收集Vendor specific log (32h) */
        retval = pd_log_collect_huawei_sas_specific32h_from_oob(ctrl_index, pd_device_id, pd_log);
        if (retval != LOG_COLLECT_OK) {
            break;
        }

        /* 收集Vendor specific log (34h) */
        retval = pd_log_collect_huawei_sas_specific34h_from_oob(ctrl_index, pd_device_id, pd_log);
        if (retval != LOG_COLLECT_OK) {
            break;
        }

        /* 收集Vendor specific log (35h) */
        retval = pd_log_collect_huawei_sas_specific35h_from_oob(ctrl_index, pd_device_id, pd_log);
        if (retval != LOG_COLLECT_OK) {
            break;
        }

        /* 收集IO Info */
        retval = pd_log_collect_huawei_sas_io_info_from_oob(ctrl_index, pd_device_id, pd_log);
        if (retval != LOG_COLLECT_OK) {
            break;
        }
    } while (0);

    return retval;
}

/*
 * Description : 带外获取kioxia SSD Specific Log
 * History：2020-11-18  新生成函数
 */
static gint32 pd_log_collect_kioxia_sas_ssd_specific_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    pd_log->SASDevice.kioxia_ssd_specific.log_type = PD_LOG_SAS_KIOXIA_SSD_SPECIFIC;
    pd_log->SASDevice.kioxia_ssd_specific.max_raw_data_size.bytes = PD_LOG_DATA_MAX_LEN;
    pd_log_collect_raw_data_from_oob(ctrl_index, pd_device_id, &pd_log->SASDevice.kioxia_ssd_specific,
        PD_LOG_COLLECT_TIMEOUT);
    if (pd_log->SASDevice.kioxia_ssd_specific.result == SML_ERR_PD_SCSI_TIMEOUT) {
        return LOG_COLLECT_TIMEOUT;
    }

    return LOG_COLLECT_OK;
}

/*
 * Description : 带外获取kioxia Endurance, Over Provisioning, Throttling Log
 * History：2020-11-18  新生成函数
 */
static gint32 pd_log_collect_kioxia_sas_eopt_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    pd_log->SASDevice.kioxia_eopt.log_type = PD_LOG_SAS_KIOXIA_EOPT;
    pd_log->SASDevice.kioxia_eopt.max_raw_data_size.bytes = PD_LOG_DATA_MAX_LEN;
    pd_log_collect_raw_data_from_oob(ctrl_index, pd_device_id, &pd_log->SASDevice.kioxia_eopt, PD_LOG_COLLECT_TIMEOUT);
    if (pd_log->SASDevice.kioxia_eopt.result == SML_ERR_PD_SCSI_TIMEOUT) {
        return LOG_COLLECT_TIMEOUT;
    }

    return LOG_COLLECT_OK;
}

/*
 * Description : 带外获取kioxia SMART data Log
 * History：2020-11-18  新生成函数
 */
static gint32 pd_log_collect_kioxia_sas_smart_data_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    pd_log->SASDevice.kioxia_smart_data.log_type = PD_LOG_SAS_KIOXIA_SMART_DATA;
    pd_log->SASDevice.kioxia_smart_data.max_raw_data_size.bytes = PD_LOG_DATA_MAX_LEN;
    pd_log_collect_raw_data_from_oob(ctrl_index, pd_device_id, &pd_log->SASDevice.kioxia_smart_data,
        PD_LOG_COLLECT_TIMEOUT);
    if (pd_log->SASDevice.kioxia_smart_data.result == SML_ERR_PD_SCSI_TIMEOUT) {
        return LOG_COLLECT_TIMEOUT;
    }

    return LOG_COLLECT_OK;
}

/*
 * Description : 带外获取kioxia SAS SSD自定义日志
 * History：2020-10-27  新生成函数
 */
static gint32 pd_log_collect_kioxia_sas_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    gint32 retval;
    do {
        /* 收集General Statistics and Performance Log */
        retval = pd_log_collect_sas_gsp_from_oob(ctrl_index, pd_device_id, pd_log);
        if (retval != LOG_COLLECT_OK) {
            break;
        }

        /* 收集SSD Specific Log */
        retval = pd_log_collect_kioxia_sas_ssd_specific_from_oob(ctrl_index, pd_device_id, pd_log);
        if (retval != LOG_COLLECT_OK) {
            break;
        }

        /* 收集Endurance, Over Provisioning, Throttling Log */
        retval = pd_log_collect_kioxia_sas_eopt_from_oob(ctrl_index, pd_device_id, pd_log);
        if (retval != LOG_COLLECT_OK) {
            break;
        }

        /* 收集SMART data Log */
        retval = pd_log_collect_kioxia_sas_smart_data_from_oob(ctrl_index, pd_device_id, pd_log);
        if (retval != LOG_COLLECT_OK) {
            break;
        }
    } while (0);

    return retval;
}

/*
 * Description : 带外获取单个SAS盘厂商自定义日志
 * History：2020-10-27  新生成函数
 */
static gint32 pd_log_collect_sas_vendor_log_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    gint32 retval = RET_OK;

    // RAMAXEL和UMIS 与HUAWEI协议一致
    if (strstr(pd_log->pd_manufacturer, PD_VENDOR_NAME_HUAWEI) != NULL ||
        strstr(pd_log->pd_manufacturer, PD_VENDOR_NAME_RAMAXEL) != NULL ||
        strstr(pd_log->pd_manufacturer, PD_VENDOR_NAME_UMIS) != NULL) {
        retval = pd_log_collect_huawei_sas_from_oob(ctrl_index, pd_device_id, pd_log);
    } else if (strstr(pd_log->pd_manufacturer, PD_VENDOR_NAME_KIOXIA) != NULL) {
        retval = pd_log_collect_kioxia_sas_from_oob(ctrl_index, pd_device_id, pd_log);
    }

    return retval;
}

/*
 * Description: 带外获取单个SAS盘的日志
 * 1. 收集原始数据，如果SCSI命令超时，则不再收集其它的日志;
 * 2. 每收集一种日志，检查系统是否发生重启或下电，如果是，则终止本次收集;
 * History: 1.2018年1月9日
 * 新生成函数
 * 2.2018年9月15日,
 * 添加调用pd_log_collect_raw_data_from_obb函数的超时参数
 */
gint32 pd_log_collect_sas_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_S *pd_log)
{
    gint32 retval = 0;

    do {
        retval = pd_log_collect_sas_standard_log_from_oob(ctrl_index, pd_device_id, pd_log);
        if (retval != LOG_COLLECT_OK) {
            break;
        }

        // SAS SSD
        if (pd_log->pd_media_type == PD_MEDIA_TYPE_SSD) {
            /* 收集SAS SSD硬盘的自定义Log */
            retval = pd_log_collect_sas_vendor_log_from_oob(ctrl_index, pd_device_id, pd_log);
            if (retval != LOG_COLLECT_OK) {
                break;
            }
        }
    } while (0);

    if (retval == LOG_COLLECT_ERR) {
        return RET_ERR;
    } else {
        return RET_OK;
    }
}

/*
 * Description : 处理huawei SAS SSD数据
 * History：2020-10-27  新生成函数
 */
static void pd_log_handle_huawei_sas_ssd(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *pd_log_jso)
{
    gint32 ret;
    Json *vendor_log_json = NULL;

    g_fprintf(file, "\nGeneral Statistics and Performance log:\n");
    ret = pd_log_check_raw_data(file, pd_log->SASDevice.general_statistics.result,
        pd_log->SASDevice.general_statistics.scsi_status_code, pd_log->SASDevice.general_statistics.data,
        pd_log->SASDevice.general_statistics.data_length, PD_LOG_COLLECT_TIMEOUT);
    if (ret == RET_OK) {
        pd_log_handle_sas_general_statistics(file, pd_log, out_put, pd_log_jso);
    }

    if (JsonObjectCreate(&vendor_log_json) != JSON_OK) {
        return;
    }

    g_fprintf(file, "\nVendor Specific log(32h):\n");
    ret = pd_log_check_raw_data(file, pd_log->SASDevice.huawei_specific32h.result,
        pd_log->SASDevice.huawei_specific32h.scsi_status_code, pd_log->SASDevice.huawei_specific32h.data,
        pd_log->SASDevice.huawei_specific32h.data_length, PD_LOG_COLLECT_TIMEOUT);
    if (ret == RET_OK) {
        pd_log_handle_sas_huawei_specific32h(file, pd_log, out_put, vendor_log_json);
    }

    g_fprintf(file, "\nVendor Specific log(34h):\n");
    ret = pd_log_check_raw_data(file, pd_log->SASDevice.huawei_specific34h.result,
        pd_log->SASDevice.huawei_specific34h.scsi_status_code, pd_log->SASDevice.huawei_specific34h.data,
        pd_log->SASDevice.huawei_specific34h.data_length, PD_LOG_COLLECT_TIMEOUT);
    if (ret == RET_OK) {
        pd_log_handle_sas_huawei_specific34h(file, pd_log, out_put, vendor_log_json);
    }

    g_fprintf(file, "\nVendor Specific log(35h):\n");
    ret = pd_log_check_raw_data(file, pd_log->SASDevice.huawei_specific35h.result,
        pd_log->SASDevice.huawei_specific35h.scsi_status_code, pd_log->SASDevice.huawei_specific35h.data,
        pd_log->SASDevice.huawei_specific35h.data_length, PD_LOG_COLLECT_TIMEOUT);
    if (ret == RET_OK) {
        pd_log_handle_sas_huawei_specific35h(file, pd_log, out_put, vendor_log_json);
    }

    g_fprintf(file, "\nDisk Io Info:\n");
    ret = pd_log_check_raw_data(file, pd_log->SASDevice.huawei_io_info.result,
        pd_log->SASDevice.huawei_io_info.scsi_status_code, pd_log->SASDevice.huawei_io_info.data,
        pd_log->SASDevice.huawei_io_info.data_length, PD_LOG_COLLECT_TIMEOUT);
    if (ret == RET_OK) {
        pd_log_handle_sas_huawei_io_info(file, pd_log, out_put, vendor_log_json);
    }
    JsonObjectItemSet(pd_log_jso, "vendor_specific_log", vendor_log_json);

    return;
}

/*
 * Description : 处理kioxia SAS SSD数据
 * History：2020-11-18  新生成函数
 */
static void pd_log_handle_kioxia_sas_ssd(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *pd_log_jso)
{
    gint32 ret;
    g_fprintf(file, "\nGeneral Statistics and Performance log:\n");
    ret = pd_log_check_raw_data(file, pd_log->SASDevice.general_statistics.result,
        pd_log->SASDevice.general_statistics.scsi_status_code, pd_log->SASDevice.general_statistics.data,
        pd_log->SASDevice.general_statistics.data_length, PD_LOG_COLLECT_TIMEOUT);
    if (ret == RET_OK) {
        pd_log_handle_sas_general_statistics(file, pd_log, out_put, pd_log_jso);
    }
    Json *vendor_log_json = NULL;
    if (JsonObjectCreate(&vendor_log_json) != JSON_OK) {
        return;
    }

    g_fprintf(file, "\nSSD Specific log:\n");
    ret = pd_log_check_raw_data(file, pd_log->SASDevice.kioxia_ssd_specific.result,
        pd_log->SASDevice.kioxia_ssd_specific.scsi_status_code, pd_log->SASDevice.kioxia_ssd_specific.data,
        pd_log->SASDevice.kioxia_ssd_specific.data_length, PD_LOG_COLLECT_TIMEOUT);
    if (ret == RET_OK) {
        pd_log_handle_sas_kioxia_ssd_specific(file, pd_log, out_put, vendor_log_json);
    }

    g_fprintf(file, "\nEndurance，Over Provisioning，Throttling Log:\n");
    ret = pd_log_check_raw_data(file, pd_log->SASDevice.kioxia_eopt.result,
        pd_log->SASDevice.kioxia_eopt.scsi_status_code, pd_log->SASDevice.kioxia_eopt.data,
        pd_log->SASDevice.kioxia_eopt.data_length, PD_LOG_COLLECT_TIMEOUT);
    if (ret == RET_OK) {
        pd_log_handle_sas_kioxia_eopt(file, pd_log, out_put, vendor_log_json);
    }

    g_fprintf(file, "\nSMART data log:\n");
    ret = pd_log_check_raw_data(file, pd_log->SASDevice.kioxia_smart_data.result,
        pd_log->SASDevice.kioxia_smart_data.scsi_status_code, pd_log->SASDevice.kioxia_smart_data.data,
        pd_log->SASDevice.kioxia_smart_data.data_length, PD_LOG_COLLECT_TIMEOUT);
    if (ret == RET_OK) {
        pd_log_handle_sas_kioxia_smart_data(file, pd_log, out_put, vendor_log_json);
    }

    JsonObjectItemSet(pd_log_jso, "vendor_specific_log", vendor_log_json);

    return;
}

/*
 * Description : 处理SAS SSD数据
 * History：2020-10-27  新生成函数
 */
static void pd_log_handle_sas_ssd(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *pd_log_jso)
{
    g_fprintf(file, "\nsolid state media log:\n");
    pd_log_handle_sas_solid_state_media(file, pd_log, out_put, pd_log_jso);

    // RAMAXEL和UMIS 与HUAWEI协议一致
    if (strstr(pd_log->pd_manufacturer, PD_VENDOR_NAME_HUAWEI) != NULL ||
        strstr(pd_log->pd_manufacturer, PD_VENDOR_NAME_RAMAXEL) != NULL ||
        strstr(pd_log->pd_manufacturer, PD_VENDOR_NAME_UMIS) != NULL) {
        pd_log_handle_huawei_sas_ssd(file, pd_log, out_put, pd_log_jso);
    } else if (strstr(pd_log->pd_manufacturer, PD_VENDOR_NAME_KIOXIA) != NULL) {
        pd_log_handle_kioxia_sas_ssd(file, pd_log, out_put, pd_log_jso);
    }

    return;
}

/*
 * Description : 处理从带外收集的SAS盘各种error日志数据，包括解析并输出到日志文件
 * History：2021-1-12  新生成函数
 */
static void pd_log_handle_sas_error_cnt_from_oob(FILE *file, PD_LOG_S *pd_log, Json *pd_log_jso)
{
    gint32 ret;

    g_fprintf(file, "\nError Count (Read/Write/Verify/Non-medium):\n");
    (void)pd_log_check_raw_data(file, pd_log->SASDevice.read_error_cnt.result,
        pd_log->SASDevice.read_error_cnt.scsi_status_code, pd_log->SASDevice.read_error_cnt.data,
        pd_log->SASDevice.read_error_cnt.data_length, PD_LOG_COLLECT_TIMEOUT);

    (void)pd_log_check_raw_data(file, pd_log->SASDevice.write_error_cnt.result,
        pd_log->SASDevice.write_error_cnt.scsi_status_code, pd_log->SASDevice.write_error_cnt.data,
        pd_log->SASDevice.write_error_cnt.data_length, PD_LOG_COLLECT_TIMEOUT);

    (void)pd_log_check_raw_data(file, pd_log->SASDevice.verify_error_cnt.result,
        pd_log->SASDevice.verify_error_cnt.scsi_status_code, pd_log->SASDevice.verify_error_cnt.data,
        pd_log->SASDevice.verify_error_cnt.data_length, PD_LOG_COLLECT_TIMEOUT);

    (void)pd_log_check_raw_data(file, pd_log->SASDevice.nonmedium_error_cnt.result,
        pd_log->SASDevice.nonmedium_error_cnt.scsi_status_code, pd_log->SASDevice.nonmedium_error_cnt.data,
        pd_log->SASDevice.nonmedium_error_cnt.data_length, PD_LOG_COLLECT_TIMEOUT);
    pd_log_handle_sas_error_cnt(file, pd_log, NULL, pd_log_jso);

    g_fprintf(file, "\nPHY Error Count:\n");
    ret = pd_log_check_raw_data(file, pd_log->SASDevice.phy_error_cnt.result,
        pd_log->SASDevice.phy_error_cnt.scsi_status_code, pd_log->SASDevice.phy_error_cnt.data,
        pd_log->SASDevice.phy_error_cnt.data_length, PD_LOG_COLLECT_TIMEOUT);
    if (ret == RET_OK) {
        pd_log_handle_sas_phy_error_cnt(file, pd_log, NULL, pd_log_jso);
    }

    return;
}

/*
 * Description : 处理从带外收集的SAS盘日志数据，包括解析并输出到日志文件
 * History：2021-1-12  新生成函数
 */
static void pd_log_handle_sas_from_oob(FILE *file, PD_LOG_S *pd_log, Json *pd_log_jso)
{
    gint32 ret;

    g_fprintf(file, "\nSelf Test:\n");
    ret = pd_log_check_raw_data(file, pd_log->SASDevice.selftest.result, pd_log->SASDevice.selftest.scsi_status_code,
        pd_log->SASDevice.selftest.data, pd_log->SASDevice.selftest.data_length, PD_LOG_COLLECT_TIMEOUT);
    if (ret == RET_OK) {
        pd_log_handle_sas_self_test(file, pd_log, NULL, pd_log_jso);
    }

    pd_log_handle_sas_error_cnt_from_oob(file, pd_log, pd_log_jso);

    g_fprintf(file, "\nGList:\n");
    ret = pd_log_check_raw_data(file, pd_log->SASDevice.glist.result, pd_log->SASDevice.glist.scsi_status_code,
        pd_log->SASDevice.glist.data, pd_log->SASDevice.glist.data_length, PD_LOG_COLLECT_TIMEOUT);
    if (ret == RET_OK) {
        pd_log_handle_sas_glist(file, pd_log, NULL, pd_log_jso);
    }

    g_fprintf(file, "\nTemperature Log:\n");
    ret = pd_log_check_raw_data(file, pd_log->SASDevice.temperature.result,
        pd_log->SASDevice.temperature.scsi_status_code, pd_log->SASDevice.temperature.data,
        pd_log->SASDevice.temperature.data_length, PD_LOG_COLLECT_TIMEOUT);
    if (ret == RET_OK) {
        pd_log_handle_sas_temperature(file, pd_log, NULL, pd_log_jso);
    }

    g_fprintf(file, "\nInformational Exceptions Log:\n");
    ret = pd_log_check_raw_data(file, pd_log->SASDevice.ie.result, pd_log->SASDevice.ie.scsi_status_code,
        pd_log->SASDevice.ie.data, pd_log->SASDevice.ie.data_length, PD_LOG_COLLECT_TIMEOUT);
    if (ret == RET_OK) {
        pd_log_handle_sas_ie_log(file, pd_log, NULL, pd_log_jso);
    }

    g_fprintf(file, "\nBackground Medium Scan Results:\n");
    ret = pd_log_check_raw_data(file, pd_log->SASDevice.bms.result, pd_log->SASDevice.bms.scsi_status_code,
        pd_log->SASDevice.bms.data, pd_log->SASDevice.bms.data_length, PD_LOG_COLLECT_TIMEOUT);
    if (ret == RET_OK) {
        pd_log_handle_sas_bms(file, pd_log, NULL, pd_log_jso);
    }

    // SAS SSD
    if (pd_log->pd_media_type == PD_MEDIA_TYPE_SSD) {
        pd_log_handle_sas_ssd(file, pd_log, NULL, pd_log_jso);
    }

    return;
}

/*
 * Description : 处理SAS盘的日志数据，包括解析并输出到日志文件
 * History：2018年1月10日 新生成函数
 * 2018年5月22日 AR.SR.SFEA02130924.009.003 oob获取日志解析并删除原始数据打印
 * 2018年9月20日  AR.SR.SFEA02130924.009.007 添加pd_log_check_raw_data的超时参数
 * 2021年1月12日   SAS SSD日志数据采集
 */
void pd_log_handle_sas(PD_LOG_S *pd_log, Json *pd_log_jso)
{
    gint32 iRet = -1;
    gchar log_file[MAX_FILEPATH_LENGTH] = {0};
    FILE *fp_w = NULL;
    struct stat file_stat;

    if (pd_log == NULL || pd_log_jso == NULL) {
        return;
    }

    /* 将DeviceName中的空格删除 */
    string_clear_blank(pd_log->pd_device_name, sizeof(pd_log->pd_device_name));

    /* 检查硬盘日志的路径 */
    if (pd_log_check_file_path(pd_log->pd_device_name) == RET_ERR) {
        debug_log(DLOG_ERROR, "Handle physical drive log failed, the log path is not exist.");
        return;
    }

    iRet = snprintf_s(log_file, sizeof(log_file), sizeof(log_file) - 1, "%s/%s/%s", PD_LOG_BASE_PATH,
        pd_log->pd_device_name, PD_LOG_SAS_LOG_FILE);
    if (iRet <= 0) {
        debug_log(DLOG_ERROR, "%s: snprintf_s fail, ret = %d", __FUNCTION__, iRet);
    }
    if (stat_s(log_file, &file_stat) >= 0) {
        check_log_file_rotate(log_file, NULL, pd_log->log_rotate_num);
    }

    fp_w = fopen_s(log_file, "w+", log_file);
    if (fp_w == NULL) {
        debug_log(DLOG_ERROR, "Open physical drive log file failed.");
        return;
    }

    (void)fchmod(fileno(fp_w), 0640);

    pd_log_write_header(fp_w, pd_log);

    (void)fflush(fp_w);
    (void)fsync(fileno(fp_w));

    if (pd_log->pd_power_state != PD_POWER_STATE_ACTIVE) {
        g_fprintf(fp_w, "The drive is not active.\n");
        (void)fclose_s(fp_w);
        return;
    }

    // 解析数据
    pd_log_handle_sas_from_oob(fp_w, pd_log, pd_log_jso);

    (void)fflush(fp_w);
    (void)fsync(fileno(fp_w));
    (void)fclose_s(fp_w);

    return;
}

/*
 * Description : 带外获取huawei SAS SSD Vendor write latency log (35h)
 */
static gint32 collect_huawei_write_latency_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_NEW_S *pd_log)
{
    pd_log->SASDevice.write_latency_statistics.log_type = PD_LOG_SAS_WRITE_LATENCY_STATISTICS;
    pd_log->SASDevice.write_latency_statistics.max_raw_data_size.bytes = PD_LOG_DATA_MAX_LEN;
    pd_log_collect_raw_data_from_oob(ctrl_index, pd_device_id, &pd_log->SASDevice.write_latency_statistics,
        PD_LOG_COLLECT_TIMEOUT);
    debug_log(DLOG_DEBUG, "%s: collect write latency statistics from oob data_length: %u result: 0x%X", __FUNCTION__,
        pd_log->SASDevice.write_latency_statistics.data_length, pd_log->SASDevice.write_latency_statistics.result);
    if (pd_log->SASDevice.write_latency_statistics.result != SML_SUCCESS ||
        pd_log->SASDevice.write_latency_statistics.data_length == 0) {
        debug_log(DLOG_ERROR, "%s: collect write latency statistics from oob failed", __FUNCTION__);
        return LOG_COLLECT_ERR;
    }
    return LOG_COLLECT_OK;
}

/*
 * Description : 带外获取huawei SAS SSD Vendor read latency log (35h)
 */
static gint32 collect_huawei_read_latency_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_NEW_S *pd_log)
{
    pd_log->SASDevice.read_latency_statistics.log_type = PD_LOG_SAS_READ_LATENCY_STATISTICS;
    pd_log->SASDevice.read_latency_statistics.max_raw_data_size.bytes = PD_LOG_DATA_MAX_LEN;
    pd_log_collect_raw_data_from_oob(ctrl_index, pd_device_id, &pd_log->SASDevice.read_latency_statistics,
        PD_LOG_COLLECT_TIMEOUT);
    debug_log(DLOG_INFO, "%s: collect read latency statistics from oob data_length: %u result: 0x%X", __FUNCTION__,
        pd_log->SASDevice.read_latency_statistics.data_length, pd_log->SASDevice.read_latency_statistics.result);
    if (pd_log->SASDevice.read_latency_statistics.result != SML_SUCCESS ||
        pd_log->SASDevice.read_latency_statistics.data_length == 0) {
        debug_log(DLOG_ERROR, "%s: collect read latency statistics from oob failed", __FUNCTION__);
        return LOG_COLLECT_ERR;
    }
    return LOG_COLLECT_OK;
}

gint32 pd_log_collect_read_io_latency_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_NEW_S *pd_log)
{
    if (pd_log == NULL) {
        return RET_ERR;
    }
    // 硬盘介质仅支持SSD，厂商仅支持华为
    if (pd_log->pd_media_type != PD_MEDIA_TYPE_SSD || strstr(pd_log->pd_manufacturer, PD_VENDOR_NAME_HUAWEI) == NULL) {
        return RET_ERR;
    }
    gint32 ret = collect_huawei_read_latency_from_oob(ctrl_index, pd_device_id, pd_log);
    if (ret != RET_OK) {
        return ret;
    }
    return ret;
}

gint32 pd_log_collect_write_io_latency_from_oob(guint8 ctrl_index, guint16 pd_device_id, PD_LOG_NEW_S *pd_log)
{
    if (pd_log == NULL) {
        return RET_ERR;
    }
    // 硬盘介质仅支持SSD，厂商仅支持华为
    if (pd_log->pd_media_type != PD_MEDIA_TYPE_SSD || strstr(pd_log->pd_manufacturer, PD_VENDOR_NAME_HUAWEI) == NULL) {
        return RET_ERR;
    }
    gint32 ret = collect_huawei_write_latency_from_oob(ctrl_index, pd_device_id, pd_log);
    if (ret != RET_OK) {
        return ret;
    }
    return ret;
}