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

#include <dlfcn.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/time.h>
#include "platform.h"
#include "sml_errcodes.h"
#include "sml.h"
#include "sml_common.h"

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

#include "sl.h"
#include "sl_pd_log.h"

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

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

#include <errno.h>

typedef gint32 (*PD_LOG_COLLECT_FUNC)(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *attribute);

typedef struct tag_pd_log_collect_func {
    SML_PD_LOG_TYPE_E log_type;
    PD_LOG_COLLECT_FUNC func;
} pd_log_collect_func;

/*
 * Description: 通过SCSI passthru获取SATA SMART Attribute
 * History: 2018年1月5日  新生成函数
*/
static gint32 GetSataDeviceSmartAttribute(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *attribute)
{
    gint32 retval = SML_SUCCESS;
    SL_SCSI_PASSTHRU_T *scsi_passthru_cmd = NULL;
    guint32 smart_attribute_len = 0;
    guint32 pscsi_passthru_len = 0;
    guint16 block_size = 0;

    if (NULL == pd || NULL == attribute) {
        return SML_ERR_NULL_DATA;
    }

    attribute->result = SML_SUCCESS;
    attribute->scsi_status_code = SCSI_STATUS_SUCCESS;
    attribute->data_length = 0;
    attribute->data = NULL;

    /* 直接读取一个sector大小的数据 */
    block_size = pd->pdinfo.block_size;
    if (PD_BLOCK_SIZE_512 != block_size && PD_BLOCK_SIZE_4K != block_size) {
        block_size = PD_BLOCK_SIZE_512;
    }

    smart_attribute_len = attribute->max_raw_data_size.sectors * block_size;

    pscsi_passthru_len = (guint32)sizeof(SL_SCSI_PASSTHRU_T) + smart_attribute_len;

    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(pscsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI;
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->dir = SL_DIR_READ;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT;
    scsi_passthru_cmd->cdbLength = 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[5] = (attribute->max_raw_data_size.sectors >> 8) & 0xFF; // 默认为0x01
    scsi_passthru_cmd->cdb[6] = attribute->max_raw_data_size.sectors & 0xFF;        // 默认为0x01
    scsi_passthru_cmd->cdb[7] = 0x00;
    scsi_passthru_cmd->cdb[8] = 0x01;
    scsi_passthru_cmd->cdb[9] = 0x00;
    scsi_passthru_cmd->cdb[10] = 0x4f;
    scsi_passthru_cmd->cdb[11] = 0x00;
    scsi_passthru_cmd->cdb[12] = 0xc2;
    scsi_passthru_cmd->cdb[13] = 0xa0;
    scsi_passthru_cmd->cdb[14] = 0xb0;
    scsi_passthru_cmd->cdb[15] = 0x00;
    scsi_passthru_cmd->dataSize = smart_attribute_len;

    retval = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_DEBUG,
            "Get SATA Device SMART data by SCSI PASSTHRU failed, DeviceId = %d, CtrlId = %d, return 0x%04X", device_id,
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);

        attribute->result = retval;
        attribute->scsi_status_code = scsi_passthru_cmd->scsiStatus;
        attribute->data_length = 0;
        attribute->data = NULL;

        g_free(scsi_passthru_cmd);
        return retval;
    }

    attribute->data_length = smart_attribute_len;

    attribute->data = (guint8 *)g_malloc0(attribute->data_length);
    if (NULL == attribute->data) {
        g_free(scsi_passthru_cmd);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    memcpy_s(attribute->data, attribute->data_length, scsi_passthru_cmd->data, attribute->data_length);

    g_free(scsi_passthru_cmd);
    return retval;
}

/*
 * Description: 通过SCSI passthru获取SATA SMART Attribute Threshold
 * History: 2018年1月5日  新生成函数
*/
static gint32 GetSataDeviceSmartAttributeThreshold(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *attribute_threshold)
{
    gint32 retval = SML_SUCCESS;
    SL_SCSI_PASSTHRU_T *scsi_passthru_cmd = NULL;
    guint32 smart_attribute_len = 0;
    guint32 pscsi_passthru_len = 0;
    guint16 block_size = 0;

    if (NULL == pd || NULL == attribute_threshold) {
        return SML_ERR_NULL_DATA;
    }

    attribute_threshold->result = SML_SUCCESS;
    attribute_threshold->scsi_status_code = SCSI_STATUS_SUCCESS;
    attribute_threshold->data_length = 0;
    attribute_threshold->data = NULL;

    /* 直接读取一个sector大小的数据 */
    block_size = pd->pdinfo.block_size;
    if (PD_BLOCK_SIZE_512 != block_size && PD_BLOCK_SIZE_4K != block_size) {
        block_size = PD_BLOCK_SIZE_512;
    }

    smart_attribute_len = attribute_threshold->max_raw_data_size.sectors * block_size;

    pscsi_passthru_len = (guint32)sizeof(SL_SCSI_PASSTHRU_T) + smart_attribute_len;

    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(pscsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI;
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->dir = SL_DIR_READ;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT;
    scsi_passthru_cmd->cdbLength = 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[5] = (attribute_threshold->max_raw_data_size.sectors >> 8) & 0xFF; // 默认为0x00;
    scsi_passthru_cmd->cdb[6] = attribute_threshold->max_raw_data_size.sectors & 0xFF;        // 默认为0x01
    scsi_passthru_cmd->cdb[7] = 0x01;
    scsi_passthru_cmd->cdb[8] = 0x01;
    scsi_passthru_cmd->cdb[9] = 0x00;
    scsi_passthru_cmd->cdb[10] = 0x4f;
    scsi_passthru_cmd->cdb[11] = 0x00;
    scsi_passthru_cmd->cdb[12] = 0xc2;
    scsi_passthru_cmd->cdb[13] = 0xa0;
    scsi_passthru_cmd->cdb[14] = 0xb0;
    scsi_passthru_cmd->cdb[15] = 0x00;
    scsi_passthru_cmd->dataSize = smart_attribute_len;

    retval = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_DEBUG,
            "Get SATA Device SMART data by SCSI PASSTHRU failed, DeviceId = %d, CtrlId = %d, return 0x%04X", device_id,
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);

        attribute_threshold->result = retval;
        attribute_threshold->scsi_status_code = scsi_passthru_cmd->scsiStatus;
        attribute_threshold->data_length = 0;
        attribute_threshold->data = NULL;

        g_free(scsi_passthru_cmd);
        return retval;
    }

    attribute_threshold->data_length = smart_attribute_len;

    attribute_threshold->data = (guint8 *)g_malloc0(attribute_threshold->data_length);
    if (NULL == attribute_threshold->data) {
        g_free(scsi_passthru_cmd);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    memcpy_s(attribute_threshold->data, attribute_threshold->data_length, scsi_passthru_cmd->data,
        attribute_threshold->data_length);

    g_free(scsi_passthru_cmd);
    return retval;
}
/*
 * Description: 通过SCSI passthru命令读取SATA Error Log
 * History: 2018年1月3日  新生成函数
 *          2018年4月13日 AR.SR.SFEA02130924.009.001 修改数据获取命令，获取summary error log
*/
static gint32 GetSataDeviceErrorlog(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd, SML_PD_LOG_DATA_S *error_log)
{
    gint32 retval = SML_SUCCESS;
    SL_SCSI_PASSTHRU_T *scsi_passthru_cmd = NULL;
    guint32 pscsi_passthru_len = 0;
    guint16 error_log_sector_cnt = 0;
    guint32 error_log_len = 0;
    guint16 block_size = 0;

    if (NULL == pd || NULL == error_log) {
        return SML_ERR_NULL_DATA;
    }

    error_log->result = SML_SUCCESS;
    error_log->scsi_status_code = SCSI_STATUS_SUCCESS;
    error_log->data_length = 0;
    error_log->data = NULL;

    /* 1. 获取数据的长度 */
    pscsi_passthru_len = (guint32)(sizeof(SL_SCSI_PASSTHRU_T) + ATA_GENERAL_PURPOSE_LOG_DIRECTORY_LENGTH);

    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(pscsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI;
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->dir = SL_DIR_READ;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT;
    scsi_passthru_cmd->cdbLength = 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] = 0x00;
    scsi_passthru_cmd->cdb[4] = 0xd5;
    scsi_passthru_cmd->cdb[5] = 0x00;
    scsi_passthru_cmd->cdb[6] = 0x01;
    scsi_passthru_cmd->cdb[7] = 0x00;
    scsi_passthru_cmd->cdb[8] = 0x00;
    scsi_passthru_cmd->cdb[9] = 0x00;
    scsi_passthru_cmd->cdb[10] = 0x4f;
    scsi_passthru_cmd->cdb[11] = 0x00;
    scsi_passthru_cmd->cdb[12] = 0xc2;
    scsi_passthru_cmd->cdb[13] = 0xa0;
    scsi_passthru_cmd->cdb[14] = 0xb0;
    scsi_passthru_cmd->cdb[15] = 0x00;
    scsi_passthru_cmd->dataSize = ATA_GENERAL_PURPOSE_LOG_DIRECTORY_LENGTH;

    retval = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_DEBUG,
            "Get SATA Device Error log length by SCSI PASSTHRU failed, DeviceId = %d, CtrlId = %d, return 0x%04X",
            device_id, SML_CTRL_ID_VALID_BIT(ctrl_id), retval);

        error_log->result = retval;
        error_log->scsi_status_code = scsi_passthru_cmd->scsiStatus;
        error_log->data_length = 0;
        error_log->data = NULL;

        g_free(scsi_passthru_cmd);
        return retval;
    }

    /* 2. 根据实际的数据长度分配buf并读取数据, 如果数据超过限制，则截断处理 */
    block_size = pd->pdinfo.block_size;
    if (PD_BLOCK_SIZE_512 != block_size && PD_BLOCK_SIZE_4K != block_size) {
        block_size = PD_BLOCK_SIZE_512;
    }

    error_log_sector_cnt = (scsi_passthru_cmd->data[3] << 8) | scsi_passthru_cmd->data[2];
    error_log_len = error_log_sector_cnt * block_size;

    if (error_log_sector_cnt > error_log->max_raw_data_size.sectors) {
        error_log->result = SML_ERR_PD_SCSI_RESP_TRUNCATED;
        error_log_sector_cnt = error_log->max_raw_data_size.sectors;
        error_log_len = error_log_sector_cnt * block_size;
    }
    error_log->max_raw_data_size.sectors = error_log_sector_cnt;

    g_free(scsi_passthru_cmd);
    scsi_passthru_cmd = NULL;
    if (0 == error_log_sector_cnt) {
        debug_log(DLOG_DEBUG, "Error Log sector number is ZERO");
        return SML_ERR_PD_SCSI_RESP_NO_DATA;
    }

    pscsi_passthru_len = (guint32)sizeof(SL_SCSI_PASSTHRU_T) + error_log_len;

    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(pscsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }
    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI;
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->dir = SL_DIR_READ;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT;
    scsi_passthru_cmd->cdbLength = 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] = 0x00;
    scsi_passthru_cmd->cdb[4] = 0xd5;
    scsi_passthru_cmd->cdb[5] = (error_log_sector_cnt >> 8) & 0xFF;
    scsi_passthru_cmd->cdb[6] = error_log_sector_cnt & 0xFF;
    scsi_passthru_cmd->cdb[7] = 0x00;
    scsi_passthru_cmd->cdb[8] = 0x01;
    scsi_passthru_cmd->cdb[9] = 0x00;
    scsi_passthru_cmd->cdb[10] = 0x4f;
    scsi_passthru_cmd->cdb[11] = 0x00;
    scsi_passthru_cmd->cdb[12] = 0xc2;
    scsi_passthru_cmd->cdb[13] = 0xa0;
    scsi_passthru_cmd->cdb[14] = 0xb0;
    scsi_passthru_cmd->cdb[15] = 0x00;
    scsi_passthru_cmd->dataSize = error_log_len;

    retval = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_DEBUG,
            "Get SATA Device Error log by SCSI PASSTHRU failed, DeviceId = %d, CtrlId = %d, return 0x%04X", device_id,
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);

        error_log->result = retval;
        error_log->scsi_status_code = scsi_passthru_cmd->scsiStatus;
        error_log->data_length = 0;
        error_log->data = NULL;

        g_free(scsi_passthru_cmd);
        return retval;
    }

    error_log->data_length = error_log_len;
    error_log->data = (guint8 *)g_malloc0(error_log->data_length);
    if (NULL == error_log->data) {
        g_free(scsi_passthru_cmd);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    memcpy_s(error_log->data, error_log->data_length, scsi_passthru_cmd->data, error_log->data_length);

    g_free(scsi_passthru_cmd);
    return retval;
}

/*
 * Description: 通过SCSI passthru获取SATA Extent Error Log
 * History: 2018年1月3日  新生成函数
 *          2018年4月13日 AR.SR.SFEA02130924.009.001 修改获取最近的5个sector的extent error log
*/
static gint32 GetSataDeviceExtentErrorlog(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *extent_error_log)
{
    gint32 retval = SML_SUCCESS;
    SL_SCSI_PASSTHRU_T *scsi_passthru_cmd = NULL;
    guint32 pscsi_passthru_len = 0;
    guint16 tmp_sector_cnt, extent_error_log_sector_cnt = 0;
    guint32 extent_error_log_len = 0;
    guint16 block_size = 0;
    guchar log_version = 0;
    guchar log_reserved1 = 0;
    guint16 log_offset = 0;
    guint16 log_index = 0;
    guint16 error_cnt = 0;

    if (NULL == pd || NULL == extent_error_log) {
        return SML_ERR_NULL_DATA;
    }

    extent_error_log->result = SML_SUCCESS;
    extent_error_log->scsi_status_code = SCSI_STATUS_SUCCESS;
    extent_error_log->data_length = 0;
    extent_error_log->data = NULL;

    /* 1. 获取数据的长度 */
    pscsi_passthru_len = (guint32)(sizeof(SL_SCSI_PASSTHRU_T) + ATA_GENERAL_PURPOSE_LOG_DIRECTORY_LENGTH);

    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(pscsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI;
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->dir = SL_DIR_READ;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT;
    scsi_passthru_cmd->cdbLength = SCSI_CDB_LENGTH16;
    scsi_passthru_cmd->dataSize = ATA_GENERAL_PURPOSE_LOG_DIRECTORY_LENGTH;
    scsi_passthru_cmd->cdb[0] = 0x85;
    scsi_passthru_cmd->cdb[1] = 0x09;
    scsi_passthru_cmd->cdb[2] = 0x0e;
    scsi_passthru_cmd->cdb[3] = 0x00;
    scsi_passthru_cmd->cdb[4] = 0x00;
    scsi_passthru_cmd->cdb[5] = 0x00;
    scsi_passthru_cmd->cdb[6] = 0x01;
    scsi_passthru_cmd->cdb[7] = 0x00;
    scsi_passthru_cmd->cdb[8] = 0x00;
    scsi_passthru_cmd->cdb[9] = 0x00;
    scsi_passthru_cmd->cdb[10] = 0x00;
    scsi_passthru_cmd->cdb[11] = 0x00;
    scsi_passthru_cmd->cdb[12] = 0x00;
    scsi_passthru_cmd->cdb[13] = 0xa0;
    scsi_passthru_cmd->cdb[14] = 0x2f;
    scsi_passthru_cmd->cdb[15] = 0x00;
    
    retval = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_DEBUG,
            "Get SATA Device Extent Error log length by SCSI PASSTHRU failed, DeviceId = %d, CtrlId = %d, return "
            "0x%04X",
            device_id, SML_CTRL_ID_VALID_BIT(ctrl_id), retval);

        extent_error_log->result = retval;
        extent_error_log->scsi_status_code = scsi_passthru_cmd->scsiStatus;
        extent_error_log->data_length = 0;
        extent_error_log->data = NULL;
        g_free(scsi_passthru_cmd);
        return retval;
    }

    /* 2. 根据实际的数据长度分配buf并读取数据, 如果数据超过限制，则截断处理 */
    block_size = pd->pdinfo.block_size;
    if (PD_BLOCK_SIZE_512 != block_size && PD_BLOCK_SIZE_4K != block_size) {
        block_size = PD_BLOCK_SIZE_512;
    }

    extent_error_log_sector_cnt = (scsi_passthru_cmd->data[7] << 8) | scsi_passthru_cmd->data[6];
    tmp_sector_cnt = extent_error_log_sector_cnt;
    extent_error_log_len = extent_error_log_sector_cnt * block_size;

    if (extent_error_log_sector_cnt > extent_error_log->max_raw_data_size.sectors) {
        extent_error_log->result = SML_ERR_PD_SCSI_RESP_TRUNCATED;
        extent_error_log_sector_cnt = extent_error_log->max_raw_data_size.sectors;
        extent_error_log_len = extent_error_log_sector_cnt * block_size;
    }
    extent_error_log->max_raw_data_size.sectors = extent_error_log_sector_cnt;

    g_free(scsi_passthru_cmd);
    scsi_passthru_cmd = NULL;
    if (0 == extent_error_log_sector_cnt) {
        debug_log(DLOG_DEBUG, "Extended Error Log sector number is ZERO");
        return SML_ERR_PD_SCSI_RESP_NO_DATA;
    }

    // 如果有数据，先获取第一个sector的数据得到总error count和error index
    pscsi_passthru_len = (guint32)sizeof(SL_SCSI_PASSTHRU_T) + block_size;

    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(pscsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }
    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI;
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->dir = SL_DIR_READ;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT;
    scsi_passthru_cmd->cdbLength = 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] = 0x00;
    scsi_passthru_cmd->cdb[4] = 0x00;
    scsi_passthru_cmd->cdb[5] = 0x00;
    scsi_passthru_cmd->cdb[6] = 0x01;
    scsi_passthru_cmd->cdb[7] = 0x00;
    scsi_passthru_cmd->cdb[8] = 0x03;
    scsi_passthru_cmd->cdb[9] = 0x00;
    scsi_passthru_cmd->cdb[10] = 0x00;
    scsi_passthru_cmd->cdb[11] = 0x00;
    scsi_passthru_cmd->cdb[12] = 0x00;
    scsi_passthru_cmd->cdb[13] = 0xa0;
    scsi_passthru_cmd->cdb[14] = 0x2f;
    scsi_passthru_cmd->cdb[15] = 0x00;
    scsi_passthru_cmd->dataSize = block_size;

    retval = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_DEBUG,
            "Get SATA Device Extent Error log by SCSI PASSTHRU failed, DeviceId = %d, CtrlId = %d, return 0x%04X",
            device_id, SML_CTRL_ID_VALID_BIT(ctrl_id), retval);

        extent_error_log->result = retval;
        extent_error_log->scsi_status_code = scsi_passthru_cmd->scsiStatus;
        extent_error_log->data_length = 0;
        extent_error_log->data = NULL;

        g_free(scsi_passthru_cmd);
        return retval;
    }

    log_version = scsi_passthru_cmd->data[0];
    log_reserved1 = scsi_passthru_cmd->data[1];
    log_index = (scsi_passthru_cmd->data[3] << 8) | scsi_passthru_cmd->data[2];
    error_cnt = (scsi_passthru_cmd->data[501] << 8) | scsi_passthru_cmd->data[500];

    g_free(scsi_passthru_cmd);
    scsi_passthru_cmd = NULL;

    debug_log(DLOG_DEBUG,
        "Get SATA Device Extent Error log by SCSI PASSTHRU, DeviceId = %d, CtrlId = %d, Log Index 0x%04X, SectorNum = "
        "%d",
        device_id, SML_CTRL_ID_VALID_BIT(ctrl_id), log_index, tmp_sector_cnt);

    /* 如果当前有error且获取的index值大于可存储的总error number或者为0认为数据无效，
            使用预留字段作为index */
    if (0 != error_cnt && !(1 <= log_index && log_index <= (tmp_sector_cnt * ATA_LOG_EXT_ERR_NUM))) {
        // Some Samsung disks (at least SP1614C/SW100-25, HD300LJ/ZT100-12) use the
        // former index from Summary Error Log (byte 1, now reserved) and set byte 2-3
        // to 0.
        if (!(log_index == 0 && 1 <= log_reserved1 && log_reserved1 <= (tmp_sector_cnt * ATA_LOG_EXT_ERR_NUM))) {
            return SML_ERR_PD_SCSI_RESP_NO_DATA;
        }
        log_index = log_reserved1;
    }
    // 根据index和允许收集的最大的sector计算offset
    if (log_index > 0) {
        log_offset = (log_index - 1) / ATA_LOG_EXT_ERR_NUM;
    }

    if (log_offset >= extent_error_log_sector_cnt) {
        log_offset = log_offset - extent_error_log_sector_cnt + 1;
    } else {
        log_offset = 0;
    }

    pscsi_passthru_len = (guint32)sizeof(SL_SCSI_PASSTHRU_T) + extent_error_log_len;

    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(pscsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }
    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI;
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->dir = SL_DIR_READ;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT;
    scsi_passthru_cmd->cdbLength = 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] = 0x00;
    scsi_passthru_cmd->cdb[4] = 0x00;
    scsi_passthru_cmd->cdb[5] = (extent_error_log_sector_cnt >> 8) & 0xFF; // 默认为0x00
    scsi_passthru_cmd->cdb[6] = extent_error_log_sector_cnt & 0xFF;        // 默认为0x05
    scsi_passthru_cmd->cdb[7] = 0x00;
    scsi_passthru_cmd->cdb[8] = 0x03;
    scsi_passthru_cmd->cdb[9] = (log_offset >> 8) & 0xFF;
    scsi_passthru_cmd->cdb[10] = log_offset & 0xFF;
    scsi_passthru_cmd->cdb[11] = 0x00;
    scsi_passthru_cmd->cdb[12] = 0x00;
    scsi_passthru_cmd->cdb[13] = 0xa0;
    scsi_passthru_cmd->cdb[14] = 0x2f;
    scsi_passthru_cmd->cdb[15] = 0x00;
    scsi_passthru_cmd->dataSize = extent_error_log_len;

    retval = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_DEBUG,
            "Get SATA Device Extent Error log by SCSI PASSTHRU failed, DeviceId = %d, CtrlId = %d, return 0x%04X",
            device_id, SML_CTRL_ID_VALID_BIT(ctrl_id), retval);

        extent_error_log->result = retval;
        extent_error_log->scsi_status_code = scsi_passthru_cmd->scsiStatus;
        extent_error_log->data_length = 0;
        extent_error_log->data = NULL;

        g_free(scsi_passthru_cmd);
        return retval;
    }

    scsi_passthru_cmd->data[0] = log_version;
    scsi_passthru_cmd->data[1] = log_reserved1;
    scsi_passthru_cmd->data[2] = log_index & 0xFF;
    scsi_passthru_cmd->data[3] = (log_index >> 8) & 0xFF;
    scsi_passthru_cmd->data[500] = error_cnt & 0xFF;
    scsi_passthru_cmd->data[501] = (error_cnt >> 8) & 0xFF;
    extent_error_log->data_length = extent_error_log_len;
    extent_error_log->data = (guint8 *)g_malloc0(extent_error_log->data_length);
    if (NULL == extent_error_log->data) {
        g_free(scsi_passthru_cmd);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    memcpy_s(extent_error_log->data, extent_error_log->data_length, scsi_passthru_cmd->data,
        extent_error_log->data_length);

    g_free(scsi_passthru_cmd);
    return retval;
}

/*
 * Description: 通过SCSI passthru获取SATA Extended Self-test Log
 * History: 2018年1月3日  新生成函数
*/
static gint32 GetSataDeviceExtendedSelfTestlog(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *extended_selftest_log)
{
    gint32 retval = SML_SUCCESS;
    SL_SCSI_PASSTHRU_T *scsi_passthru_cmd = NULL;
    guint32 extended_selftest_log_len = 0;
    guint16 extended_selftest_log_sector_cnt = 0;
    guint32 pscsi_passthru_len = 0;
    guint16 block_size = 0;

    if (NULL == pd || NULL == extended_selftest_log) {
        return SML_ERR_NULL_DATA;
    }

    extended_selftest_log->result = SML_SUCCESS;
    extended_selftest_log->scsi_status_code = SCSI_STATUS_SUCCESS;
    extended_selftest_log->data_length = 0;
    extended_selftest_log->data = NULL;

    /* 1. 获取数据的长度 */
    pscsi_passthru_len = (guint32)(sizeof(SL_SCSI_PASSTHRU_T) + ATA_GENERAL_PURPOSE_LOG_DIRECTORY_LENGTH);

    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(pscsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI;
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->dir = SL_DIR_READ;
    scsi_passthru_cmd->cdbLength = SCSI_CDB_LENGTH16;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT;
    scsi_passthru_cmd->cdb[0] = 0x85;
    scsi_passthru_cmd->cdb[1] = 0x09;
    scsi_passthru_cmd->cdb[2] = 0x0e;
    scsi_passthru_cmd->cdb[3] = 0x00;
    scsi_passthru_cmd->cdb[4] = 0x00;
    scsi_passthru_cmd->cdb[5] = 0x00;
    scsi_passthru_cmd->cdb[6] = 0x01;
    scsi_passthru_cmd->cdb[7] = 0x00;
    scsi_passthru_cmd->cdb[8] = 0x00;
    scsi_passthru_cmd->cdb[9] = 0x00;
    scsi_passthru_cmd->cdb[10] = 0x00;
    scsi_passthru_cmd->cdb[11] = 0x00;
    scsi_passthru_cmd->cdb[12] = 0x00;
    scsi_passthru_cmd->cdb[13] = 0xa0;
    scsi_passthru_cmd->cdb[14] = 0x2f;
    scsi_passthru_cmd->cdb[15] = 0x00;
    scsi_passthru_cmd->dataSize = ATA_GENERAL_PURPOSE_LOG_DIRECTORY_LENGTH;

    retval = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_DEBUG,
            "Get SATA Device Extent Error log length by SCSI PASSTHRU failed, DeviceId = %d, CtrlId = %d, return "
            "0x%04X",
            device_id, SML_CTRL_ID_VALID_BIT(ctrl_id), retval);

        extended_selftest_log->result = retval;
        extended_selftest_log->scsi_status_code = scsi_passthru_cmd->scsiStatus;
        extended_selftest_log->data_length = 0;
        extended_selftest_log->data = NULL;

        g_free(scsi_passthru_cmd);
        return retval;
    }

    /* 2. 根据实际的数据长度分配buf并读取数据, 如果数据超过限制，则截断处理 */
    block_size = pd->pdinfo.block_size;
    if (PD_BLOCK_SIZE_512 != block_size && PD_BLOCK_SIZE_4K != block_size) {
        block_size = PD_BLOCK_SIZE_512;
    }

    extended_selftest_log_sector_cnt = (scsi_passthru_cmd->data[15] << 8) | scsi_passthru_cmd->data[14];
    extended_selftest_log_len = extended_selftest_log_sector_cnt * block_size;

    if (extended_selftest_log_sector_cnt > extended_selftest_log->max_raw_data_size.sectors) {
        extended_selftest_log->result = SML_ERR_PD_SCSI_RESP_TRUNCATED;
        extended_selftest_log_sector_cnt = extended_selftest_log->max_raw_data_size.sectors;
        extended_selftest_log_len = extended_selftest_log_sector_cnt * block_size;
    }
    extended_selftest_log->max_raw_data_size.sectors = extended_selftest_log_sector_cnt;

    g_free(scsi_passthru_cmd);
    scsi_passthru_cmd = NULL;
    if (0 == extended_selftest_log_len) {
        debug_log(DLOG_DEBUG, "Extended self-text Log sector number is ZERO");
        return SML_ERR_PD_SCSI_RESP_NO_DATA;
    }

    pscsi_passthru_len = (guint32)sizeof(SL_SCSI_PASSTHRU_T) + extended_selftest_log_len;

    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(pscsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI;
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->dir = SL_DIR_READ;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT;
    scsi_passthru_cmd->cdbLength = 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] = 0x00;
    scsi_passthru_cmd->cdb[4] = 0x00;
    scsi_passthru_cmd->cdb[5] = (extended_selftest_log_sector_cnt >> 8) & 0xFF; // 默认为0x00
    scsi_passthru_cmd->cdb[6] = extended_selftest_log_sector_cnt & 0xFF;        // 默认为0x05
    scsi_passthru_cmd->cdb[7] = 0x00;
    scsi_passthru_cmd->cdb[8] = 0x07;
    scsi_passthru_cmd->cdb[9] = 0x00;
    scsi_passthru_cmd->cdb[10] = 0x00;
    scsi_passthru_cmd->cdb[11] = 0x00;
    scsi_passthru_cmd->cdb[12] = 0x00;
    scsi_passthru_cmd->cdb[13] = 0xa0;
    scsi_passthru_cmd->cdb[14] = 0x2f;
    scsi_passthru_cmd->cdb[15] = 0x00;
    scsi_passthru_cmd->dataSize = extended_selftest_log_len;

    retval = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_DEBUG,
            "Get SATA Device Extended Selftest log length by SCSI PASSTHRU failed, DeviceId = %d, CtrlId = %d, return "
            "0x%04X",
            device_id, SML_CTRL_ID_VALID_BIT(ctrl_id), retval);

        extended_selftest_log->result = retval;
        extended_selftest_log->scsi_status_code = scsi_passthru_cmd->scsiStatus;
        extended_selftest_log->data_length = 0;
        extended_selftest_log->data = NULL;

        g_free(scsi_passthru_cmd);
        return retval;
    }

    extended_selftest_log->data_length = extended_selftest_log_len;
    extended_selftest_log->data = (guint8 *)g_malloc0(extended_selftest_log->data_length);
    if (NULL == extended_selftest_log->data) {
        g_free(scsi_passthru_cmd);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    memcpy_s(extended_selftest_log->data, extended_selftest_log->data_length, scsi_passthru_cmd->data,
        extended_selftest_log->data_length);

    g_free(scsi_passthru_cmd);
    return retval;
}

/*
 * Description: 通过SCSI passthru获取SATA PHY Event Log
 * History: 2018年1月3日  新生成函数
*/
static gint32 GetSataDevicePHYEventlog(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *phy_event_log)
{
    gint32 retval = SML_SUCCESS;
    SL_SCSI_PASSTHRU_T *scsi_passthru_cmd = NULL;
    guint32 phy_event_log_len = 0;
    guint16 phy_event_log_sector_cnt = 0;
    guint32 pscsi_passthru_len = 0;
    guint16 block_size = 0;

    if (NULL == pd || NULL == phy_event_log) {
        return SML_ERR_NULL_DATA;
    }

    phy_event_log->result = SML_SUCCESS;
    phy_event_log->scsi_status_code = SCSI_STATUS_SUCCESS;
    phy_event_log->data_length = 0;
    phy_event_log->data = NULL;

    /* 读取固定大小的数据，如1个sector */
    block_size = pd->pdinfo.block_size;
    if (PD_BLOCK_SIZE_512 != block_size && PD_BLOCK_SIZE_4K != block_size) {
        block_size = PD_BLOCK_SIZE_512;
    }

    phy_event_log_sector_cnt = phy_event_log->max_raw_data_size.sectors;
    phy_event_log_len = phy_event_log_sector_cnt * block_size;

    pscsi_passthru_len = (guint32)sizeof(SL_SCSI_PASSTHRU_T) + phy_event_log_len;

    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(pscsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI;
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->dir = SL_DIR_READ;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT;
    scsi_passthru_cmd->cdbLength = 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] = 0x00;
    scsi_passthru_cmd->cdb[4] = 0x00;
    scsi_passthru_cmd->cdb[5] = (phy_event_log_sector_cnt >> 8) & 0xFF; // 默认为0x00
    scsi_passthru_cmd->cdb[6] = phy_event_log_sector_cnt & 0xFF;        // 默认为0x01
    scsi_passthru_cmd->cdb[7] = 0x00;
    scsi_passthru_cmd->cdb[8] = 0x11;
    scsi_passthru_cmd->cdb[9] = 0x00;
    scsi_passthru_cmd->cdb[10] = 0x00;
    scsi_passthru_cmd->cdb[11] = 0x00;
    scsi_passthru_cmd->cdb[12] = 0x00;
    scsi_passthru_cmd->cdb[13] = 0x40;
    scsi_passthru_cmd->cdb[14] = 0x2f;
    scsi_passthru_cmd->cdb[15] = 0x00;
    scsi_passthru_cmd->dataSize = phy_event_log_len;

    retval = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_DEBUG,
            "Get SATA Device PHY Event log by SCSI PASSTHRU failed, DeviceId = %d, CtrlId = %d, return 0x%04X",
            device_id, SML_CTRL_ID_VALID_BIT(ctrl_id), retval);

        phy_event_log->result = retval;
        phy_event_log->scsi_status_code = scsi_passthru_cmd->scsiStatus;
        phy_event_log->data_length = 0;
        phy_event_log->data = NULL;

        g_free(scsi_passthru_cmd);
        return retval;
    }

    phy_event_log->data_length = phy_event_log_len;
    phy_event_log->data = (guint8 *)g_malloc0(phy_event_log->data_length);
    if (NULL == phy_event_log->data) {
        g_free(scsi_passthru_cmd);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    memcpy_s(phy_event_log->data, phy_event_log->data_length, scsi_passthru_cmd->data, phy_event_log->data_length);

    g_free(scsi_passthru_cmd);
    return retval;
}

/*
 * Description: 通过SCSI passthru获取Seagate STAT Glist
 * History: 2018年1月4日  新生成函数
*/
static gint32 GetSeagateSataDeviceGlist(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd, SML_PD_LOG_DATA_S *glist)
{
    gint32 retval = SML_SUCCESS;
    SL_SCSI_PASSTHRU_T *scsi_passthru_cmd = NULL;
    guint32 glist_len = 0;
    guint16 glist_sector_cnt = 0;
    guint32 pscsi_passthru_len = 0;
    guint16 block_size = 0;

    if (NULL == pd || NULL == glist) {
        return SML_ERR_NULL_DATA;
    }

    glist->result = SML_SUCCESS;
    glist->scsi_status_code = SCSI_STATUS_SUCCESS;
    glist->data_length = 0;
    glist->data = NULL;

    /* 读取固定大小的数据，如5个sectors */
    block_size = pd->pdinfo.block_size;
    if (PD_BLOCK_SIZE_512 != block_size && PD_BLOCK_SIZE_4K != block_size) {
        block_size = PD_BLOCK_SIZE_512;
    }

    glist_sector_cnt = glist->max_raw_data_size.sectors;
    glist_len = glist_sector_cnt * block_size;

    pscsi_passthru_len = (guint32)sizeof(SL_SCSI_PASSTHRU_T) + glist_len;

    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(pscsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI;
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->dir = SL_DIR_READ;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT;
    scsi_passthru_cmd->cdbLength = 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] = 0x00;
    scsi_passthru_cmd->cdb[4] = 0x00;
    scsi_passthru_cmd->cdb[5] = (glist_sector_cnt >> 8) & 0xFF; // 默认为0x00
    scsi_passthru_cmd->cdb[6] = glist_sector_cnt & 0xFF;        // 默认为0x05
    scsi_passthru_cmd->cdb[7] = 0x00;
    scsi_passthru_cmd->cdb[8] = 0xa8;
    scsi_passthru_cmd->cdb[9] = 0x00;
    scsi_passthru_cmd->cdb[10] = 0x00;
    scsi_passthru_cmd->cdb[11] = 0x00;
    scsi_passthru_cmd->cdb[12] = 0x00;
    scsi_passthru_cmd->cdb[13] = 0xa0;
    scsi_passthru_cmd->cdb[14] = 0x2f;
    scsi_passthru_cmd->cdb[15] = 0x00;
    scsi_passthru_cmd->dataSize = glist_len;

    retval = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_DEBUG,
            "Get Segate SATA Device Glist by SCSI PASSTHRU failed, DeviceId = %d, CtrlId = %d, return 0x%04X",
            device_id, SML_CTRL_ID_VALID_BIT(ctrl_id), retval);

        glist->result = retval;
        glist->scsi_status_code = scsi_passthru_cmd->scsiStatus;
        glist->data_length = 0;
        glist->data = NULL;

        g_free(scsi_passthru_cmd);
        return retval;
    }

    glist->data_length = glist_len;
    glist->data = (guint8 *)g_malloc0(glist->data_length);
    if (NULL == glist->data) {
        g_free(scsi_passthru_cmd);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    memcpy_s(glist->data, glist->data_length, scsi_passthru_cmd->data, glist->data_length);

    g_free(scsi_passthru_cmd);
    return retval;
}

/*
 * Description: 通过SCSI passthru获取Seagate SATA Plist
 * History: 2018年1月4日  新生成函数
*/
static gint32 GetSeagateSataDevicePlist(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd, SML_PD_LOG_DATA_S *plist)
{
    gint32 retval = SML_SUCCESS;
    SL_SCSI_PASSTHRU_T *scsi_passthru_cmd = NULL;
    guint32 plist_len = 0;
    guint16 plist_sector_cnt = 0;
    guint32 pscsi_passthru_len = 0;
    guint16 block_size = 0;

    if (NULL == pd || NULL == plist) {
        return SML_ERR_NULL_DATA;
    }

    plist->result = SML_SUCCESS;
    plist->scsi_status_code = SCSI_STATUS_SUCCESS;
    plist->data_length = 0;
    plist->data = NULL;

    /* 读取固定大小的数据，如1个sector */
    block_size = pd->pdinfo.block_size;
    if (PD_BLOCK_SIZE_512 != block_size && PD_BLOCK_SIZE_4K != block_size) {
        block_size = PD_BLOCK_SIZE_512;
    }

    plist_sector_cnt = plist->max_raw_data_size.sectors;
    plist_len = plist_sector_cnt * block_size;

    pscsi_passthru_len = (guint32)sizeof(SL_SCSI_PASSTHRU_T) + plist_len;

    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(pscsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI;
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->dir = SL_DIR_READ;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT;
    scsi_passthru_cmd->cdbLength = 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] = 0xd5;
    scsi_passthru_cmd->cdb[4] = 0xd5;
    scsi_passthru_cmd->cdb[5] = (plist_sector_cnt >> 8) & 0xFF; // 默认为0x00
    scsi_passthru_cmd->cdb[6] = plist_sector_cnt & 0xFF;        // 默认为0x01
    scsi_passthru_cmd->cdb[7] = 0x00;
    scsi_passthru_cmd->cdb[8] = 0xa9;
    scsi_passthru_cmd->cdb[9] = 0x4f;
    scsi_passthru_cmd->cdb[10] = 0x4f;
    scsi_passthru_cmd->cdb[11] = 0xc2;
    scsi_passthru_cmd->cdb[12] = 0xc2;
    scsi_passthru_cmd->cdb[13] = 0xa0;
    scsi_passthru_cmd->cdb[14] = 0xb0;
    scsi_passthru_cmd->cdb[15] = 0x00;
    scsi_passthru_cmd->dataSize = plist_len;

    retval = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_DEBUG,
            "Get Segate SATA Device Plist by SCSI PASSTHRU failed, DeviceId = %d, CtrlId = %d, return 0x%04X",
            device_id, SML_CTRL_ID_VALID_BIT(ctrl_id), retval);

        plist->result = retval;
        plist->scsi_status_code = scsi_passthru_cmd->scsiStatus;
        plist->data_length = 0;
        plist->data = NULL;

        g_free(scsi_passthru_cmd);
        return retval;
    }

    plist->data_length = plist_len;
    plist->data = (guint8 *)g_malloc0(plist->data_length);
    if (NULL == plist->data) {
        g_free(scsi_passthru_cmd);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    memcpy_s(plist->data, plist->data_length, scsi_passthru_cmd->data, plist->data_length);

    g_free(scsi_passthru_cmd);
    return retval;
}

/*
 * Description: 通过SCSI passthru获取Seagate SATA HDD Critival Event
 * History: 2018年1月4日  新生成函数
*/
static gint32 GetSeagateSataDeviceCriticalEvtLog(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *cr_event)
{
    gint32 retval = SML_SUCCESS;
    SL_SCSI_PASSTHRU_T *scsi_passthru_cmd = NULL;
    guint32 critical_event_len = 0;
    guint16 critical_event_sector_cnt = 0;
    guint32 pscsi_passthru_len = 0;
    guint16 block_size = 0;

    if (NULL == pd || NULL == cr_event) {
        return SML_ERR_NULL_DATA;
    }

    cr_event->result = SML_SUCCESS;
    cr_event->scsi_status_code = SCSI_STATUS_SUCCESS;
    cr_event->data_length = 0;
    cr_event->data = NULL;

    /* 读取固定大小的数据，如20个sector */
    block_size = pd->pdinfo.block_size;
    if (PD_BLOCK_SIZE_512 != block_size && PD_BLOCK_SIZE_4K != block_size) {
        block_size = PD_BLOCK_SIZE_512;
    }

    critical_event_sector_cnt = cr_event->max_raw_data_size.sectors;
    critical_event_len = critical_event_sector_cnt * block_size;

    pscsi_passthru_len = (guint32)sizeof(SL_SCSI_PASSTHRU_T) + critical_event_len;

    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(pscsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI;
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->dir = SL_DIR_READ;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT;
    scsi_passthru_cmd->cdbLength = SCSI_CDB_LENGTH16;
    scsi_passthru_cmd->cdb[0] = 0x85;
    scsi_passthru_cmd->cdb[1] = 0x0d;
    scsi_passthru_cmd->cdb[2] = 0x0e;
    scsi_passthru_cmd->cdb[3] = 0x00;
    scsi_passthru_cmd->cdb[4] = 0x00;
    scsi_passthru_cmd->cdb[5] = (critical_event_sector_cnt >> 8) & 0xFF; // 默认为0x00
    scsi_passthru_cmd->cdb[6] = critical_event_sector_cnt & 0xFF;        // 默认为0x14
    scsi_passthru_cmd->cdb[7] = 0x00;
    scsi_passthru_cmd->cdb[8] = 0xa1;
    scsi_passthru_cmd->cdb[9] = 0x00;
    scsi_passthru_cmd->cdb[10] = 0x00;
    scsi_passthru_cmd->cdb[11] = 0x00;
    scsi_passthru_cmd->cdb[12] = 0x00;
    scsi_passthru_cmd->cdb[13] = 0xa0;
    scsi_passthru_cmd->cdb[14] = 0x47;
    scsi_passthru_cmd->cdb[15] = 0x00;
    scsi_passthru_cmd->dataSize = critical_event_len;

    retval = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_DEBUG,
            "Get Segate SATA Device Critical Event Log by SCSI PASSTHRU failed, DeviceId = %d, CtrlId = %d, return "
            "0x%04X",
            device_id, SML_CTRL_ID_VALID_BIT(ctrl_id), retval);

        cr_event->result = retval;
        cr_event->scsi_status_code = scsi_passthru_cmd->scsiStatus;
        cr_event->data_length = 0;
        cr_event->data = NULL;

        g_free(scsi_passthru_cmd);
        return retval;
    }

    cr_event->data_length = critical_event_len;
    cr_event->data = (guint8 *)g_malloc0(cr_event->data_length);
    if (NULL == cr_event->data) {
        g_free(scsi_passthru_cmd);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    memcpy_s(cr_event->data, cr_event->data_length, scsi_passthru_cmd->data, cr_event->data_length);

    g_free(scsi_passthru_cmd);
    return retval;
}

/*
 * Description: 通过SCSI passthru获取Seagate SATA FARM Log
 * History: 2018年9月15日  新生成函数
 *          2019年10月23日
 *          free farm_log->data后未置NULL，导致app层double free
*/
static gint32 GetSeagateSataDeviceFARMLog(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *farm_log)
{
    gint32 retval = SML_SUCCESS;
    SL_SCSI_PASSTHRU_T *scsi_passthru_cmd = NULL;
    guint32 farm_log_len = 0;
    guint16 farm_log_sector_cnt = 0;
    guint32 pscsi_passthru_len = 0;
    guint16 block_size = 0;
    guint16 offset_sector = 0;
    guint32 offset_data = 0;
    guint16 count = 32;

#define ATA_LOG_TYPE_SEAGATE_FARM_LOG 0xA6

    if (NULL == pd || NULL == farm_log) {
        return SML_ERR_NULL_DATA;
    }

    farm_log->result = SML_SUCCESS;
    farm_log->scsi_status_code = SCSI_STATUS_SUCCESS;
    farm_log->data_length = 0;
    farm_log->data = NULL;

    /* 1. 获取数据的长度 */
    pscsi_passthru_len = (guint32)(sizeof(SL_SCSI_PASSTHRU_T) + ATA_GENERAL_PURPOSE_LOG_DIRECTORY_LENGTH);

    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(pscsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI;
    scsi_passthru_cmd->dir = SL_DIR_READ;
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT;
    scsi_passthru_cmd->cdbLength = 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] = 0x00;
    scsi_passthru_cmd->cdb[4] = 0x00;
    scsi_passthru_cmd->cdb[5] = 0x00;
    scsi_passthru_cmd->cdb[6] = 0x01;
    scsi_passthru_cmd->cdb[7] = 0x00;
    scsi_passthru_cmd->cdb[8] = 0x00;
    scsi_passthru_cmd->cdb[9] = 0x00;
    scsi_passthru_cmd->cdb[10] = 0x00;
    scsi_passthru_cmd->cdb[11] = 0x00;
    scsi_passthru_cmd->cdb[12] = 0x00;
    scsi_passthru_cmd->cdb[13] = 0x00;
    scsi_passthru_cmd->cdb[14] = 0x2f;
    scsi_passthru_cmd->cdb[15] = 0x00;
    scsi_passthru_cmd->dataSize = ATA_GENERAL_PURPOSE_LOG_DIRECTORY_LENGTH;

    retval = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_DEBUG,
            "Get Seagate SATA Device FARM Log length by SCSI PASSTHRU failed, DeviceId = %d, CtrlId = %d, return "
            "0x%04X",
            device_id, SML_CTRL_ID_VALID_BIT(ctrl_id), retval);

        farm_log->result = retval;
        farm_log->scsi_status_code = scsi_passthru_cmd->scsiStatus;
        farm_log->data_length = 0;
        farm_log->data = NULL;

        g_free(scsi_passthru_cmd);
        return retval;
    }

    /* 2. 根据实际的数据长度分配buf并读取数据，如果数据超过限制，则截断处理 */
    block_size = pd->pdinfo.block_size;
    /* 不支持4K块大小 */
    if (PD_BLOCK_SIZE_4K == block_size) {
        g_free(scsi_passthru_cmd);
        return SML_ERR_PD_OPERATION_NOT_SUPPORT;
    }
    if (PD_BLOCK_SIZE_512 != block_size) {
        block_size = PD_BLOCK_SIZE_512;
    }

    farm_log_sector_cnt = (scsi_passthru_cmd->data[ATA_LOG_TYPE_SEAGATE_FARM_LOG * 2 + 1] << 8) |
        scsi_passthru_cmd->data[ATA_LOG_TYPE_SEAGATE_FARM_LOG * 2];
    farm_log_len = (guint32)farm_log_sector_cnt * (guint32)block_size;

    g_free(scsi_passthru_cmd);
    scsi_passthru_cmd = NULL;

    debug_log(DLOG_DEBUG, "Get Seagate FARMLOG sector num = %d, DeviceId = %d, CtrlId = %d", farm_log_sector_cnt,
        device_id, SML_CTRL_ID_VALID_BIT(ctrl_id));

    /* 3. 判断sector个数是否等于farmlog定义的sector数 */
    if (farm_log_sector_cnt != farm_log->max_raw_data_size.sectors) {
        debug_log(DLOG_DEBUG, "Seagate SATA Device FARM Log sector number is not %d",
            farm_log->max_raw_data_size.sectors);
        return SML_ERR_PD_SCSI_RESP_INCORRECT;
    }

    /* 4. 如果有数据，分帧(32 sectors)获取日志数据 */
    pscsi_passthru_len = (guint32)sizeof(SL_SCSI_PASSTHRU_T) + block_size * 32;
    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(pscsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }
    farm_log->data_length = farm_log_len;
    farm_log->data = (guint8 *)g_malloc0(farm_log->data_length);
    if (NULL == farm_log->data) {
        g_free(scsi_passthru_cmd);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    while (offset_sector < farm_log->max_raw_data_size.sectors) {
        scsi_passthru_cmd->targetId = device_id;
        scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI;
        scsi_passthru_cmd->lun = 0;
        scsi_passthru_cmd->dir = SL_DIR_READ;
        scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT;
        scsi_passthru_cmd->cdbLength = 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] = 0x00;
        scsi_passthru_cmd->cdb[4] = 0x00;
        scsi_passthru_cmd->cdb[5] = 0x00;
        scsi_passthru_cmd->cdb[6] = count & 0xFF;
        scsi_passthru_cmd->cdb[7] = 0x00;
        scsi_passthru_cmd->cdb[8] = ATA_LOG_TYPE_SEAGATE_FARM_LOG;
        scsi_passthru_cmd->cdb[9] = 0x00;
        scsi_passthru_cmd->cdb[10] = offset_sector & 0xFF;
        scsi_passthru_cmd->cdb[11] = 0x00;
        scsi_passthru_cmd->cdb[12] = 0x00;
        scsi_passthru_cmd->cdb[13] = 0x00;
        scsi_passthru_cmd->cdb[14] = 0x2f;
        scsi_passthru_cmd->cdb[15] = 0x00;
        scsi_passthru_cmd->dataSize = block_size * count;

        retval = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
        if (retval != SML_SUCCESS) {
            debug_log(DLOG_DEBUG,
                "Get Seagate SATA Device FARM Log by SCSI PASSTHRU failed, DeviceId = %d, CtrlId = %d, return 0x%04X",
                device_id, SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
            farm_log->result = retval;
            farm_log->scsi_status_code = scsi_passthru_cmd->scsiStatus;
            farm_log->data_length = 0;

            g_free(farm_log->data);
            farm_log->data = NULL;
            g_free(scsi_passthru_cmd);
            return retval;
        }

        debug_log(DLOG_DEBUG, "Get Seagate FARMLOG log page, offset_sector = %d, DeviceId = %d, CtrlId = %d",
            offset_sector, device_id, SML_CTRL_ID_VALID_BIT(ctrl_id));

        offset_data = offset_sector * block_size;

        if (offset_data + scsi_passthru_cmd->dataSize <= farm_log_len) {
            errno_t safe_fun_ret = memcpy_s(farm_log->data + offset_data, scsi_passthru_cmd->dataSize,
                scsi_passthru_cmd->data, scsi_passthru_cmd->dataSize);
            if (safe_fun_ret != EOK) {
                debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
            }
        }

        offset_sector += count;

        /* 循环使用scsi_passthru_cmd后，清空数据 */
        (void)memset_s(scsi_passthru_cmd, pscsi_passthru_len, 0, pscsi_passthru_len);

        /* 实测中IT卡发送命令太快会导致异常，延时发送命令 */
        vos_task_delay(500);
    }

    g_free(scsi_passthru_cmd);
    return retval;
}

/*
 * Description: 发送SCSI LogSense命令
 * History: 2016年4月14日  新生成函数
 *          2018年01月15日
 *          AR.SR.SFEA02109778.006.006 调用接口由定长的buf改为变长的buf，
 *          接口内部分配内存，调用者释放
 *          2018年05月20日   AR.SR.SFEA02130924.009.003 buf_size 如果非0表示获取指定size的数据
*/
gint32 SendSCSILogSenseCommand(guint32 ctrl_id, guint16 device_id, guint8 page_code, guint8 sub_page_code,
    guint8 **pbuf, guint32 *buf_size, guint32 *scsi_status)
{
    gint32 ret = 0;
    guint16 page_length = 0;
    SL_SCSI_PASSTHRU_T *scsi_passthru_cmd = NULL;
    guint32 scsi_passthru_len = 0;

    if (pbuf == NULL || buf_size == NULL) {
        return SML_ERR_NULL_DATA;
    }

    scsi_passthru_len = (guint32)(sizeof(SL_SCSI_PASSTHRU_T) + SCSI_LOG_PAGE_HEADER_SIZE);
    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(scsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    page_length = SCSI_LOG_PAGE_HEADER_SIZE;
    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI;
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->dir = SL_DIR_READ;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT;
    scsi_passthru_cmd->cdbLength = SCSI_CDB_LENGTH10;
    // refers to SPC-4 Table 187
    scsi_passthru_cmd->cdb[0] = SCSI_CMD_LOG_SENSE;
    scsi_passthru_cmd->cdb[1] = 0x00;
    scsi_passthru_cmd->cdb[2] = 0x40 | (page_code & 0x3F);
    scsi_passthru_cmd->cdb[3] = sub_page_code;
    scsi_passthru_cmd->cdb[7] = (page_length >> 8) & 0xff;
    scsi_passthru_cmd->cdb[8] = page_length & 0xff;
    scsi_passthru_cmd->dataSize = SCSI_LOG_PAGE_HEADER_SIZE;

    ret = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_DEBUG, "Get log page length failed, DeviceId = %d, CtrlId = %d, return 0x%04X", device_id,
            SML_CTRL_ID_VALID_BIT(ctrl_id), ret);
        if (NULL != scsi_status) {
            *scsi_status = scsi_passthru_cmd->scsiStatus;
        }

        g_free(scsi_passthru_cmd);
        return ret;
    }

    if ((SCSI_LOG_PAGE_SUPPORTED_LOG_PAGES != page_code) && ((scsi_passthru_cmd->data[0] & 0x3F) != page_code)) {
        debug_log(DLOG_DEBUG, "Responsed with incorrect page code 0x%02x, should be 0x%02x", scsi_passthru_cmd->data[0],
            page_code);
        g_free(scsi_passthru_cmd);
        return SML_ERR_PD_SCSI_RESP_INCORRECT;
    }

    page_length = (scsi_passthru_cmd->data[2] << 8) + scsi_passthru_cmd->data[3];

    if (0 == page_length) {
        debug_log(DLOG_DEBUG, "Responsed log page length is ZERO");
        g_free(scsi_passthru_cmd);
        return SML_ERR_PD_SCSI_RESP_NO_DATA;
    }

    g_free(scsi_passthru_cmd);
    scsi_passthru_cmd = NULL;

    page_length += SCSI_LOG_PAGE_HEADER_SIZE;
    // 如果buf_size > 数据头，表示获取指定大小的返回数据
    if (*buf_size > SCSI_LOG_PAGE_HEADER_SIZE) {
        page_length = page_length > *buf_size ? *buf_size : page_length;
    }

    scsi_passthru_len = (guint32)sizeof(SL_SCSI_PASSTHRU_T) + page_length;
    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(scsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI; /* fire to physical device */
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->dir = SL_DIR_READ;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT; /* in seconds */
    scsi_passthru_cmd->cdbLength = SCSI_CDB_LENGTH10;
    scsi_passthru_cmd->cdb[0] = SCSI_CMD_LOG_SENSE;
    scsi_passthru_cmd->cdb[1] = 0x00;
    scsi_passthru_cmd->cdb[2] = 0x40 | (page_code & 0x3F);
    scsi_passthru_cmd->cdb[3] = sub_page_code;
    scsi_passthru_cmd->cdb[7] = (page_length >> 8) & 0xFF;
    scsi_passthru_cmd->cdb[8] = page_length & 0xFF;
    scsi_passthru_cmd->dataSize = page_length;

    ret = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_DEBUG, "Get log page data failed, DeviceId = %d, CtrlId = %d, return 0x%04X", device_id, ctrl_id,
            ret);
        if (NULL != scsi_status) {
            *scsi_status = scsi_passthru_cmd->scsiStatus;
        }

        g_free(scsi_passthru_cmd);
        return ret;
    }

    if ((SCSI_LOG_PAGE_SUPPORTED_LOG_PAGES != page_code) && ((scsi_passthru_cmd->data[0] & 0x3F) != page_code)) {
        debug_log(DLOG_DEBUG, "Responsed with incorrect page code 0x%02x, should be 0x%02x", scsi_passthru_cmd->data[0],
            page_code);
        g_free(scsi_passthru_cmd);
        return SML_ERR_PD_SCSI_RESP_INCORRECT;
    }

    *pbuf = (guint8 *)g_malloc0(page_length);
    if (*pbuf == NULL) {
        debug_log(DLOG_DEBUG, "Cannot alloc memory for response data buf");
        g_free(scsi_passthru_cmd);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    memcpy_s(*pbuf, page_length, scsi_passthru_cmd->data, page_length);
    *buf_size = page_length;
    g_free(scsi_passthru_cmd);

    return SML_SUCCESS;
}

/*
 * Description: 通过SCSI passthru发送READ DEFECT(12)命令读取Glist
 * History: 2018年1月6日  新生成函数
*/
static gint32 SendSCSIReadDefectCommand12(guint32 ctrl_id, guint16 device_id, guint8 **pbuf, guint32 *buf_size,
    guint32 *scsi_status)
{
    gint32 ret = 0;
    SL_SCSI_PASSTHRU_T *scsi_passthru_cmd = NULL;
    guint32 scsi_passthru_len = 0;
    guint32 defect_list_length = 0;

    if (pbuf == NULL || buf_size == NULL) {
        return SML_ERR_NULL_DATA;
    }

    scsi_passthru_len = (guint32)(sizeof(SL_SCSI_PASSTHRU_T) + SCSI_DEFECT_LIST_HEADER_SIZE);
    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(scsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI;
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->dir = SL_DIR_READ;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT;
    scsi_passthru_cmd->cdbLength = SCSI_CDB_LENGTH12;
    // refers to SPC-4 Table 187
    scsi_passthru_cmd->cdb[0] = SCSI_CMD_READ_DEFECT_DATA;
    scsi_passthru_cmd->cdb[1] = 0x0d;
    scsi_passthru_cmd->cdb[8] = 0;
    scsi_passthru_cmd->cdb[9] = SCSI_DEFECT_LIST_HEADER_SIZE;
    scsi_passthru_cmd->dataSize = SCSI_DEFECT_LIST_HEADER_SIZE;

    ret = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_DEBUG, "Get Defect data length failed, DeviceId = %d, CtrlId = %d, return 0x%04X", device_id,
            SML_CTRL_ID_VALID_BIT(ctrl_id), ret);

        if (NULL != scsi_status) {
            *scsi_status = scsi_passthru_cmd->scsiStatus;
        }

        g_free(scsi_passthru_cmd);
        return ret;
    }

    defect_list_length = (scsi_passthru_cmd->data[4] << 24) | (scsi_passthru_cmd->data[5] << 16) |
        (scsi_passthru_cmd->data[6] << 8) | scsi_passthru_cmd->data[7];
    debug_log(DLOG_DEBUG, "Defect List length %d, DeviceId = %d, CtrlId = %d", defect_list_length, device_id,
        SML_CTRL_ID_VALID_BIT(ctrl_id));

    g_free(scsi_passthru_cmd);
    scsi_passthru_cmd = NULL;

    defect_list_length += SCSI_DEFECT_LIST_HEADER_SIZE;
    scsi_passthru_len = sizeof(SL_SCSI_PASSTHRU_T) + defect_list_length;
    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(scsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI;
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->dir = SL_DIR_READ;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT;
    scsi_passthru_cmd->cdbLength = SCSI_CDB_LENGTH12;
    // refers to SBC-3 Table 72
    scsi_passthru_cmd->cdb[0] = SCSI_CMD_READ_DEFECT_DATA;
    scsi_passthru_cmd->cdb[1] = 0x0d;
    scsi_passthru_cmd->cdb[6] = (defect_list_length >> 24) & 0xff;
    scsi_passthru_cmd->cdb[7] = (defect_list_length >> 16) & 0xff;
    scsi_passthru_cmd->cdb[8] = (defect_list_length >> 8) & 0xff;
    scsi_passthru_cmd->cdb[9] = defect_list_length & 0xff;
    scsi_passthru_cmd->dataSize = defect_list_length;

    ret = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_DEBUG, "Get Defect data failed, DeviceId = %d, CtrlId = %d, return 0x%04X", device_id,
            SML_CTRL_ID_VALID_BIT(ctrl_id), ret);

        if (NULL != scsi_status) {
            *scsi_status = scsi_passthru_cmd->scsiStatus;
        }

        g_free(scsi_passthru_cmd);
        return ret;
    }

    *pbuf = (guint8 *)g_malloc0(defect_list_length);
    if (*pbuf == NULL) {
        debug_log(DLOG_DEBUG, "Cannot alloc memory for response data buf");
        g_free(scsi_passthru_cmd);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    memcpy_s(*pbuf, defect_list_length, scsi_passthru_cmd->data, defect_list_length);
    *buf_size = defect_list_length;

    g_free(scsi_passthru_cmd);

    return SML_SUCCESS;
}

/*
 * Description : 通过SCSI passthru发送命令读取HSSD IO Info
 * History：2020-11-4  新生成函数
 */
gint32 send_read_hssd_io_info_scsi_command(guint32 ctrl_id, guint16 device_id, guint8 **pbuf, guint32 *buf_size,
    guint32 *scsi_status)
{
    gint32 ret;
    const guint16 page_length = 64;

    if (pbuf == NULL || buf_size == NULL) {
        return SML_ERR_NULL_DATA;
    }

    guint32 scsi_passthru_len = sizeof(SL_SCSI_PASSTHRU_T) + page_length;
    SL_SCSI_PASSTHRU_T *scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(scsi_passthru_len);

    if (scsi_passthru_cmd == NULL) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }
    // 该命令获取硬盘的读写数据量统计数据, 返回0x40字节数据，每项8字节
    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI; /* fire to physical device */
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->dir = SL_DIR_READ;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT; /* in seconds */
    scsi_passthru_cmd->cdbLength = SCSI_CDB_LENGTH10;
    scsi_passthru_cmd->cdb[0] = 0xC0;   // operation Code(C0h)
    scsi_passthru_cmd->cdb[1] = 0x07;   // SubFunCode(07h)
    scsi_passthru_cmd->cdb[2] = 0x00;   // 2: page_length高字节位
    scsi_passthru_cmd->cdb[3] = 0x40;   // 3: page_length低字节位
    scsi_passthru_cmd->cdb[4] = 0x00;   // 4: 后6字节为Reserved
    scsi_passthru_cmd->cdb[5] = 0x00;
    scsi_passthru_cmd->cdb[6] = 0x00;
    scsi_passthru_cmd->cdb[7] = 0x00;
    scsi_passthru_cmd->cdb[8] = page_length & 0xFF;
    scsi_passthru_cmd->cdb[9] = 0x00;
    scsi_passthru_cmd->dataSize = page_length;

    ret = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (ret != SML_SUCCESS) {
        debug_log(
            DLOG_DEBUG, "Get IO Info data failed, DeviceId = %d, CtrlId = %d, return 0x%04X", device_id, ctrl_id, ret);
        if (NULL != scsi_status) {
            *scsi_status = scsi_passthru_cmd->scsiStatus;
        }

        g_free(scsi_passthru_cmd);
        return ret;
    }

    *pbuf = (guint8 *)g_malloc0(page_length);
    if (*pbuf == NULL) {
        debug_log(DLOG_DEBUG, "Cannot alloc memory for response data buf");
        g_free(scsi_passthru_cmd);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    memcpy_s(*pbuf, page_length, scsi_passthru_cmd->data, page_length);
    *buf_size = page_length;
    g_free(scsi_passthru_cmd);

    return SML_SUCCESS;
}

/*
 * Description: 获取当前设备是否支持指定的LogPage
 * History: 2016年4月14日  新生成函数
*/
gint32 GetSCSIDeviceSupportLogPages(guint32 ctrl_id, guint16 device_id, guint8 page_code, guint8 *lp_support)
{
    guint32 idx = 0;
    gint32 retval = SML_SUCCESS;
    guint8 *buf = NULL;
    guint32 buf_size = 0;

    if (lp_support == NULL) {
        return SML_ERR_NULL_DATA;
    }

    retval = SendSCSILogSenseCommand(ctrl_id, device_id, SCSI_LOG_PAGE_SUPPORTED_LOG_PAGES, 0, &buf, &buf_size, NULL);
    if (retval != SML_SUCCESS) {
        return retval;
    }

    if (buf == NULL) {
        return SML_ERR_DATA_LEN_INVALID;
    }

    if (buf_size < SCSI_LOG_PAGE_HEADER_SIZE || buf_size < (buf[3] + SCSI_LOG_PAGE_HEADER_SIZE)) {
        g_free(buf);
        return SML_ERR_DATA_LEN_INVALID;
    }

    *lp_support = FALSE;

    for (idx = SCSI_LOG_PAGE_HEADER_SIZE; idx < buf[3] + SCSI_LOG_PAGE_HEADER_SIZE;
        idx++) { // buf[3] = length, refers to SPC-4 Table-422
        if (buf[idx] == page_code) {
            *lp_support = TRUE;
            break;
        }
    }

    debug_log(DLOG_MASS, "Supported Log Pages response raw data: \n");

    for (idx = 0; idx < buf_size; idx++) {
        if (idx % 16 == 0 && idx != 0) {
            debug_log(DLOG_MASS, "\n");
        }

        debug_log(DLOG_MASS, "%02x ", buf[idx]);
    }

    debug_log(DLOG_MASS, "\n");

    g_free(buf);

    return SML_SUCCESS;
}

/*
 * Description: 通过SCSI passthru获取SAS Self-test Log
 * History: 2018年1月4日  新生成函数
*/
static gint32 GetSasDeviceSelfTestLog(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *selftest_log)
{
    gint32 retval = SML_SUCCESS;
    guint8 *buf = NULL;
    guint32 buf_size = 0;
    guint8 lp_support = FALSE;

    if (NULL == selftest_log) {
        return SML_ERR_NULL_DATA;
    }

    selftest_log->result = SML_SUCCESS;
    selftest_log->scsi_status_code = SCSI_STATUS_SUCCESS;
    selftest_log->data_length = 0;
    selftest_log->data = NULL;

    retval = GetSCSIDeviceSupportLogPages(ctrl_id, device_id, SCSI_LOG_PAGE_SELFTEST_RESULTS, &lp_support);
    if (SML_SUCCESS != retval) {
        return retval;
    }

    if (FALSE == lp_support) {
        return SML_ERR_PD_LOG_PAGE_UNSUPPORT;
    }

    retval = SendSCSILogSenseCommand(ctrl_id, device_id, SCSI_LOG_PAGE_SELFTEST_RESULTS, 0, &buf, &buf_size,
        &selftest_log->scsi_status_code);
    debug_log(DLOG_DEBUG, "Send SCSI Log sense command %x to %d.%d return 0x%x\n", SCSI_LOG_PAGE_SELFTEST_RESULTS,
        SML_CTRL_ID_VALID_BIT(ctrl_id), device_id, retval);

    if (retval == SML_SUCCESS && NULL != buf) {
        if (buf_size > selftest_log->max_raw_data_size.bytes) {
            selftest_log->result = SML_ERR_PD_SCSI_RESP_TRUNCATED;
            selftest_log->data_length = selftest_log->max_raw_data_size.bytes;
        } else {
            selftest_log->data_length = buf_size;
        }

        selftest_log->data = (guint8 *)g_malloc0(selftest_log->data_length);
        if (NULL == selftest_log->data) {
            g_free(buf);
            return SML_ERR_CANNOT_ALLOC_MEM;
        }

        memcpy_s(selftest_log->data, selftest_log->data_length, buf, selftest_log->data_length);

        g_free(buf);
    }

    return retval;
}

/*
 * Description: 通过SCSI passthru获取SAS Write Error Count
 * History: 2018年1月4日  新生成函数
*/
static gint32 GetSasDeviceWriteErrorCntLog(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *write_error_log)
{
    gint32 retval = SML_SUCCESS;
    guint8 *buf = NULL;
    guint32 buf_size = 0;
    guint8 lp_support = FALSE;

    if (NULL == write_error_log) {
        return SML_ERR_NULL_DATA;
    }

    write_error_log->result = SML_SUCCESS;
    write_error_log->scsi_status_code = SCSI_STATUS_SUCCESS;
    write_error_log->data_length = 0;
    write_error_log->data = NULL;

    retval = GetSCSIDeviceSupportLogPages(ctrl_id, device_id, SCSI_LOG_PAGE_WRITE_ERROR_COUNTER, &lp_support);
    if (SML_SUCCESS != retval) {
        return retval;
    }

    if (FALSE == lp_support) {
        return SML_ERR_PD_LOG_PAGE_UNSUPPORT;
    }

    retval = SendSCSILogSenseCommand(ctrl_id, device_id, SCSI_LOG_PAGE_WRITE_ERROR_COUNTER, 0, &buf, &buf_size,
        &write_error_log->scsi_status_code);
    debug_log(DLOG_DEBUG, "Send SCSI %d.%d Log sense command %x return 0x%x\n", SML_CTRL_ID_VALID_BIT(ctrl_id),
        device_id, SCSI_LOG_PAGE_WRITE_ERROR_COUNTER, retval);

    if (retval == SML_SUCCESS && NULL != buf) {
        if (buf_size > write_error_log->max_raw_data_size.bytes) {
            write_error_log->result = SML_ERR_PD_SCSI_RESP_TRUNCATED;
            write_error_log->data_length = write_error_log->max_raw_data_size.bytes;
        } else {
            write_error_log->data_length = buf_size;
        }

        write_error_log->data = (guint8 *)g_malloc0(write_error_log->data_length);
        if (NULL == write_error_log->data) {
            g_free(buf);
            return SML_ERR_CANNOT_ALLOC_MEM;
        }

        memcpy_s(write_error_log->data, write_error_log->data_length, buf, write_error_log->data_length);

        g_free(buf);
    }

    return retval;
}

/*
 * Description: 通过SCSI passthru获取SAS Read Error Count
 * History: 2018年1月4日  新生成函数
*/
static gint32 GetSasDeviceReadErrorCntLog(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *read_error_log)
{
    gint32 retval = SML_SUCCESS;
    guint8 *buf = NULL;
    guint32 buf_size = 0;
    guint8 lp_support = FALSE;

    if (NULL == read_error_log) {
        return SML_ERR_NULL_DATA;
    }

    read_error_log->result = SML_SUCCESS;
    read_error_log->scsi_status_code = SCSI_STATUS_SUCCESS;
    read_error_log->data_length = 0;
    read_error_log->data = NULL;

    retval = GetSCSIDeviceSupportLogPages(ctrl_id, device_id, SCSI_LOG_PAGE_READ_ERROR_COUNTER, &lp_support);
    if (SML_SUCCESS != retval) {
        return retval;
    }

    if (FALSE == lp_support) {
        return SML_ERR_PD_LOG_PAGE_UNSUPPORT;
    }

    retval = SendSCSILogSenseCommand(ctrl_id, device_id, SCSI_LOG_PAGE_READ_ERROR_COUNTER, 0, &buf, &buf_size,
        &read_error_log->scsi_status_code);
    debug_log(DLOG_DEBUG, "Send SCSI %d.%d Log sense command %x return 0x%x\n", SML_CTRL_ID_VALID_BIT(ctrl_id),
        device_id, SCSI_LOG_PAGE_READ_ERROR_COUNTER, retval);

    if (retval == SML_SUCCESS && NULL != buf) {
        if (buf_size > read_error_log->max_raw_data_size.bytes) {
            read_error_log->result = SML_ERR_PD_SCSI_RESP_TRUNCATED;
            read_error_log->data_length = read_error_log->max_raw_data_size.bytes;
        } else {
            read_error_log->data_length = buf_size;
        }

        read_error_log->data = (guint8 *)g_malloc0(read_error_log->data_length);
        if (NULL == read_error_log->data) {
            g_free(buf);
            return SML_ERR_CANNOT_ALLOC_MEM;
        }

        memcpy_s(read_error_log->data, read_error_log->data_length, buf, read_error_log->data_length);

        g_free(buf);
    }

    return retval;
}

/*
 * Description: 通过SCSI passthru获取SAS Verify Error Count
 * History: 2018年1月4日  新生成函数
*/
static gint32 GetSasDeviceVerifyErrorCntLog(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *verify_error_log)
{
    gint32 retval = SML_SUCCESS;
    guint8 *buf = NULL;
    guint32 buf_size = 0;
    guint8 lp_support = FALSE;

    if (NULL == verify_error_log) {
        return SML_ERR_NULL_DATA;
    }

    verify_error_log->result = SML_SUCCESS;
    verify_error_log->scsi_status_code = SCSI_STATUS_SUCCESS;
    verify_error_log->data_length = 0;
    verify_error_log->data = NULL;

    retval = GetSCSIDeviceSupportLogPages(ctrl_id, device_id, SCSI_LOG_PAGE_VERIFY_ERROR_COUNTER, &lp_support);
    if (SML_SUCCESS != retval) {
        return retval;
    }

    if (FALSE == lp_support) {
        return SML_ERR_PD_LOG_PAGE_UNSUPPORT;
    }

    retval = SendSCSILogSenseCommand(ctrl_id, device_id, SCSI_LOG_PAGE_VERIFY_ERROR_COUNTER, 0, &buf, &buf_size,
        &verify_error_log->scsi_status_code);
    debug_log(DLOG_DEBUG, "Send SCSI %d.%d Log sense command %x return 0x%x\n", SML_CTRL_ID_VALID_BIT(ctrl_id),
        device_id, SCSI_LOG_PAGE_VERIFY_ERROR_COUNTER, retval);

    if (retval == SML_SUCCESS && NULL != buf) {
        if (buf_size > verify_error_log->max_raw_data_size.bytes) {
            verify_error_log->result = SML_ERR_PD_SCSI_RESP_TRUNCATED;
            verify_error_log->data_length = verify_error_log->max_raw_data_size.bytes;
        } else {
            verify_error_log->data_length = buf_size;
        }

        verify_error_log->data = (guint8 *)g_malloc0(verify_error_log->data_length);
        if (NULL == verify_error_log->data) {
            g_free(buf);
            return SML_ERR_CANNOT_ALLOC_MEM;
        }

        memcpy_s(verify_error_log->data, verify_error_log->data_length, buf, verify_error_log->data_length);

        g_free(buf);
    }

    return retval;
}

/*
 * Description: 通过SCSI passthru获取SAS Verify Error Count
 * History: 2018年1月4日  新生成函数
*/
static gint32 GetSasDeviceNonmediumErrorCntLog(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *nonmedium_error_log)
{
    gint32 retval = SML_SUCCESS;
    guint8 *buf = NULL;
    guint32 buf_size = 0;
    guint8 lp_support = FALSE;

    if (NULL == nonmedium_error_log) {
        return SML_ERR_NULL_DATA;
    }

    nonmedium_error_log->result = SML_SUCCESS;
    nonmedium_error_log->scsi_status_code = SCSI_STATUS_SUCCESS;
    nonmedium_error_log->data_length = 0;
    nonmedium_error_log->data = NULL;

    retval = GetSCSIDeviceSupportLogPages(ctrl_id, device_id, SCSI_LOG_PAGE_NON_MEDIUM_ERROR, &lp_support);
    if (SML_SUCCESS != retval) {
        return retval;
    }

    if (FALSE == lp_support) {
        return SML_ERR_PD_LOG_PAGE_UNSUPPORT;
    }

    retval = SendSCSILogSenseCommand(ctrl_id, device_id, SCSI_LOG_PAGE_NON_MEDIUM_ERROR, 0, &buf, &buf_size,
        &nonmedium_error_log->scsi_status_code);
    debug_log(DLOG_DEBUG, "Send SCSI %d.%d Log sense command %x return 0x%x\n", SML_CTRL_ID_VALID_BIT(ctrl_id),
        device_id, SCSI_LOG_PAGE_NON_MEDIUM_ERROR, retval);

    if (retval == SML_SUCCESS && NULL != buf) {
        if (buf_size > nonmedium_error_log->max_raw_data_size.bytes) {
            nonmedium_error_log->result = SML_ERR_PD_SCSI_RESP_TRUNCATED;
            nonmedium_error_log->data_length = nonmedium_error_log->max_raw_data_size.bytes;
        } else {
            nonmedium_error_log->data_length = buf_size;
        }

        nonmedium_error_log->data = (guint8 *)g_malloc0(nonmedium_error_log->data_length);
        if (NULL == nonmedium_error_log->data) {
            g_free(buf);
            return SML_ERR_CANNOT_ALLOC_MEM;
        }

        memcpy_s(nonmedium_error_log->data, nonmedium_error_log->data_length, buf, nonmedium_error_log->data_length);

        g_free(buf);
    }

    return retval;
}

/*
 * Description: 通过SCSI passthru获取SAS PHY Error Count
 * History: 2018年1月4日  新生成函数
*/
static gint32 GetSasDevicePHYErrorCntLog(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *phy_error_log)
{
    gint32 retval = SML_SUCCESS;
    guint8 *buf = NULL;
    guint32 buf_size = 0;
    guint8 lp_support = FALSE;

    if (NULL == phy_error_log) {
        return SML_ERR_NULL_DATA;
    }

    phy_error_log->result = SML_SUCCESS;
    phy_error_log->scsi_status_code = SCSI_STATUS_SUCCESS;
    phy_error_log->data_length = 0;
    phy_error_log->data = NULL;

    retval = GetSCSIDeviceSupportLogPages(ctrl_id, device_id, SCSI_LOG_PAGE_PROTOCOL_SPECIFIC, &lp_support);
    if (SML_SUCCESS != retval) {
        return retval;
    }

    if (FALSE == lp_support) {
        return SML_ERR_PD_LOG_PAGE_UNSUPPORT;
    }

    retval = SendSCSILogSenseCommand(ctrl_id, device_id, SCSI_LOG_PAGE_PROTOCOL_SPECIFIC, 0, &buf, &buf_size,
        &phy_error_log->scsi_status_code);
    debug_log(DLOG_DEBUG, "Send SCSI %d.%d Log sense command %x return 0x%x\n", SML_CTRL_ID_VALID_BIT(ctrl_id),
        device_id, SCSI_LOG_PAGE_PROTOCOL_SPECIFIC, retval);

    if (retval == SML_SUCCESS && NULL != buf) {
        if (buf_size > phy_error_log->max_raw_data_size.bytes) {
            phy_error_log->result = SML_ERR_PD_SCSI_RESP_TRUNCATED;
            phy_error_log->data_length = phy_error_log->max_raw_data_size.bytes;
        } else {
            phy_error_log->data_length = buf_size;
        }

        phy_error_log->data = (guint8 *)g_malloc0(phy_error_log->data_length);
        if (NULL == phy_error_log->data) {
            g_free(buf);
            return SML_ERR_CANNOT_ALLOC_MEM;
        }

        memcpy_s(phy_error_log->data, phy_error_log->data_length, buf, phy_error_log->data_length);

        g_free(buf);
    }

    return retval;
}

/*
 * Description: 通过SCSI passthru获取SAS Internal Exception
 * History: 2018年1月5日  新生成函数
*/
static gint32 GetSasDeviceInternalExceptionlog(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *ie)
{
    gint32 retval = SML_SUCCESS;
    guint8 *buf = NULL;
    guint32 buf_size = 0;
    guint8 lp_support = FALSE;

    if (NULL == ie) {
        return SML_ERR_NULL_DATA;
    }

    ie->result = SML_SUCCESS;
    ie->scsi_status_code = SCSI_STATUS_SUCCESS;
    ie->data_length = 0;
    ie->data = NULL;

    retval = GetSCSIDeviceSupportLogPages(ctrl_id, device_id, SCSI_LOG_PAGE_IE, &lp_support);
    if (SML_SUCCESS != retval) {
        return retval;
    }

    if (FALSE == lp_support) {
        return SML_ERR_PD_LOG_PAGE_UNSUPPORT;
    }

    retval = SendSCSILogSenseCommand(ctrl_id, device_id, SCSI_LOG_PAGE_IE, 0, &buf, &buf_size, &ie->scsi_status_code);
    debug_log(DLOG_DEBUG, "Send SCSI %d.%d Log sense command %x return 0x%x\n", SML_CTRL_ID_VALID_BIT(ctrl_id),
        device_id, SCSI_LOG_PAGE_TEMPERATURE, retval);

    if (retval == SML_SUCCESS && NULL != buf) {
        if (buf_size > ie->max_raw_data_size.bytes) {
            ie->result = SML_ERR_PD_SCSI_RESP_TRUNCATED;
            ie->data_length = ie->max_raw_data_size.bytes;
        } else {
            ie->data_length = buf_size;
        }

        ie->data = (guint8 *)g_malloc0(ie->data_length);
        if (NULL == ie->data) {
            g_free(buf);
            return SML_ERR_CANNOT_ALLOC_MEM;
        }

        memcpy_s(ie->data, ie->data_length, buf, ie->data_length);

        g_free(buf);
    }

    return retval;
}

/*
 * Description: 通过SCSI passthru获取SAS Temperature Log
 * History: 2018年1月4日  新生成函数
*/
static gint32 GetSasDeviceTemperaturelog(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *temperature_log)
{
    gint32 retval = SML_SUCCESS;
    guint8 *buf = NULL;
    guint32 buf_size = 0;
    guint8 lp_support = FALSE;

    if (NULL == temperature_log) {
        return SML_ERR_NULL_DATA;
    }

    temperature_log->result = SML_SUCCESS;
    temperature_log->scsi_status_code = SCSI_STATUS_SUCCESS;
    temperature_log->data_length = 0;
    temperature_log->data = NULL;

    retval = GetSCSIDeviceSupportLogPages(ctrl_id, device_id, SCSI_LOG_PAGE_TEMPERATURE, &lp_support);
    if (SML_SUCCESS != retval) {
        return retval;
    }

    if (FALSE == lp_support) {
        return SML_ERR_PD_LOG_PAGE_UNSUPPORT;
    }

    retval = SendSCSILogSenseCommand(ctrl_id, device_id, SCSI_LOG_PAGE_TEMPERATURE, 0, &buf, &buf_size,
        &temperature_log->scsi_status_code);
    debug_log(DLOG_DEBUG, "Send SCSI %d.%d Log sense command %x return 0x%x\n", SML_CTRL_ID_VALID_BIT(ctrl_id),
        device_id, SCSI_LOG_PAGE_TEMPERATURE, retval);

    if (retval == SML_SUCCESS && NULL != buf) {
        if (buf_size > temperature_log->max_raw_data_size.bytes) {
            temperature_log->result = SML_ERR_PD_SCSI_RESP_TRUNCATED;
            temperature_log->data_length = temperature_log->max_raw_data_size.bytes;
        } else {
            temperature_log->data_length = buf_size;
        }

        temperature_log->data = (guint8 *)g_malloc0(temperature_log->data_length);
        if (NULL == temperature_log->data) {
            g_free(buf);
            return SML_ERR_CANNOT_ALLOC_MEM;
        }

        memcpy_s(temperature_log->data, temperature_log->data_length, buf, temperature_log->data_length);

        g_free(buf);
    }

    return retval;
}

/*
 * Description: 通过SCSI passthru获取SAS BMS Log
 * History: 2018年1月4日  新生成函数
*/
static gint32 GetSasDeviceBMSLog(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd, SML_PD_LOG_DATA_S *bms)
{
    gint32 retval = SML_SUCCESS;
    guint8 *buf = NULL;
    guint32 buf_size = 0;
    guint8 lp_support = FALSE;

    if (NULL == bms) {
        return SML_ERR_NULL_DATA;
    }

    bms->result = SML_SUCCESS;
    bms->scsi_status_code = SCSI_STATUS_SUCCESS;
    bms->data_length = 0;
    bms->data = NULL;

    retval = GetSCSIDeviceSupportLogPages(ctrl_id, device_id, SCSI_LOG_PAGE_BACKGROUND_RESULTS, &lp_support);
    if (SML_SUCCESS != retval) {
        return retval;
    }

    if (FALSE == lp_support) {
        return SML_ERR_PD_LOG_PAGE_UNSUPPORT;
    }

    retval = SendSCSILogSenseCommand(ctrl_id, device_id, SCSI_LOG_PAGE_BACKGROUND_RESULTS, 0, &buf, &buf_size,
        &bms->scsi_status_code);
    debug_log(DLOG_DEBUG, "Send SCSI %d.%d Log sense command %x return 0x%x\n", SML_CTRL_ID_VALID_BIT(ctrl_id),
        device_id, SCSI_LOG_PAGE_BACKGROUND_RESULTS, retval);

    if (retval == SML_SUCCESS && NULL != buf) {
        if (buf_size > bms->max_raw_data_size.bytes) {
            bms->result = SML_ERR_PD_SCSI_RESP_TRUNCATED;
            bms->data_length = bms->max_raw_data_size.bytes;
        } else {
            bms->data_length = buf_size;
        }

        bms->data = (guint8 *)g_malloc0(bms->data_length);
        if (NULL == bms->data) {
            g_free(buf);
            return SML_ERR_CANNOT_ALLOC_MEM;
        }

        memcpy_s(bms->data, bms->data_length, buf, bms->data_length);

        g_free(buf);
    }

    return retval;
}

/*
 * Description: 通过SCSI passthru获取SAS Glist
 * History: 2018年1月4日  新生成函数
*/
static gint32 GetSasDeviceGlist(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd, SML_PD_LOG_DATA_S *glist)
{
    gint32 retval = SML_SUCCESS;
    guint8 *buf = NULL;
    guint32 buf_size = 0;

    if (NULL == glist) {
        return SML_ERR_NULL_DATA;
    }

    glist->result = SML_SUCCESS;
    glist->scsi_status_code = SCSI_STATUS_SUCCESS;
    glist->data_length = 0;
    glist->data = NULL;

    retval = SendSCSIReadDefectCommand12(ctrl_id, device_id, &buf, &buf_size, &glist->scsi_status_code);
    debug_log(DLOG_DEBUG, "Send SCSI %d.%d Read Defect(12) command return 0x%x\n", SML_CTRL_ID_VALID_BIT(ctrl_id),
        device_id, retval);

    if (retval == SML_SUCCESS && NULL != buf) {
        if (buf_size > glist->max_raw_data_size.bytes) {
            glist->result = SML_ERR_PD_SCSI_RESP_TRUNCATED;
            glist->data_length = glist->max_raw_data_size.bytes;
        } else {
            glist->data_length = buf_size;
        }

        glist->data = (guint8 *)g_malloc0(glist->data_length);
        if (NULL == glist->data) {
            g_free(buf);
            return SML_ERR_CANNOT_ALLOC_MEM;
        }

        memcpy_s(glist->data, glist->data_length, buf, glist->data_length);

        g_free(buf);
    }

    return retval;
}

/*
 * Description : 通过SCSI passthru获取指定pagecode log
 * History：2020-10-27  新生成函数
 */
static gint32 get_sas_log_by_pagecode(guint32 ctrl_id, guint16 device_id, guint8 page_code, guint8 sub_page_code,
    SML_PD_INFO_S *pd, SML_PD_LOG_DATA_S *pPDlog)
{
    gint32 retval;
    guint8 *buf = NULL;
    guint32 buf_size = 0;
    guint32 count;
    guint8 lp_support = FALSE;

    if (pPDlog == NULL) {
        return SML_ERR_NULL_DATA;
    }

    pPDlog->result = SML_SUCCESS;
    pPDlog->scsi_status_code = SCSI_STATUS_SUCCESS;
    pPDlog->data_length = 0;
    pPDlog->data = NULL;

    retval = GetSCSIDeviceSupportLogPages(ctrl_id, device_id, page_code, &lp_support);
    if (retval != SML_SUCCESS) {
        return retval;
    }

    if (lp_support == FALSE) {
        return SML_ERR_PD_LOG_PAGE_UNSUPPORT;
    }

    retval = SendSCSILogSenseCommand(ctrl_id, device_id, page_code, sub_page_code, &buf, &buf_size, NULL);
    debug_log(DLOG_DEBUG,
        "Send SCSI %d.%d Log sense command %x return 0x%x\n",
        SML_CTRL_ID_VALID_BIT(ctrl_id),
        device_id,
        page_code,
        retval);

    if (retval == SML_SUCCESS && buf != NULL) {
        if (buf_size > pPDlog->max_raw_data_size.bytes) {
            pPDlog->result = SML_ERR_PD_SCSI_RESP_TRUNCATED;
            pPDlog->data_length = pPDlog->max_raw_data_size.bytes;
            count = pPDlog->max_raw_data_size.bytes - 1;
        } else {
            pPDlog->data_length = buf_size;
            count = buf_size;
        }

        pPDlog->data = (guint8 *)g_malloc0(pPDlog->data_length);
        if (pPDlog->data == NULL) {
            g_free(buf);
            return SML_ERR_CANNOT_ALLOC_MEM;
        }

        (void)memcpy_s(pPDlog->data, pPDlog->data_length, buf, count);

        g_free(buf);
    }

    return retval;
}

/*
 * Description : 通过SCSI passthru获取general statistics and performance log
 * History：2020-10-27  新生成函数
 */
static gint32 get_sas_log_general_statistics(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *pPDlog)
{
    return get_sas_log_by_pagecode(ctrl_id, device_id, SCSI_LOG_PAGE_GENERAL_STATISTICS, 0, pd, pPDlog);
}

/*
 * Description : 通过SCSI passthru获取华为SAS SSD vendor specific log(32h)
 * History：2020-11-18  新生成函数
 */
static gint32 get_sas_log_huawei_specific32h(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *pPDlog)
{
    return get_sas_log_by_pagecode(ctrl_id, device_id, SCSI_LOG_PAGE_HUAWEI_SPECIFIC32H, 0, pd, pPDlog);
}

/*
 * Description : 通过SCSI passthru获取华为SAS SSD vendor specific log(34h)
 * History：2020-11-9  新生成函数
 */
static gint32 get_sas_log_huawei_specific34h(
    guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd, SML_PD_LOG_DATA_S *pPDlog)
{
    return get_sas_log_by_pagecode(ctrl_id, device_id, SCSI_LOG_PAGE_HUAWEI_SPECIFIC34H, 0, pd, pPDlog);
}

/*
 * Description : 通过SCSI passthru获取华为SAS SSD vendor specific log(35h)
 * History：2020-10-27  新生成函数
 */
static gint32 get_sas_log_huawei_specific35h(
    guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd, SML_PD_LOG_DATA_S *pPDlog)
{
    return get_sas_log_by_pagecode(ctrl_id, device_id, SCSI_LOG_PAGE_HUAWEI_SPECIFIC35H, 0, pd, pPDlog);
}

/*
 * Description : 通过SCSI passthru获取华为SAS SSD IO Info
 * History：2020-11-4  新生成函数
 */
static gint32 get_sas_log_huawei_io_info(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *pPDlog)
{
    gint32 retval;
    guint8 *buf = NULL;
    guint32 buf_size = 0;
    guint32 count;

    if (pPDlog == NULL) {
        return SML_ERR_NULL_DATA;
    }

    pPDlog->result = SML_SUCCESS;
    pPDlog->scsi_status_code = SCSI_STATUS_SUCCESS;
    pPDlog->data_length = 0;
    pPDlog->data = NULL;

    retval = send_read_hssd_io_info_scsi_command(ctrl_id, device_id, &buf, &buf_size, NULL);
    debug_log(DLOG_DEBUG,
        "Send SCSI %d.%d read hssd io info return 0x%x\n",
        SML_CTRL_ID_VALID_BIT(ctrl_id),
        device_id,
        retval);

    if (retval == SML_SUCCESS && buf != NULL) {
        if (buf_size > pPDlog->max_raw_data_size.bytes) {
            pPDlog->result = SML_ERR_PD_SCSI_RESP_TRUNCATED;
            pPDlog->data_length = pPDlog->max_raw_data_size.bytes;
            count = pPDlog->max_raw_data_size.bytes - 1;
        } else {
            pPDlog->data_length = buf_size;
            count = buf_size;
        }

        pPDlog->data = (guint8 *)g_malloc0(pPDlog->data_length);
        if (pPDlog->data == NULL) {
            g_free(buf);
            return SML_ERR_CANNOT_ALLOC_MEM;
        }

        (void)memcpy_s(pPDlog->data, pPDlog->data_length, buf, count);

        g_free(buf);
    }

    return retval;
}

/*
 * Description : 通过SCSI passthru获取kioxia SAS SSD ssd specific log
 * History：2020-11-19  新生成函数
 */
static gint32 get_sas_log_kioxia_ssd_specific(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *pPDlog)
{
    return get_sas_log_by_pagecode(ctrl_id, device_id, SCSI_LOG_PAGE_KIOXIA_SSD_SPECIFIC, 0, pd, pPDlog);
}

/*
 * Description : 通过SCSI passthru获取kioxia SAS SSD Endurance Over Provisioning Throttling Log
 * History：2020-11-19  新生成函数
 */
static gint32 get_sas_log_kioxia_eopt(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd, SML_PD_LOG_DATA_S *pPDlog)
{
    return get_sas_log_by_pagecode(ctrl_id, device_id, SCSI_LOG_PAGE_KIOXIA_EOPT, 1, pd, pPDlog);
}

/*
 * Description : 通过SCSI passthru获取kioxia SAS SSD Endurance, Over Provisioning, Throttling Log
 * History：2020-11-19  新生成函数
 */
static gint32 get_sas_log_kioxia_smart_data(guint32 ctrl_id, guint16 device_id, SML_PD_INFO_S *pd,
    SML_PD_LOG_DATA_S *pPDlog)
{
    return get_sas_log_by_pagecode(ctrl_id, device_id, SCSI_LOG_PAGE_KIOXIA_SMART_DATA, 0, pd, pPDlog);
}

static pd_log_collect_func g_pd_log_collect_func[] = {
    {PD_LOG_SATA_SMART_ATTRIBUTE,                   GetSataDeviceSmartAttribute},
    {PD_LOG_SATA_SMART_ATTRIBUTE_THRESHOLD,         GetSataDeviceSmartAttributeThreshold},
    {PD_LOG_SATA_ERROR,                             GetSataDeviceErrorlog},
    {PD_LOG_SATA_EXTENT_ERROR,                      GetSataDeviceExtentErrorlog},
    {PD_LOG_SATA_EXTENDED_SELF_TEST,                GetSataDeviceExtendedSelfTestlog},
    {PD_LOG_SATA_PHY_EVENT,                         GetSataDevicePHYEventlog},
    {PD_LOG_SATA_SEAGATE_GLIST,                     GetSeagateSataDeviceGlist},
    {PD_LOG_SATA_SEAGATE_PLIST,                     GetSeagateSataDevicePlist},
    {PD_LOG_SATA_SEAGATE_CRITICAL_EVENT,            GetSeagateSataDeviceCriticalEvtLog},
    {PD_LOG_SATA_SEAGATE_FARM,                      GetSeagateSataDeviceFARMLog},
    {PD_LOG_SAS_SELF_TEST,                          GetSasDeviceSelfTestLog},
    {PD_LOG_SAS_WRITE_ERROR_CNT,                    GetSasDeviceWriteErrorCntLog},
    {PD_LOG_SAS_READ_ERROR_CNT,                     GetSasDeviceReadErrorCntLog},
    {PD_LOG_SAS_VERIFY_ERROR_CNT,                   GetSasDeviceVerifyErrorCntLog},
    {PD_LOG_SAS_NONMEDIUM_ERROR_CNT,                GetSasDeviceNonmediumErrorCntLog},
    {PD_LOG_SAS_PHY_ERROR_CNT,                      GetSasDevicePHYErrorCntLog},
    {PD_LOG_SAS_INTERNAL_EXCEPTION,                 GetSasDeviceInternalExceptionlog},
    {PD_LOG_SAS_TEMPERATURE,                        GetSasDeviceTemperaturelog},
    {PD_LOG_SAS_BACKGORUN_MEDIA_SCAN,               GetSasDeviceBMSLog},
    {PD_LOG_SAS_GLIST,                              GetSasDeviceGlist},
    {PD_LOG_SAS_GENERAL_STATISTICS,                 get_sas_log_general_statistics},
    {PD_LOG_SAS_HUAWEI_SPECIFIC32H,                 get_sas_log_huawei_specific32h},
    {PD_LOG_SAS_HUAWEI_SPECIFIC34H,                 get_sas_log_huawei_specific34h},
    {PD_LOG_SAS_HUAWEI_SPECIFIC35H,                 get_sas_log_huawei_specific35h},
    {PD_LOG_SAS_HUAWEI_IO_INFO,                     get_sas_log_huawei_io_info},
    {PD_LOG_SAS_KIOXIA_SSD_SPECIFIC,                get_sas_log_kioxia_ssd_specific},
    {PD_LOG_SAS_KIOXIA_EOPT,                        get_sas_log_kioxia_eopt},
    {PD_LOG_SAS_KIOXIA_SMART_DATA,                  get_sas_log_kioxia_smart_data}
};

/*
 * Description: 通过LSI的storelib获取物理盘的日志数据
 * History: 2018年1月6日  新生成函数
 *          2018年9月15日  AR.SR.SFEA02130924.009.007
 *          新增收集FARM Log日志
*/
gint32 lsi_get_pd_log(guint32 ctrl_id, guint16 device_id, gpointer param, gpointer data)
{
    gint32 retval = SML_ERR_PD_OPERATION_NOT_SUPPORT;
    SML_PD_INFO_S *pPDinfo = NULL;
    SML_PD_LOG_DATA_S *pPDlog = NULL;
    guint32 func_len;
    guint32 i;

    if (NULL == param || NULL == data) {
        return SML_ERR_NULL_DATA;
    }

    pPDinfo = (SML_PD_INFO_S *)param;
    pPDlog = (SML_PD_LOG_DATA_S *)data;

    func_len = G_N_ELEMENTS(g_pd_log_collect_func);

    for (i = 0; i < func_len; i++) {
        if (pPDlog->log_type == g_pd_log_collect_func[i].log_type) {
            retval = g_pd_log_collect_func[i].func(ctrl_id, device_id, pPDinfo, pPDlog);
        }
    }

    return retval;
}
