/* 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 "platform.h"
#include "sml.h"
#include "sml_errcodes.h"
#include "sml_phy_event.h"
#include "diagnose_defs.h"
#include "pd_log_process.h"
#include "sas_log_parse.h"

/* Table 41 */
typedef enum _SCSI_GLIST_FORMAT_TYPE {
    GLIST_FORMAT_TYPE_SHORT_BLOCK = 0,
    GLIST_FORMAT_TYPE_EXT_BYTES = 1,
    GLIST_FORMAT_TYPE_EXT_PHY_SECTOR,
    GLIST_FORMAT_TYPE_LONG_BLOCK,
    GLIST_FORMAT_TYPE_BYTES,
    GLIST_FORMAT_TYPE_PHY_SECTOR,
    GLIST_FORMAT_TYPE_VENDOR_SPECIFIC
} SCSI_GLIST_FORMAT_TYPE;

static const gchar* g_bms_status[] = {
    "no scans active",
    "background medium scan is active",
    "pre-scan is active",
    "scan halted due to fatal error",
    "scan halted due to unusual pattern of error",
    "scan halted due to medium formatted without P-List",
    "scan halted - vendor specific cause",
    "scan halted due to temperature out of range",
    "scan suspended until BMS Interval Time expires", /* 8 */
};

static const gchar* g_reassign_status[] = {
    "No assignment",
    "Reassignment pending",
    "LBA reassigned",
    "Reassign status: Reserved [0x3]",
    "Reassignment failed",
    "LBA recovered via re-write",
};

#define VENDOR_LOG_STRING_LEN 128

typedef struct general_statistics_log {
    const gchar name_str[VENDOR_LOG_STRING_LEN];
    const gchar key_str[VENDOR_LOG_STRING_LEN];
} GENERAL_STATISTICS_LOG;

static GENERAL_STATISTICS_LOG g_general_statistics_log_map[] = {
    {"number of read commands:",                                          "r_cmd_num"},
    {"number of write commands:",                                         "w_cmd_num"},
    {"number of logical blocks received:",                                "recv_logic_blocks"},
    {"number of logical blocks transmitted:",                             "transmit_logic_blocks"},
    {"read command processing intervals:",                                "r_cmd_proc_interval"},
    {"write command processing intervals:",                               "w_cmd_proc_interval"},
    {"weighted number of read commands plus write commands:",             "wt_rw"},
    {"weighted read command processing plus write command processing:",   "wt_rw_proc_time"}
};

typedef struct vendor_specific_log {
    guint8 attr_id;
    const gchar name_str[VENDOR_LOG_STRING_LEN];
    const gchar key_str[VENDOR_LOG_STRING_LEN];
} VENDOR_SPECIFIC_LOG;

static VENDOR_SPECIFIC_LOG g_huawei_vendor_specific_log_map[] = {
    {0x01, "Raw_Read_Error_rate",           "rr_err_rate"},
    {0x02, "Raw_Write_Error_rate",          "rw_err_rate"},
    {0x03, "Soft_Read_Error_rate",          "sr_err_rate"},
    {0x04, "Block_Erase_Fail_rate",         "be_fail_rate"},
    {0xC2, "Disk_Temperature",              "dk_temper"},
    {0xC4, "Reallocation_count",            "re_allocount"},
    {0xFB, "Disk_Life_Expend",              "dk_lifeexpd"},
    {0x09, "Power_On_Minutes",              "POT"},
    {0x0C, "Device_Power_Cycle_Count",      "DPCC"},
    {0x0D, "Soft_Read_Count",               "SRC"},
    {0xC7, "CRC_Error_Count(P0)",           "CRC_EC_P0"},
    {0xC8, "CRC_Error_Count(P1)",           "CRC_EC_P1"},
    {0xE1, "Rebuild_Flag",                  "Rflag"},
    {0xE8, "Defect_Block",                  "Dblock"},
    {0xE9, "Total_Erase_Count",             "TEC"},
    {0xEA, "Block_Erase_Fail_Count",        "BEFC"},
    {0xEB, "Block_Program_Fail_Count",      "BPFC"},
    {0xEC, "New_Bad_Block_Count",           "NBBC"},
    {0xEE, "UNC_Error_Count",               "UNC_EC"},
    {0xF1, "Map_Table_Rebuild_Count",       "MTRC"},
    {0xF2, "Capacitor_Status",              "Cstatus"},
    {0xF3, "Former_Pow_Cyc_CRC_Error(P0)",  "FPC_P0"},
    {0xF4, "Former_Pow_Cyc_CRC_Error(P1)",  "FPC_P1"},
    {0xF5, "Hard_Reset_Count(P0)",          "HRC_P0"},
    {0xF6, "Hard_Reset_Count(P1)",          "HRC_P1"},
    {0xF7, "Highest_Temperature",           "HT"},
    {0xF8, "8b/10b_Error_Count(P0)",        "EC_P0"},
    {0xF9, "8b/10b_Error_Count(P1)",        "EC_P1"},
    {0xFA, "Cunrrent_Pending_Sector",       "CPS"},
    {0xD2, "Page_Size",                     "PS"},
    {0xFC, "Sigle_Bit_DDR_ECC_Count",       "OXFC"},
    {0xFD, "Multi_Bit_DDR_ECC_Count",       "OXFD"},
    {0xFE, "Flash_ECC_Count",               "OXFE"}
};

static VENDOR_SPECIFIC_LOG g_kioxia_vendor_specific_log_map[] = {
    {0x00, "Total Number Of Host Writes Processed(GB)",                                "host_write_byte"},
    {0x01, "Maximum Erase Block Count",                                                "max_ebc"},
    {0x02, "Average Erase Block Count",                                                "avg_ebc"},
    {0x03, "Minimum Erase Block Count",                                                "min_ebc"},
    {0x08, "The block of the maximum erase count,the rate of uncorrectable error",     "max_ec_uce"},
    {0x09, "The block near the average erase count,the rate of uncorrectable error",   "avg_ec_uce"},
    {0x0A, "The block of the maximum erase count,the rate of correctable error",       "max_ec_ce"},
    {0x0B, "The block near the average erase count,the rate of correctable error",     "avg_ec_ce"},
    {0x0C, "The block of the maximum erase count,the rate of ECC correction",          "max_ec_ecc"},
    {0x0D, "The block near the average erase count,the rate of ECC correction",        "avg_ec_ecc"},
    {0x10, "Wear Leveling Count",                                                      "WLC"},
    {0x11, "Data Reallocation Count",                                                  "DRC"},
    {0x12, "Program Fail Count(total)",                                                "BPFC"},
    {0x13, "Erase Fail Count(total)",                                                  "BEFC"},
    {0x14, "ECC fail Count(total)",                                                    "UNC_CE"},
    {0x15, "Used Reserved Block Count(total)",                                         "NBBC"},
    {0x16, "Unused Reserved Block Count(total)",                                       "URBC"},
    {0x17, "Chip Fail Count(total)",                                                   "CFC"}
};

/*
 * Description: 诊断sas盘的self test结果
 * History: 1.2019年1月14日,
 * 新生成函数          PN:UADP135084
 */
static void pd_log_handle_sas_self_test_diagnose(guint8 *find_short_long_dst_flag, guint8 *p_self_test,
    gint8 p_self_test_len, PD_SMART_TEST_ANALYSIS *diagnose_result)
{
    if (NULL == find_short_long_dst_flag || NULL == p_self_test || p_self_test_len < SCSI_LOG_SELF_TEST_LOG_DATA_LEN ||
        NULL == diagnose_result) {
        return;
    }
    guint8 res, type, short_long_dst_flag = 0;
    guint8 short_test_id = 1, long_test_id = 2;

    /* Type :  0(Default),          1(Background short), 2(Background long),
               4(Abort background), 5(Foreground short), 6(Foreground long)
       Result: 0(Completed),                 1(Aborted (by user command)), 2(Aborted (device reset ?)),
               3(Unknown error, incomplete), 4(Completed, segment failed), 5(Failed in first segment),
               6(Failed in second segment),  7(Failed in segment -->),     15(Self test in progress ...)
    */

    gint32 n = (p_self_test[6] << 8) | p_self_test[7]; // POT
    res = p_self_test[4] & 0xf;                 // 测试结果
    type = (p_self_test[4] >> 5) & 0x7;         // 测试类型

    debug_log(DLOG_INFO,
        "Diagnose SAS drive short dst item : find_short_long_dst_flag = %d, POT = %d, p_self_test[4] = %d.",
        *find_short_long_dst_flag, n, p_self_test[4]); // 记录测试状态

    // 确认是short dst或者long dst
    short_long_dst_flag = 0;
    if (short_test_id == type || long_test_id == type) {
        short_long_dst_flag = 1;
    }

    // 未找到short 或 long dst记录
    if (!(*find_short_long_dst_flag)) {
        // 首条short 或long dst记录
        if (short_long_dst_flag) {
            // 处于自检状态中，标记测试中，直接返回
            if (res == 0xf) {
                diagnose_result->in_progress = 1;
                debug_log(DLOG_INFO, "SAS drive short dst is in progress.");
                return;
            }
            // 故障标记返回
            if (res >= 3 && res <= 7 && NULL != diagnose_result->result) {
                diagnose_result->result->o_fault_bitmap.pd_short_dst_error = 1;
                debug_log(DLOG_INFO, "SAS drive first self test is error.");
                return;
            }
        }
    // 非首条查找到的short 或 long dst，仅判断long dst的测试结果
    } else if (long_test_id == type) {
        // 故障标记返回
        if (res >= 3 && res <= 7 && NULL != diagnose_result->result) {
            diagnose_result->result->o_fault_bitmap.pd_short_dst_error = 1;
            debug_log(DLOG_INFO, "SAS drive self test is error.");
            return;
        }
    }
    // 更新find_short_long_dst
    if (short_long_dst_flag) {
        *find_short_long_dst_flag = 1;
    }
}

/*
 * Description: 处理sas盘self-test数据
 * History: 1.2018年5月7日
 * 新生成函数
 * 2.2018年7月25日
 */
void pd_log_handle_sas_self_test(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *pd_log_jso)
{
    gint32 num, i, k, n, res;
    gint32 no_header = 1;
    gchar buff[32];
    guint8 *p_self_test = NULL;
    guint64 ull_tmp = 0;
    const gchar* self_test_code[] = {
        "Default         ", "Background short", "Background long ", "Reserved(3)     ",
        "Abort background", "Foreground short", "Foreground long ", "Reserved(7)     "
    };

    const gchar* self_test_result[] = {
        "Completed                ",
        "Aborted (by user command)", "Aborted (device reset ?) ",
        "Unknown error, incomplete", "Completed, segment failed",
        "Failed in first segment  ", "Failed in second segment ",
        "Failed in segment -->    ", "Reserved(8)              ",
        "Reserved(9)              ", "Reserved(10)             ",
        "Reserved(11)             ", "Reserved(12)             ",
        "Reserved(13)             ", "Reserved(14)             ",
        "Self test in progress ..."
    };

    PD_SMART_TEST_ANALYSIS *diagnose_result = (PD_SMART_TEST_ANALYSIS *)out_put;
    guint8 find_short_long_dst = 0;
    guint8 tmp_data_error = 0;
    gboolean failed_flag = FALSE;

    /* pd_log_jso在add时判空，此处不判空 */
    if (pd_log == NULL) {
        return;
    }

    tmp_data_error = ((SML_SUCCESS != pd_log->SASDevice.selftest.result &&
        SML_ERR_PD_SCSI_RESP_TRUNCATED != pd_log->SASDevice.selftest.result) ||
        NULL == pd_log->SASDevice.selftest.data || 0 == pd_log->SASDevice.selftest.data_length ||
        (PD_LOG_DATA_MAX_LEN < pd_log->SASDevice.selftest.data_length));

    if (tmp_data_error) {
        return;
    }

    guint8 *self_test_data = (guint8 *)g_malloc0(PD_LOG_DATA_MAX_LEN);
    if (NULL == self_test_data) {
        return;
    }

    (void)memset_s(self_test_data, PD_LOG_DATA_MAX_LEN, 0, PD_LOG_DATA_MAX_LEN);
    errno_t safe_fun_ret = memcpy_s(self_test_data, PD_LOG_DATA_MAX_LEN, pd_log->SASDevice.selftest.data,
        pd_log->SASDevice.selftest.data_length);
    if (safe_fun_ret != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
    }

    if ((self_test_data[0] & 0x3f) != SCSI_LOG_PAGE_SELFTEST_RESULTS) {
        pd_log_fprintf(file, "Self-test Log Sense Failed, page mismatch\n");
        g_free(self_test_data);
        return;
    }

    num = (self_test_data[2] << 8) + self_test_data[3];
    if (num != (PD_LOG_SAS_SELF_TEST_MAX_BYTES - SCSI_LOG_PAGE_HEADER_SIZE)) {
        pd_log_fprintf(file, "Self-test Log Sense length is 0x%x not %d bytes\n", num,
            PD_LOG_SAS_SELF_TEST_MAX_BYTES - SCSI_LOG_PAGE_HEADER_SIZE);
        g_free(self_test_data);
        return;
    }
    Json *self_test_array = NULL;
    if (JsonArrayCreate(&self_test_array) != JSON_OK) {
        g_free(self_test_data);
        return;
    }
    for (k = 0, p_self_test = self_test_data + SCSI_LOG_PAGE_HEADER_SIZE; k < SCSI_LOG_SELF_TEST_LOG_NUM;
        ++k, p_self_test += SCSI_LOG_SELF_TEST_LOG_DATA_LEN) {
        // ACCUMULATED POWER ON HOURS
        n = (p_self_test[6] << 8) | p_self_test[7];
        if ((0 == n) && (0 == p_self_test[4])) {
            break;
        }
        // 故障诊断
        /* BEGIN: Added by, 2019/1/17   PN:UADP135084 */
        pd_log_handle_sas_self_test_diagnose(&find_short_long_dst, p_self_test, SCSI_LOG_SELF_TEST_LOG_DATA_LEN,
            diagnose_result);
        if (NULL != diagnose_result && NULL != diagnose_result->result &&
            1 == diagnose_result->result->o_fault_bitmap.pd_short_dst_error) {
            gint32 ret = snprintf_s(diagnose_result->result->io_buf, sizeof(diagnose_result->result->io_buf),
                sizeof(diagnose_result->result->io_buf) - 1, "the result of %s is %s",
                self_test_code[(p_self_test[4] >> 5) & 0x7],
                self_test_result[p_self_test[4] & 0xf]); //  测试类型和测试结果
            if (0 >= ret) {
                debug_log(DLOG_ERROR, "%s: snprintf_s error.", __FUNCTION__);
            }

            debug_log(DLOG_INFO, "Self test error of %s.", pd_log->pd_device_name);
        }
        if (NULL != diagnose_result && NULL != diagnose_result->result &&
            (1 == diagnose_result->in_progress || 1 == diagnose_result->result->o_fault_bitmap.pd_short_dst_error)) {
            g_free(self_test_data);
            JsonObjectRelease(self_test_array);
            return;
        }
        /* END:   Added by, 2019/1/17 */

        if (no_header) {
            pd_log_fprintf(file,
                "Num  Test              Status                 segment  LifeTime  LBA_first_err [SK ASC ASQ]\n"
                "     Description                              number   (hours)\n");
            no_header = 0;
        }

        // PARAMETER CODE (test number) 、 SELF-TEST CODE
        pd_log_fprintf(file, "#%2d  %s", (p_self_test[0] << 8) | p_self_test[1],
            self_test_code[(p_self_test[4] >> 5) & 0x7]);

        // SELF-TEST RESULTS
        res = p_self_test[4] & 0xf;
        pd_log_fprintf(file, "  %s", self_test_result[res]);
        Json *self_test_node = NULL;
        if (strstr(self_test_result[res], "failed") || strstr(self_test_result[res], "Failed")) {
            failed_flag = TRUE;
            if (JsonObjectCreate(&self_test_node) != JSON_OK) {
                continue;
            }
        }
        if (failed_flag) {
            Json *json_type = NULL;
            JsonStringCreate(self_test_code[(p_self_test[4] >> 5) & 0x7], &json_type);
            JsonObjectItemSet(self_test_node, "type", json_type);
            Json *json_failure_status = NULL;
            JsonStringCreate(self_test_code[res], &json_failure_status);
            JsonObjectItemSet(self_test_node, "failure_status", json_failure_status);
        }

        if (p_self_test[5]) {
            pd_log_fprintf(file, " %3d", (gint32)p_self_test[5]);
            if (failed_flag) {
                memset_s(buff, sizeof(buff), 0, sizeof(buff));
                (void)snprintf_s(buff, sizeof(buff), sizeof(buff) - 1, "%d", (gint32)p_self_test[5]);
                Json *json_segment_number = NULL;
                JsonStringCreate(buff, &json_segment_number);
                JsonObjectItemSet(self_test_node, "segment_number", json_segment_number);
            }
        } else {
            pd_log_fprintf(file, "   -");
            if (failed_flag) {
                JsonObjectItemSet(self_test_node, "segment_number", NULL);
            }
        }

        if (n == 0 && res == 0xf) {
            // self-test in progress
            pd_log_fprintf(file, "     NOW");
            if (failed_flag) {
                Json *json_pot_now = NULL;
                JsonStringCreate("NOW", &json_pot_now);
                JsonObjectItemSet(self_test_node, "pot", json_pot_now);
            }
        } else {
            pd_log_fprintf(file, "   %5d", n);
            if (failed_flag) {
                memset_s(buff, sizeof(buff), 0, sizeof(buff));
                (void)snprintf_s(buff, sizeof(buff), sizeof(buff) - 1, "%d", n);
                Json *json_pot = NULL;
                JsonStringCreate(buff, &json_pot);
                JsonObjectItemSet(self_test_node, "pot", json_pot);
            }
        }

        // ADDRESS OF FIRST FAILURE
        for (i = 0; i < 8; i++) {
            ull_tmp <<= 8;
            ull_tmp |= p_self_test[i + 8];
        }

        if ((~(guint64)0 != ull_tmp) && (res > 0) && (res < 0xf)) {
            (void)memset_s(buff, sizeof(buff), 0, sizeof(buff));
            (void)snprintf_s(buff, sizeof(buff), sizeof(buff) - 1, "%" G_GUINT64_FORMAT, ull_tmp);
            pd_log_fprintf(file, "%18s", buff);
            if (failed_flag) {
                Json *json_lba = NULL;
                JsonStringCreate(buff, &json_lba);
                JsonObjectItemSet(self_test_node, "lba", json_lba);
            }
        } else {
            pd_log_fprintf(file, "                 -");
            if (failed_flag) {
                JsonObjectItemSet(self_test_node, "lba", NULL);
            }
        }

        // if SENSE KEY nonzero, then print ADDITIONAL SENSE CODE、ADDITIONAL SENSE CODE QUALIFIER
        if (p_self_test[16] & 0xf) {
            pd_log_fprintf(file, " [0x%x 0x%x 0x%x]\n", p_self_test[16] & 0xf, p_self_test[17], p_self_test[18]);
            if (failed_flag) {
                (void)memset_s(buff, sizeof(buff), 0, sizeof(buff));
                (void)snprintf_s(buff, sizeof(buff), sizeof(buff) - 1, "0x%x", p_self_test[16] & 0xf);
                Json *json_key = NULL;
                JsonStringCreate(buff, &json_key);
                JsonObjectItemSet(self_test_node, "key", json_key);
                (void)memset_s(buff, sizeof(buff), 0, sizeof(buff));
                (void)snprintf_s(buff, sizeof(buff), sizeof(buff) - 1, "0x%x", p_self_test[17]);
                Json *json_asc = NULL;
                JsonStringCreate(buff, &json_asc);
                JsonObjectItemSet(self_test_node, "asc", json_asc);
                (void)memset_s(buff, sizeof(buff), 0, sizeof(buff));
                (void)snprintf_s(buff, sizeof(buff), sizeof(buff) - 1, "0x%x", p_self_test[18]);
                Json *json_ascq = NULL;
                JsonStringCreate(buff, &json_ascq);
                JsonObjectItemSet(self_test_node, "ascq", json_ascq);
            }
        } else {
            pd_log_fprintf(file, " [-   -    -]\n");
            if (failed_flag) {
                JsonObjectItemSet(self_test_node, "key", NULL);
                JsonObjectItemSet(self_test_node, "asc", NULL);
                JsonObjectItemSet(self_test_node, "ascq", NULL);
            }
        }

        if (failed_flag) {
            guint32 array_size = 0;
            JsonArraySizeGet(self_test_array, &array_size);
            (void)JsonArrayItemInsert(self_test_array, array_size, self_test_node);
            failed_flag = FALSE;
        }
    }

    if (no_header) {
        pd_log_fprintf(file, "No self-tests have been logged\n");
    }

    if (NULL != pd_log_jso) {
        JsonObjectItemSet(pd_log_jso, "selftest_log", self_test_array);
    } else {
        JsonObjectRelease(self_test_array);
    }

    g_free(self_test_data);
}

/*
 * Description: sas盘error counter(read/write/verify)数据解析
 * History: 1.2018年5月11日
 * 新生成函数
 * 2.2018年7月25日
 */
void pd_log_scsi_decode_err_counter(guchar *error_counter_data, guint32 error_counter_data_len,
    SCSI_ERROR_COUNTER_S *error_counter, guint32 counter_size)
{
    guint32 i, j = 0;
    guint32 page_code, page_length;
    guchar *xp_error_counter = NULL;
    guint64 *ull_p_error_counter = NULL;

    if (NULL == error_counter_data || SCSI_LOG_PAGE_HEADER_SIZE > error_counter_data_len || NULL == error_counter ||
        counter_size == 0) {
        return;
    }
    (void)memset_s(error_counter, sizeof(SCSI_ERROR_COUNTER_S), 0, sizeof(SCSI_ERROR_COUNTER_S));

    guint32 num = (error_counter_data[2] << 8) | error_counter_data[3];
    if (error_counter_data_len < num) {
        return;
    }

    guchar *p_error_counter = &error_counter_data[0] + SCSI_LOG_PAGE_HEADER_SIZE;

    while (num > 3) {
        page_code = (p_error_counter[0] << 8) | p_error_counter[1];
        page_length = p_error_counter[3] + SCSI_LOG_PAGE_HEADER_SIZE;

        if (page_code > 6) {
            error_counter->got_extra_pc = 1;
            ull_p_error_counter = &error_counter->counter[7];
        } else {
            error_counter->got_pc[page_code] = 1;
            ull_p_error_counter = &error_counter->counter[page_code];
        }

        i = page_length - SCSI_LOG_PAGE_HEADER_SIZE;
        xp_error_counter = p_error_counter + SCSI_LOG_PAGE_HEADER_SIZE;

        if (i > sizeof(*ull_p_error_counter)) {
            xp_error_counter += (i - sizeof(*ull_p_error_counter));
            i = sizeof(*ull_p_error_counter);
        }

        *ull_p_error_counter = 0;

        for (j = 0; j < i; ++j) {
            if (j > 0) {
                *ull_p_error_counter <<= 8;
            }

            *ull_p_error_counter |= xp_error_counter[j];
        }

        num -= page_length;
        p_error_counter += page_length;
    }
}

static gint32 determine_access_method(const gint32 index_page, gchar **access_method)
{
    gint32 ret_value = RET_OK;
    switch (index_page) {
        case 0: {
            *access_method = "read";
            break;
        }
        case 1: {
            *access_method = "write";
            break;
        }
        case 2: {
            *access_method = "verify";
            break;
        }
        default: {
            debug_log(DLOG_DEBUG, "%s: index_page not in the list.", __FUNCTION__);
            ret_value = RET_ERR;
        }
    }
    return ret_value;
}

/*
 * Description: 将sas盘的error count log添加到json对象中
 */
static void pd_log_add_sas_error_log(gint32 index_page, SCSI_ERROR_COUNTER_S *data, Json *out_put_jso)
{
    gchar property_name[TMP_STR_LEN] = {0};
    gchar *tmp_name = NULL;
    gchar tmp_str[TMP_STR_LEN] = {0};
    const gchar* property_map[] = {"ecsd", "ecpd", "operations", "ec", "times", "processed", "uce"};
    guint8 i = 0;
    gdouble gb_processed = 0.0;

    if (NULL == data || NULL == out_put_jso) {
        return;
    }
    gint32 ret_val = determine_access_method(index_page, &tmp_name);
    if (ret_val == RET_ERR) {
        return;
    }

    /*
     * data->counter仅使用前7个(0-6)数据，分别是:
     * "ecsd", "ecpd", "operations", "ec", "times", "processed", "uce"
     */
    for (i = 0; i < 7; i++) {
        (void)memset_s(property_name, TMP_STR_LEN, 0, TMP_STR_LEN);
        ret_val = snprintf_s(property_name, TMP_STR_LEN, TMP_STR_LEN - 1, "%s_%s", tmp_name, property_map[i]);
        if (ret_val <= 0) {
            continue;
        }
        memset_s(tmp_str, TMP_STR_LEN, 0, TMP_STR_LEN);
        if (5 == i) {
            gb_processed = data->counter[i] / 1000000000.0;
            ret_val = snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%.3f", gb_processed);
        } else {
            ret_val = snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%" G_GUINT64_FORMAT, data->counter[i]);
        }
        if (ret_val <= 0) {
            continue;
        }
        Json *str_obj = NULL;
        JsonStringCreate(tmp_str, &str_obj);
        JsonObjectItemSet(out_put_jso, property_name, str_obj);
    }
}

/*
 * Description: sas盘non-medium error counter数据解析
 * History: 1.2018年5月11日
 * 新生成函数
 * 2.2018年7月25日
 */
void pd_log_scsi_decode_non_medium_err_counter(guchar *non_medium_data, guint32 non_medium_data_len,
    SCSI_NON_MEDIUM_ERROR_S *non_medium)
{
    guint32 i, j = 0;
    guint32 page_code, page_length;
    guchar *p_error_counter = NULL;
    guchar *xp_error_counter = NULL;

    if (NULL == non_medium_data || SCSI_LOG_PAGE_HEADER_SIZE > non_medium_data_len || NULL == non_medium) {
        return;
    }
    (void)memset_s(non_medium, sizeof(SCSI_NON_MEDIUM_ERROR_S), 0, sizeof(SCSI_NON_MEDIUM_ERROR_S));

    guint32 num = (non_medium_data[2] << 8) | non_medium_data[3];
    if (non_medium_data_len < num) {
        return;
    }

    p_error_counter = &non_medium_data[0] + SCSI_LOG_PAGE_HEADER_SIZE;
    guint32 len = (guint32)sizeof(non_medium->counter_pc0);

    while (num > 3) {
        page_code = (p_error_counter[0] << 8) | p_error_counter[1];
        page_length = p_error_counter[3] + SCSI_LOG_PAGE_HEADER_SIZE;

        switch (page_code) {
            case 0:
                non_medium->got_pc0 = 1;
                i = page_length - SCSI_LOG_PAGE_HEADER_SIZE;
                xp_error_counter = p_error_counter + SCSI_LOG_PAGE_HEADER_SIZE;

                if (i > len) {
                    xp_error_counter += (i - len);
                    i = len;
                }

                non_medium->counter_pc0 = 0;

                for (j = 0; j < i; ++j) {
                    if (j > 0) {
                        non_medium->counter_pc0 <<= 8;
                    }

                    non_medium->counter_pc0 |= xp_error_counter[j];
                }

                break;

            case 0x8009:
                non_medium->got_tfe_h = 1;
                i = page_length - SCSI_LOG_PAGE_HEADER_SIZE;
                xp_error_counter = p_error_counter + SCSI_LOG_PAGE_HEADER_SIZE;

                if (i > len) {
                    xp_error_counter += (i - len);
                    i = len;
                }

                non_medium->counter_tfe_h = 0;

                for (j = 0; j < i; ++j) {
                    if (j > 0) {
                        non_medium->counter_tfe_h <<= 8;
                    }

                    non_medium->counter_tfe_h |= xp_error_counter[j];
                }

                break;

            case 0x8015:
                non_medium->got_pe_h = 1;
                i = page_length - SCSI_LOG_PAGE_HEADER_SIZE;
                xp_error_counter = p_error_counter + SCSI_LOG_PAGE_HEADER_SIZE;

                if (i > len) {
                    xp_error_counter += (i - len);
                    i = len;
                }

                non_medium->counter_pe_h = 0;

                for (j = 0; j < i; ++j) {
                    if (j > 0) {
                        non_medium->counter_pe_h <<= 8; /* 8:每次左移8位，将xp_error_counter里的内容拼起来 */
                    }

                    non_medium->counter_pe_h |= xp_error_counter[j];
                }

                break;

            default:
                non_medium->got_extra_pc = 1;
                break;
        }

        num -= page_length;
        p_error_counter += page_length;
    }
}

/*
 * Description: 处理sas盘read、write、verify、non-medium error cnt数据
 * History: 1.2018年5月11日
 * 新生成函数
 * 2.2018年7月25日
 */
void pd_log_handle_sas_error_cnt(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *pd_log_jso)
{
    SCSI_ERROR_COUNTER_S error_cnt_arr[3];
    SCSI_NON_MEDIUM_ERROR_S nonmedium_error_cnt;
    SCSI_ERROR_COUNTER_S *ecp = NULL;
    gint32 print_flag[] = {0, 0, 0};
    guint8 need_print = 0;

    gdouble gb_processed = 0.0;
    gint32 j;
    const gchar * const page_names[] = {"read:   ", "write:  ", "verify: "};
    SML_PD_FAULT_ANALYSIS *result = (SML_PD_FAULT_ANALYSIS *)out_put;
    const guint64 threshold[] = {100, 50, 100};
    gchar tmp_str[TMP_STR_LEN] = {0};
    Json *error_log_jso = NULL;

    /* pd_log_jso在add时判空，此处不判空 */
    if (pd_log == NULL) {
        return;
    }

    guint8 *error_cnt_data = (guint8 *)g_malloc0(PD_LOG_DATA_MAX_LEN);
    if (NULL == error_cnt_data) {
        return;
    }

    guint8 error_flag = ((SML_SUCCESS != pd_log->SASDevice.read_error_cnt.result &&
        SML_ERR_PD_SCSI_RESP_TRUNCATED != pd_log->SASDevice.read_error_cnt.result) ||
        NULL == pd_log->SASDevice.read_error_cnt.data || 0 == pd_log->SASDevice.read_error_cnt.data_length ||
        (PD_LOG_DATA_MAX_LEN < pd_log->SASDevice.read_error_cnt.data_length));

    if (!error_flag) {
        (void)memset_s(error_cnt_data, PD_LOG_DATA_MAX_LEN, 0, PD_LOG_DATA_MAX_LEN);
        errno_t safe_fun_ret = memcpy_s(error_cnt_data, PD_LOG_DATA_MAX_LEN, pd_log->SASDevice.read_error_cnt.data,
            pd_log->SASDevice.read_error_cnt.data_length);
        if (safe_fun_ret != EOK) {
            debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
        }

        if ((error_cnt_data[0] & 0x3f) != SCSI_LOG_PAGE_READ_ERROR_COUNTER) {
            pd_log_fprintf(file, "Read Error counter Log Sense Failed, page mismatch\n");
        } else {
            pd_log_scsi_decode_err_counter(error_cnt_data, PD_LOG_DATA_MAX_LEN, &error_cnt_arr[0],
                sizeof(SCSI_ERROR_COUNTER_S));
            print_flag[0] = 1;
        }
    }

    error_flag = ((SML_SUCCESS != pd_log->SASDevice.write_error_cnt.result &&
        SML_ERR_PD_SCSI_RESP_TRUNCATED != pd_log->SASDevice.write_error_cnt.result) ||
        NULL == pd_log->SASDevice.write_error_cnt.data || 0 == pd_log->SASDevice.write_error_cnt.data_length ||
        (PD_LOG_DATA_MAX_LEN < pd_log->SASDevice.write_error_cnt.data_length));

    if (!error_flag) {
        (void)memset_s(error_cnt_data, PD_LOG_DATA_MAX_LEN, 0, PD_LOG_DATA_MAX_LEN);
        errno_t safe_fun_ret = memcpy_s(error_cnt_data, PD_LOG_DATA_MAX_LEN, pd_log->SASDevice.write_error_cnt.data,
            pd_log->SASDevice.write_error_cnt.data_length);
        if (safe_fun_ret != EOK) {
            debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
        }

        if ((error_cnt_data[0] & 0x3f) != SCSI_LOG_PAGE_WRITE_ERROR_COUNTER) {
            pd_log_fprintf(file, "Write Error counter Log Sense Failed, page mismatch\n");
        } else {
            pd_log_scsi_decode_err_counter(error_cnt_data, PD_LOG_DATA_MAX_LEN, &error_cnt_arr[1],
                sizeof(SCSI_ERROR_COUNTER_S));
            print_flag[1] = 1;
        }
    }

    error_flag = ((SML_SUCCESS != pd_log->SASDevice.verify_error_cnt.result &&
        SML_ERR_PD_SCSI_RESP_TRUNCATED != pd_log->SASDevice.verify_error_cnt.result) ||
        NULL == pd_log->SASDevice.verify_error_cnt.data || 0 == pd_log->SASDevice.verify_error_cnt.data_length ||
        (PD_LOG_DATA_MAX_LEN < pd_log->SASDevice.verify_error_cnt.data_length));

    if (!error_flag) {
        (void)memset_s(error_cnt_data, PD_LOG_DATA_MAX_LEN, 0, PD_LOG_DATA_MAX_LEN);
        errno_t safe_fun_ret = memcpy_s(error_cnt_data, PD_LOG_DATA_MAX_LEN, pd_log->SASDevice.verify_error_cnt.data,
            pd_log->SASDevice.verify_error_cnt.data_length);
        if (safe_fun_ret != EOK) {
            debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
        }

        if ((error_cnt_data[0] & 0x3f) != SCSI_LOG_PAGE_VERIFY_ERROR_COUNTER) {
            pd_log_fprintf(file, "Verify Error counter Log Sense Failed, page mismatch\n");
        } else {
            pd_log_scsi_decode_err_counter(error_cnt_data, PD_LOG_DATA_MAX_LEN, &error_cnt_arr[2],
                sizeof(SCSI_ERROR_COUNTER_S));
            print_flag[2] = 1;
        }
    }

    // 是否有read、write和verify error需要打印
    need_print = (print_flag[0] || print_flag[1] || print_flag[2]);
    if (JsonObjectCreate(&error_log_jso) != JSON_OK) {
        g_free(error_cnt_data);
        return;
    }

    if (need_print) {
        pd_log_fprintf(file,
            "             Errors Corrected by                 Total     Correction       Gigabytes      Total\n");
        pd_log_fprintf(file,
            "                 ECC              rereads/      errors     algorithm        processed      uncorrected\n");
        pd_log_fprintf(file,
            "             fast  |  delayed     rewrites    corrected    invocations     [10^9 bytes]    errors\n");

        for (j = 0; j < 3; ++j) {
            if (print_flag[j] == 0) {
                continue;
            }

            ecp = &error_cnt_arr[j];
            pd_log_fprintf(file, "%s%10llu %10llu  %10llu  %10llu   %10llu", page_names[j], ecp->counter[0],
                ecp->counter[1], ecp->counter[2], ecp->counter[3], ecp->counter[4]);
            gb_processed = ecp->counter[5] / 1000000000.0;
            pd_log_fprintf(file, "   %12.3f    %10llu\n", gb_processed, ecp->counter[6]);

            pd_log_add_sas_error_log(j, ecp, error_log_jso);

            // 诊断故障
            /* BEGIN: Added by, 2019/1/17   PN:UADP135084 */
            if (NULL != result && ecp->counter[6] > threshold[j]) {
                result->o_fault_bitmap.pd_smart_log_error = 1;
                gint32 i_ret = snprintf_s(result->io_buf, sizeof(result->io_buf), sizeof(result->io_buf) - 1,
                    "%s%" G_GUINT64_FORMAT ", threshold: %" G_GUINT64_FORMAT, page_names[j], ecp->counter[6],
                    threshold[j]); // 当前值和阈值
                if (i_ret <= 0) {
                    debug_log(DLOG_ERROR, "%s: snprintf_s fail, ret = %d\n", __FUNCTION__, i_ret);
                }
                debug_log(DLOG_INFO, "Error count( %s%" G_GUINT64_FORMAT ") error of %s.", page_names[j],
                    ecp->counter[6],
                    pd_log->pd_device_name); // 记录日志
                g_free(error_cnt_data);
                JsonObjectRelease(error_log_jso);
                return;
            }
            /* END:   Added by, 2019/1/17 */
        }
    }

    error_flag = ((SML_SUCCESS != pd_log->SASDevice.nonmedium_error_cnt.result &&
        SML_ERR_PD_SCSI_RESP_TRUNCATED != pd_log->SASDevice.nonmedium_error_cnt.result) ||
        NULL == pd_log->SASDevice.nonmedium_error_cnt.data || 0 == pd_log->SASDevice.nonmedium_error_cnt.data_length ||
        (PD_LOG_DATA_MAX_LEN < pd_log->SASDevice.nonmedium_error_cnt.data_length));

    if (!error_flag) {
        (void)memset_s(error_cnt_data, PD_LOG_DATA_MAX_LEN, 0, PD_LOG_DATA_MAX_LEN);
        errno_t safe_fun_ret = memcpy_s(error_cnt_data, PD_LOG_DATA_MAX_LEN, pd_log->SASDevice.nonmedium_error_cnt.data,
            pd_log->SASDevice.nonmedium_error_cnt.data_length);
        if (safe_fun_ret != EOK) {
            debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
        }

        if ((error_cnt_data[0] & 0x3f) != SCSI_LOG_PAGE_NON_MEDIUM_ERROR) {
            pd_log_fprintf(file, "Non-medium Error counter Log Sense Failed, page mismatch\n");
        } else {
            pd_log_scsi_decode_non_medium_err_counter(error_cnt_data, PD_LOG_DATA_MAX_LEN, &nonmedium_error_cnt);
            if (nonmedium_error_cnt.got_pc0) {
                (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%" G_GUINT64_FORMAT,
                    nonmedium_error_cnt.counter_pc0);
                Json *str_obj = NULL;
                JsonStringCreate(tmp_str, &str_obj);
                JsonObjectItemSet(error_log_jso, "nonmedium_ec", str_obj);
                pd_log_fprintf(file, "\nNon-medium error count: %8llu\n", nonmedium_error_cnt.counter_pc0);
            }

            if (nonmedium_error_cnt.got_tfe_h) {
                pd_log_fprintf(file, "Track following error count [Hitachi]: %8llu\n",
                    nonmedium_error_cnt.counter_tfe_h);
            }

            if (nonmedium_error_cnt.got_pe_h) {
                pd_log_fprintf(file, "Positioning error count [Hitachi]: %8llu\n", nonmedium_error_cnt.counter_pe_h);
            }
        }
    }
    gchar *json_str = JsonPrint(error_log_jso);
    if (NULL == pd_log_jso || 0 == g_strcmp0(json_str, "{ }")) {
        JsonObjectRelease(error_log_jso);
    } else {
        JsonObjectItemSet(pd_log_jso, "error_count_log", error_log_jso);
    }
    JsonStringValueFree(json_str);
    g_free(error_cnt_data);
}

/*
 * Description: 解析phy info
 * History: 1.2018年5月11日
 * 新生成函数
 */
static void pd_log_scsi_show_phy_event_info(FILE *file, gint32 phy_event_source, guint32 val, guint32 thresh_val)
{
    guint32 temp;

    switch (phy_event_source) {
        case SML_PHY_EVENT_CODE_NO_EVENT:
            pd_log_fprintf(file, "     No event\n");
            break;

        case SML_PHY_EVENT_CODE_INVALID_DWORD:
            pd_log_fprintf(file, "     Invalid word count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_RUNNING_DISPARITY_ERROR:
            pd_log_fprintf(file, "     Running disparity error count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_LOSS_DWORD_SYNC:
            pd_log_fprintf(file, "     Loss of dword synchronization count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_PHY_RESET_PROBLEM:
            pd_log_fprintf(file, "     Phy reset problem count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_ELASTICITY_BUF_OVERFLOW:
            pd_log_fprintf(file, "     Elasticity buffer overflow count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_RX_ERROR:
            pd_log_fprintf(file, "     Received ERROR  count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_RX_ADDR_FRAME_ERROR:
            pd_log_fprintf(file, "     Received address frame error count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_TX_AC_OPEN_REJECT:
            pd_log_fprintf(file, "     Transmitted abandon-class OPEN_REJECT count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_RX_AC_OPEN_REJECT:
            pd_log_fprintf(file, "     Received abandon-class OPEN_REJECT count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_TX_RC_OPEN_REJECT:
            pd_log_fprintf(file, "     Transmitted retry-class OPEN_REJECT count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_RX_RC_OPEN_REJECT:
            pd_log_fprintf(file, "     Received retry-class OPEN_REJECT count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_RX_AIP_PARTIAL_WAITING_ON:
            pd_log_fprintf(file, "     Received AIP (WATING ON PARTIAL) count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_RX_AIP_CONNECT_WAITING_ON:
            pd_log_fprintf(file, "     Received AIP (WAITING ON CONNECTION) count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_TX_BREAK:
            pd_log_fprintf(file, "     Transmitted BREAK count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_RX_BREAK:
            pd_log_fprintf(file, "     Received BREAK count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_BREAK_TIMEOUT:
            pd_log_fprintf(file, "     Break timeout count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_CONNECTION:
            pd_log_fprintf(file, "     Connection count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_PEAKTX_PATHWAY_BLOCKED:
            pd_log_fprintf(file, "     Peak transmitted pathway blocked count: %u\n", val & 0xff);
            pd_log_fprintf(file, "         Peak value detector threshold: %u\n", thresh_val & 0xff);
            break;

        case SML_PHY_EVENT_CODE_PEAKTX_ARB_WAIT_TIME:
            temp = val & 0xffff;
            if (temp < 0x8000) {
                pd_log_fprintf(file, "     Peak transmitted arbitration wait time (us): %u\n", temp);
            } else {
                pd_log_fprintf(file, "     Peak transmitted arbitration wait time (ms): %u\n", 33 + (temp - 0x8000));
            }

            temp = thresh_val & 0xffff;
            if (temp < 0x8000) {
                pd_log_fprintf(file, "         Peak value detector threshold (us): %u\n", temp);
            } else {
                pd_log_fprintf(file, "         Peak value detector threshold (ms): %u\n", 33 + (temp - 0x8000));
            }

            break;

        case SML_PHY_EVENT_CODE_PEAK_ARB_WAIT_TIME:
            pd_log_fprintf(file, "     Peak arbitration time (us): %u\n", val);
            pd_log_fprintf(file, "         Peak value detector threshold: %u\n", thresh_val);
            break;

        case SML_PHY_EVENT_CODE_PEAK_CONNECT_TIME:
            pd_log_fprintf(file, "     Peak connection time (us): %u\n", val);
            pd_log_fprintf(file, "         Peak value detector threshold: %u\n", thresh_val);
            break;

        case SML_PHY_EVENT_CODE_TX_SSP_FRAMES:
            pd_log_fprintf(file, "     Transmitted SSP frame count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_RX_SSP_FRAMES:
            pd_log_fprintf(file, "     Received SSP frame count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_TX_SSP_ERROR_FRAMES:
            pd_log_fprintf(file, "     Transmitted SSP frame error count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_RX_SSP_ERROR_FRAMES:
            pd_log_fprintf(file, "     Received SSP frame error count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_TX_CREDIT_BLOCKED:
            pd_log_fprintf(file, "     Transmitted CREDIT_BLOCKED count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_RX_CREDIT_BLOCKED:
            pd_log_fprintf(file, "     Received CREDIT_BLOCKED count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_TX_SATA_FRAMES:
            pd_log_fprintf(file, "     Transmitted SATA frame count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_RX_SATA_FRAMES:
            pd_log_fprintf(file, "     Received SATA frame count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_SATA_OVERFLOW:
            pd_log_fprintf(file, "     SATA flow control buffer overflow count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_TX_SMP_FRAMES:
            pd_log_fprintf(file, "     Transmitted SMP frame count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_RX_SMP_FRAMES:
            pd_log_fprintf(file, "     Received SMP frame count: %u\n", val);
            break;

        case SML_PHY_EVENT_CODE_RX_SMP_ERROR_FRAMES:
            pd_log_fprintf(file, "     Received SMP frame error count: %u\n", val);
            break;

        default:
            break;
    }
}

/*
 * Description : 处理Protocol-Specific Port log中sas phy log descriptor部分头部信息
 * History：2021-3-12  新生成函数
 */
static void pd_log_handle_sas_phy_log_descriptor_head(FILE *file, guchar *p_param_data, guint32 portid,
    Json *out_put_jso)
{
    gchar key_str[TMP_STR_LEN] = {0};
    gchar val_str[TMP_STR_LEN] = {0};

    pd_log_fprintf(file, "  phy identifier = %d\n", p_param_data[1]); // byte 1为port id
    (void)snprintf_s(key_str, TMP_STR_LEN, TMP_STR_LEN - 1, "p_id_%u", portid);
    (void)snprintf_s(val_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%d", (gchar)p_param_data[1]);
    Json *str_obj  = NULL;
    JsonStringCreate(val_str, &str_obj);
    JsonObjectItemSet(out_put_jso, key_str, str_obj);
}

/*
 * Description : 处理Protocol-Specific Port log中sas phy log descriptor部分attached device type信息
 * History：2021-3-12  新生成函数
 */
static void pd_log_handle_sas_phy_log_descriptor_attached_device_type(FILE *file, guchar *p_param_data, guint32 portid,
    Json *out_put_jso)
{
    guint32 dev_type = ((0x70 & p_param_data[4]) >> 4); // byte 4~6为device type
    gchar str[TMP_STR_LEN] = {0};
    const gchar* atta_dev_type_des[] = {
        "no device attached", "SAS or SATA device",
        "expander device", "expander device (fanout)"
    };
    guint8 atta_type_des_num = (guint8)G_N_ELEMENTS(atta_dev_type_des);
    errno_t safe_fun_ret = EOK;

    if (dev_type < atta_type_des_num) {
        safe_fun_ret = strncpy_s(str, TMP_STR_LEN, atta_dev_type_des[dev_type], strlen(atta_dev_type_des[dev_type]));
        if (safe_fun_ret != EOK) {
            debug_log(DLOG_ERROR, "%s: strncpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
        }
    } else {
        (void)snprintf_s(str, TMP_STR_LEN, TMP_STR_LEN - 1, "reserved [%u]", dev_type);
    }

    pd_log_fprintf(file, "    attached device type: %s\n", str);
}

/*
 * Description : 处理Protocol-Specific Port log中sas phy log descriptor部分reason信息
 * History：2021-3-12  新生成函数
 */
static void pd_log_handle_sas_phy_log_descriptor_reason(FILE *file, guchar *p_param_data, guint32 portid,
    Json *out_put_jso)
{
    errno_t safe_fun_ret = EOK;
    gchar str[TMP_STR_LEN] = {0};
    const gchar* atta_reason_des[] = {
        "unknown", "power on", "hard reset",
        "SMP phy control function", "loss of dword synchronization",
        "mux mix up", "I_T nexus loss timeout for STP/SATA",
        "break timeout timer expired",
        "phy test function stopped", "expander device reduced functionality"
    };
    guint8 atta_reason_des_num = (guint8)G_N_ELEMENTS(atta_reason_des);

    guint32 attach_reason = 0xf & p_param_data[4]; // byte 4低4bit为attached reason
    if (attach_reason < atta_reason_des_num) {
        safe_fun_ret =
            strncpy_s(str, TMP_STR_LEN, atta_reason_des[attach_reason], strlen(atta_reason_des[attach_reason]));
        if (safe_fun_ret != EOK) {
            debug_log(DLOG_ERROR, "%s: strncpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
        }
    } else {
        (void)snprintf_s(str, TMP_STR_LEN, TMP_STR_LEN - 1, "reserved [0x%x]", attach_reason);
    }
    pd_log_fprintf(file, "    attached reason: %s\n", str);

    guint32 reason = (p_param_data[5] & 0xf0) >> 4; // byte 4高4bit为reason
    if (reason < atta_reason_des_num) {
        safe_fun_ret = strncpy_s(str, TMP_STR_LEN, atta_reason_des[reason], strlen(atta_reason_des[reason]));
        if (safe_fun_ret != EOK) {
            debug_log(DLOG_ERROR, "%s: strncpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
        }
    } else {
        (void)snprintf_s(str, TMP_STR_LEN, TMP_STR_LEN - 1, "reserved [0x%x]", reason);
    }
    pd_log_fprintf(file, "    reason: %s\n", str);
}

/*
 * Description : 处理Protocol-Specific Port log中sas phy log descriptor部分link rate信息
 * History：2021-3-12  新生成函数
 */
static void pd_log_handle_sas_phy_log_descriptor_link_rate(FILE *file, guchar *p_param_data, guint32 portid,
    Json *out_put_jso)
{
    guint32 link_rate = (0xf & p_param_data[5]); // byte 5低4bit为link rate
    gchar str[TMP_STR_LEN] = {0};
    gchar key_str[TMP_STR_LEN] = {0};
    errno_t safe_fun_ret = EOK;
    const gchar* link_rate_des[] = {
        "phy enabled; unknown", "phy disabled", "phy enabled; speed negotiation failed",
        "phy enabled; SATA spinup hold state",
        "phy enabled; port selector", "phy enabled; reset in progress",
        "phy enabled; unsupported phy attached", "",
        "phy enabled; 1.5 Gbps", "phy enabled; 3 Gbps",
        "phy enabled; 6 Gbps", "phy enabled; 12 Gbps"
    };
    guint8 link_rate_des_num = (guint8)G_N_ELEMENTS(link_rate_des);
    if ((link_rate < link_rate_des_num) && (link_rate != 7)) { // link_rate为7为空描述
        safe_fun_ret = strncpy_s(str, TMP_STR_LEN, link_rate_des[link_rate], strlen(link_rate_des[link_rate]));
        if (safe_fun_ret != EOK) {
            debug_log(DLOG_ERROR, "%s: strncpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
        }
    } else {
        (void)snprintf_s(str, TMP_STR_LEN, TMP_STR_LEN - 1, "reserved [%u]", link_rate);
    }

    pd_log_fprintf(file, "    negotiated logical link rate: %s\n", str);
    (void)snprintf_s(key_str, TMP_STR_LEN, TMP_STR_LEN - 1, "n_linkrate_%u", portid);
    Json *str_obj = NULL;
    JsonStringCreate(str, &str_obj);
    JsonObjectItemSet(out_put_jso, key_str, str_obj);
}

/*
 * Description : 处理Protocol-Specific Port log中sas phy log descriptor部分sas adress信息
 * History：2021-3-12  新生成函数
 */
static void pd_log_handle_sas_phy_log_descriptor_sas_adress(FILE *file, guchar *p_param_data)
{
    gint32 k;
    gint32 address_len = 8;

    guint64 ull_param_data = p_param_data[8]; // byte 8~15为sas address
    for (k = 0; k < address_len; ++k) {
        ull_param_data <<= 8;
        ull_param_data |= p_param_data[8 + k];
    }
    pd_log_fprintf(file, "    SAS address = 0x%llx\n", ull_param_data);

    ull_param_data = p_param_data[16]; // byte 16~24为sas address
    for (k = 0; k < address_len; ++k) {
        ull_param_data <<= 8;
        ull_param_data |= p_param_data[16 + k];
    }
    pd_log_fprintf(file, "    attached SAS address = 0x%llx\n", ull_param_data);
}

/*
 * Description : 处理Protocol-Specific Port log中sas phy log descriptor部分invalid dowrd count信息
 * History：2021-3-12  新生成函数
 */
static void pd_log_handle_sas_phy_log_descriptor_invalid_dword_cnt(FILE *file, guchar *p_param_data, guint32 portid,
    Json *out_put_jso)
{
    gchar key_str[TMP_STR_LEN] = {0};
    gchar val_str[TMP_STR_LEN] = {0};
    guint32 phy_event = (p_param_data[32] << 24) | (p_param_data[33] << 16) | (p_param_data[34] << 8) |
        p_param_data[35]; // byte 32~35为 invalid dowrd count

    pd_log_fprintf(file, "    Invalid DWORD count = %u\n", phy_event);
    (void)snprintf_s(key_str, TMP_STR_LEN, TMP_STR_LEN - 1, "i_dwcount_%u", portid);
    (void)snprintf_s(val_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%u", phy_event);
    Json *str_obj = NULL;
    JsonStringCreate(val_str, &str_obj);
    JsonObjectItemSet(out_put_jso, key_str, str_obj);
}

/*
 * Description : 处理Protocol-Specific Port log中sas phy log descriptor部分runing disparity error count信息
 * History：2021-3-12  新生成函数
 */
static void pd_log_handle_sas_phy_log_descriptor_error_cnt(FILE *file, guchar *p_param_data, guint32 portid,
    Json *out_put_jso)
{
    gchar key_str[TMP_STR_LEN] = {0};
    gchar val_str[TMP_STR_LEN] = {0};
    guint32 phy_event = (p_param_data[36] << 24) | (p_param_data[37] << 16) | (p_param_data[38] << 8) |
        p_param_data[39]; // byte 36~39为 runing disparity error count

    pd_log_fprintf(file, "    Running disparity error count = %u\n", phy_event);
    (void)snprintf_s(key_str, TMP_STR_LEN, TMP_STR_LEN - 1, "r_errcount_%u", portid);
    (void)snprintf_s(val_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%u", phy_event);
    Json *str_obj = NULL;
    JsonStringCreate(val_str, &str_obj);
    JsonObjectItemSet(out_put_jso, key_str, str_obj);
}

/*
 * Description : 处理Protocol-Specific Port log中sas phy log descriptor部分loss of dword synchronization信息
 * History：2021-3-12  新生成函数
 */
static void pd_log_handle_sas_phy_log_descriptor_loss_of_dword_sync(FILE *file, guchar *p_param_data, guint32 portid,
    Json *out_put_jso)
{
    gchar key_str[TMP_STR_LEN] = {0};
    gchar val_str[TMP_STR_LEN] = {0};
    guint32 phy_event = (p_param_data[40] << 24) | (p_param_data[41] << 16) | (p_param_data[42] << 8) |
        p_param_data[43]; // byte 40~43为 loss of dword synchronization

    pd_log_fprintf(file, "    Loss of DWORD synchronization = %u\n", phy_event);
    (void)snprintf_s(key_str, TMP_STR_LEN, TMP_STR_LEN - 1, "l_dwsync_%u", portid);
    (void)snprintf_s(val_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%u", phy_event);
    Json *str_obj = NULL;
    JsonStringCreate(val_str, &str_obj);
    JsonObjectItemSet(out_put_jso, key_str, str_obj);
}

/*
 * Description : 处理Protocol-Specific Port log中sas phy log descriptor部分phy reset problem信息
 * History：2021-3-12  新生成函数
 */
static void pd_log_handle_sas_phy_log_descriptor_phy_reset_problem(FILE *file, guchar *p_param_data, guint32 portid,
    Json *out_put_jso)
{
    gchar key_str[TMP_STR_LEN] = {0};
    gchar val_str[TMP_STR_LEN] = {0};
    guint32 phy_event = (p_param_data[44] << 24) | (p_param_data[45] << 16) | (p_param_data[46] << 8) |
        p_param_data[47]; // byte 44~47为 phy reset problem

    pd_log_fprintf(file, "    Phy reset problem = %u\n", phy_event);
    (void)snprintf_s(key_str, TMP_STR_LEN, TMP_STR_LEN - 1, "p_prob_%u", portid);
    (void)snprintf_s(val_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%u", phy_event);
    Json *str_obj = NULL;
    JsonStringCreate(val_str, &str_obj);
    JsonObjectItemSet(out_put_jso, key_str, str_obj);
}

/*
 * Description : 处理Protocol-Specific Port log中sas phy log descriptor部分信息
 * History：2021-3-12  新生成函数
 */
static void pd_log_handle_sas_phy_log_descriptor(FILE *file, guchar *param_data, guint32 param_len, guint32 portid,
    Json *out_put_jso)
{
    guint32 len, i, j;
    guchar *p_data = NULL;
    guint32 phy_event, peak_threshold;
    guint32 log_head_len = 8;

    guchar *p_param_data = param_data + log_head_len; // sas phy log descriptor
    for (i = 0; i < (param_len - log_head_len); p_param_data += len, i += len) {
        // byte 3为log内容长度，log头长度为4个byte，只处理前44个byte
        len = (p_param_data[3] < 44) ? 48 : (p_param_data[3] + 4);

        pd_log_handle_sas_phy_log_descriptor_head(file, p_param_data, portid, out_put_jso);
        pd_log_handle_sas_phy_log_descriptor_attached_device_type(file, p_param_data, portid, out_put_jso);
        pd_log_handle_sas_phy_log_descriptor_reason(file, p_param_data, portid, out_put_jso);
        pd_log_handle_sas_phy_log_descriptor_link_rate(file, p_param_data, portid, out_put_jso);

        pd_log_fprintf(file, "    attached initiator port: ssp=%d stp=%d smp=%d\n", !!(p_param_data[6] & 8),
            !!(p_param_data[6] & 4), !!(p_param_data[6] & 2)); // byte 6的1~3bit分别为smp、stp和ssp
        pd_log_fprintf(file, "    attached target port: ssp=%d stp=%d smp=%d\n", !!(p_param_data[7] & 8),
            !!(p_param_data[7] & 4), !!(p_param_data[7] & 2)); // byte 7的1~3bit分别为smp、stp和ssp

        pd_log_handle_sas_phy_log_descriptor_sas_adress(file, p_param_data);

        pd_log_fprintf(file, "    attached phy identifier = %d\n", p_param_data[24]); // byte 24为phy identifier

        pd_log_handle_sas_phy_log_descriptor_invalid_dword_cnt(file, p_param_data, portid, out_put_jso);
        pd_log_handle_sas_phy_log_descriptor_error_cnt(file, p_param_data, portid, out_put_jso);
        pd_log_handle_sas_phy_log_descriptor_loss_of_dword_sync(file, p_param_data, portid, out_put_jso);
        pd_log_handle_sas_phy_log_descriptor_phy_reset_problem(file, p_param_data, portid, out_put_jso);

        if (len > 51) { // byte 51为Phy event descriptorr的数量，从byte 52开始，每个descriptorr占 12个字节
            if (((p_param_data[51] * 12 + 52) > len) || ((i + len) > (param_len - log_head_len))) {
                continue;
            }
            if (p_param_data[51] > 0) {
                pd_log_fprintf(file, "    Phy event descriptors:\n");
            }

            p_data = p_param_data + 52; // byte 52开始为phy Event descriptor，每个descriptor 12个字节
            for (j = 0; j < (p_param_data[51] * 12); j += 12, p_data += 12) {
                phy_event = (p_data[4] << 24) | (p_data[5] << 16) | (p_data[6] << 8) | p_data[7];
                peak_threshold = (p_data[8] << 24) | (p_data[9] << 16) | (p_data[10] << 8) | p_data[11];
                pd_log_scsi_show_phy_event_info(file, (gint32)p_data[3], phy_event, peak_threshold);
            }
        }
    }
}

/*
 * Description: 解析打印每个PORT LOG PARAMETER
 * History: 1.2018年5月11日
 * 新生成函数
 */
static void pd_log_scsi_show_port_param(FILE *file, guchar *param_data, guint32 param_len, Json *out_put_jso)
{
    gchar key_str[TMP_STR_LEN] = {0};
    gchar val_str[TMP_STR_LEN] = {0};

    if (param_data == NULL || param_len < 8) {
        return;
    }

    guint32 temp = (param_data[0] << 8) | param_data[1];
    if (temp == 0) {
        return;
    }

    pd_log_fprintf(file, "relative target port id = %d\n  generation code = %d\n  number of phys = %d\n", temp,
        param_data[6], param_data[7]);

    guint32 portid = temp - 1;
    (void)snprintf_s(key_str, TMP_STR_LEN, TMP_STR_LEN - 1, "r_portid_%u", portid);
    (void)snprintf_s(val_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%u", temp);
    Json *str_obj = NULL;
    JsonStringCreate(val_str, &str_obj);
    JsonObjectItemSet(out_put_jso, key_str, str_obj);
    pd_log_handle_sas_phy_log_descriptor(file, param_data, param_len, portid, out_put_jso);
}

/*
 * Description: 解析Protocol-Specific Port log page数据
 * History: 1.2018年5月11日
 * 新生成函数
 */
static gint32 pd_log_scsi_show_protocol_specific_page(FILE *file, guchar *phy_error_cnt, gint32 total_len,
    Json *out_put_jso)
{
    gsize current_read_len;
    gsize param_len;

    if (file == NULL || phy_error_cnt == NULL || total_len <= SCSI_LOG_PAGE_HEADER_SIZE) {
        debug_log(DLOG_ERROR, "%s: invalid input.", __FUNCTION__);
        return 0;
    }

    /* 偏移SCSI_LOG_PAGE_HEADER_SIZE个字节开始读取数据 */
    guchar *param_data = phy_error_cnt + SCSI_LOG_PAGE_HEADER_SIZE;

    gsize remain_size = (gsize)total_len;
    for (current_read_len = 0; current_read_len < (gsize)total_len;) {
        /* 计算要读取的param_data的总长度 */
        param_len = (gsize)param_data[3] + SCSI_LOG_PAGE_HEADER_SIZE;

        if ((0xf & param_data[4]) != 6) {
            return 0;
        }

        if (current_read_len == 0) {
            pd_log_fprintf(file, "Protocol Specific port log page for SAS SSP\n");
        }

        if (param_len > remain_size) {
            debug_log(DLOG_ERROR, "%s: param_len [%zu] > remain_len [%zu].", __FUNCTION__, param_len, remain_size);
            return 0;
        }

        pd_log_scsi_show_port_param(file, param_data, param_len, out_put_jso);
        current_read_len += param_len;
        remain_size -= param_len;

        /* 移动指针 */
        param_data += param_len;
    }

    return 1;
}

/*
 * Description: 处理phy error counter数据
 * History: 1.2018年5月11日
 * 新生成函数
 * 2.2018年7月25日
 */
void pd_log_handle_sas_phy_error_cnt(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *pd_log_jso)
{
    Json *protocol_specific_log_jso = NULL;
    if (pd_log == NULL) {
        return;
    }

    if ((SML_SUCCESS != pd_log->SASDevice.phy_error_cnt.result &&
        SML_ERR_PD_SCSI_RESP_TRUNCATED != pd_log->SASDevice.phy_error_cnt.result) ||
        NULL == pd_log->SASDevice.phy_error_cnt.data || 0 == pd_log->SASDevice.phy_error_cnt.data_length ||
        (PD_LOG_DATA_MAX_LEN < pd_log->SASDevice.phy_error_cnt.data_length)) {
        return;
    }
    guint8 *phy_error_cnt_data = (guint8 *)g_malloc0(PD_LOG_DATA_MAX_LEN);
    if (NULL == phy_error_cnt_data) {
        return;
    }

    (void)memset_s(phy_error_cnt_data, PD_LOG_DATA_MAX_LEN, 0, PD_LOG_DATA_MAX_LEN);
    errno_t safe_fun_ret = memcpy_s(phy_error_cnt_data, PD_LOG_DATA_MAX_LEN, pd_log->SASDevice.phy_error_cnt.data,
        pd_log->SASDevice.phy_error_cnt.data_length);
    if (safe_fun_ret != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
    }

    if ((phy_error_cnt_data[0] & 0x3f) != SCSI_LOG_PAGE_PROTOCOL_SPECIFIC) {
        pd_log_fprintf(file, "PHY Error Log Sense Failed, page mismatch\n");
        g_free(phy_error_cnt_data);
        return;
    }

    if (JsonObjectCreate(&protocol_specific_log_jso) != JSON_OK) {
        g_free(phy_error_cnt_data);
        return;
    }

    gint32 num = (phy_error_cnt_data[2] << 8) + phy_error_cnt_data[3];

    if (pd_log_scsi_show_protocol_specific_page(file, phy_error_cnt_data, num, protocol_specific_log_jso) != 1) {
        pd_log_fprintf(file, "Only support protocol specific log page on SAS devices\n\n");
        g_free(phy_error_cnt_data);
        JsonObjectRelease(protocol_specific_log_jso);
        return;
    }
    gchar *json_str = JsonPrint(protocol_specific_log_jso);
    if (pd_log_jso == NULL || g_strcmp0(json_str, "{ }") == 0) {
        JsonObjectRelease(protocol_specific_log_jso);
    } else {
        JsonObjectItemSet(pd_log_jso, "protocol_specific_port_log", protocol_specific_log_jso);
    }
    JsonStringValueFree(json_str);
    g_free(phy_error_cnt_data);
}

/*
 * Description: 获取Glist每条数据长度
 * History: 1.2019年2月14日,
 * 新生成函数
 */
guint8 pd_log_sas_glist_get_format_len(guint8 format_type)
{
    guint8 format_len = 0;

    switch (format_type) {
        case GLIST_FORMAT_TYPE_SHORT_BLOCK:
            format_len = 4; // 固定模式长度为4
            break;
        case GLIST_FORMAT_TYPE_EXT_BYTES:
        case GLIST_FORMAT_TYPE_EXT_PHY_SECTOR:
        case GLIST_FORMAT_TYPE_LONG_BLOCK:
        case GLIST_FORMAT_TYPE_BYTES:
        case GLIST_FORMAT_TYPE_PHY_SECTOR:
            format_len = 8; // 固定模式长度为8
            break;
        default:
            format_len = 0;
            break;
    }

    return format_len;
}

/*
 * Description: 处理Grown Defect List数据 SCSI Commands Reference Manual Table 41
 * History: 1.2018年5月11日
 * 新生成函数
 * 2.2018年7月25日
 */
void pd_log_handle_sas_glist(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *pd_log_jso)
{
    guint32 cylinder = 0, head = 0, sector = 0, length;
    guint32 i = 0;
    SML_PD_FAULT_ANALYSIS *result = (SML_PD_FAULT_ANALYSIS *)out_put;
    const guint32 threshold = 1000;
    gchar tmp_str[TMP_STR_LEN] = {0};

    /* pd_log_jso在add时判空，此处不判空 */
    if (pd_log == NULL) {
        return;
    }

    if ((SML_SUCCESS != pd_log->SASDevice.glist.result &&
        SML_ERR_PD_SCSI_RESP_TRUNCATED != pd_log->SASDevice.glist.result) ||
        NULL == pd_log->SASDevice.glist.data || 0 == pd_log->SASDevice.glist.data_length ||
        (PD_LOG_DATA_MAX_LEN < pd_log->SASDevice.glist.data_length)) {
        return;
    }

    guint8 *glist_data = (guint8 *)g_malloc0(PD_LOG_DATA_MAX_LEN);
    if (NULL == glist_data) {
        return;
    }

    (void)memset_s(glist_data, PD_LOG_DATA_MAX_LEN, 0, PD_LOG_DATA_MAX_LEN);
    errno_t safe_fun_ret =
        memcpy_s(glist_data, PD_LOG_DATA_MAX_LEN, pd_log->SASDevice.glist.data, pd_log->SASDevice.glist.data_length);
    if (safe_fun_ret != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
    }
    length = (glist_data[4] << 24) + (glist_data[5] << 16) + (glist_data[6] << 8) + glist_data[7];
    if (0 == length) {
        pd_log_fprintf(file, "Grown Defect List is empty...\n");
        g_free(glist_data);
        return;
    }

    guint8 format_type = (glist_data[1] & 0x7);

    guint8 format_len = pd_log_sas_glist_get_format_len(format_type);
    if (0 == format_len) {
        pd_log_fprintf(file, "Grown defect list length=%u bytes [unknown number of elements]\n", length);
        if (NULL != pd_log_jso) {
            JsonObjectItemSet(pd_log_jso, "glist_count", NULL);
        }
    } else {
        pd_log_fprintf(file, "Elements in grown defect list: %u\n", length / format_len);
        (void)memset_s(tmp_str, TMP_STR_LEN, 0, TMP_STR_LEN);
        (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%u", length / format_len);
        if (NULL != pd_log_jso) {
            Json *str_obj = NULL;
            JsonStringCreate(tmp_str, &str_obj);
            JsonObjectItemSet(pd_log_jso, "glist_count", str_obj);
        }
    }

    // 诊断故障
    /* BEGIN: Added by, 2019/1/17   PN:UADP135084 */
    if (NULL != result && 0 != format_len && (length / format_len) > threshold) {
        result->o_fault_bitmap.pd_smart_log_error = 1;
        (void)snprintf_s(result->io_buf, sizeof(result->io_buf), sizeof(result->io_buf) - 1,
            "glist count: %u, threshold: %u", (length / format_len), threshold);
        debug_log(DLOG_INFO, "Glist count(%d) error of %s.", (length / format_len), pd_log->pd_device_name);
        g_free(glist_data);
        return;
    }
    /* END:   Added by, 2019/1/17 */

    if (GLIST_FORMAT_TYPE_PHY_SECTOR == format_type) {
        pd_log_fprintf(file, "Cylinder-Head--Sector\n");
        pd_log_fprintf(file, "--------------------------\n");
        Json *glist_array = NULL;
        if (JsonArrayCreate(&glist_array) != JSON_OK) {
            g_free(glist_data);
            return;
        }

        for (i = 8; i < pd_log->SASDevice.glist.data_length - SCSI_DEFECT_LIST_HEADER_SIZE + 1; i += format_len) {
            // 前三个字节表示cylinder
            cylinder = (glist_data[i] << 16) + (glist_data[i + 1] << 8) + glist_data[i + 2];
            // 第四个字节表示head
            head = glist_data[i + 3];
            // 5-8字节表示sector
            sector =
                (glist_data[i + 4] << 24) + (glist_data[i + 5] << 16) + (glist_data[i + 6] << 8) + glist_data[i + 7];
            pd_log_fprintf(file, "0x%06X-%02X-%08X\n", cylinder, head, sector);
            Json *glist_node = NULL;
            if (JsonObjectCreate(&glist_node) != JSON_OK) {
                continue;
            }
            (void)memset_s(tmp_str, TMP_STR_LEN, 0, TMP_STR_LEN);
            (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%06X", cylinder);
            Json *str_cylinder = NULL;
            JsonStringCreate(tmp_str, &str_cylinder);
            JsonObjectItemSet(glist_node, "cylinder", str_cylinder);
            (void)memset_s(tmp_str, TMP_STR_LEN, 0, TMP_STR_LEN);
            (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%02X", head);
            Json *str_head = NULL;
            JsonStringCreate(tmp_str, &str_head);
            JsonObjectItemSet(glist_node, "head", str_head);
            (void)memset_s(tmp_str, TMP_STR_LEN, 0, TMP_STR_LEN);
            (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%08X", sector);
            Json *str_sector = NULL;
            JsonStringCreate(tmp_str, &str_sector);
            JsonObjectItemSet(glist_node, "sector", str_sector);
            guint32 array_size = 0;
            JsonArraySizeGet(glist_array, &array_size);
            JsonArrayItemInsert(glist_array, array_size, glist_node);
        }

        if ((pd_log->SASDevice.glist.data_length - SCSI_DEFECT_LIST_HEADER_SIZE) < length) {
            pd_log_fprintf(file, "......\n");
        }

        if (NULL != pd_log_jso) {
            JsonObjectItemSet(pd_log_jso, "glist", glist_array);
        } else {
            JsonObjectRelease(glist_array);
        }
    }

    g_free(glist_data);
}

/*
 * Description: 处理温度数据
 * History: 1.2018年5月11日
 * 新生成函数
 * 2.2018年7月25日
 */
void pd_log_handle_sas_temperature(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *pd_log_jso)
{
    guint8 temp = 255;
    guint8 trip = 255;
    Json *temp_log_jso = NULL;
    gchar tmp_str[TMP_STR_LEN] = {0};

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

    if ((SML_SUCCESS != pd_log->SASDevice.temperature.result &&
        SML_ERR_PD_SCSI_RESP_TRUNCATED != pd_log->SASDevice.temperature.result) ||
        NULL == pd_log->SASDevice.temperature.data || 0 == pd_log->SASDevice.temperature.data_length) {
        return;
    }

    guint8 *temperature_data = (guint8 *)g_malloc0(PD_LOG_DATA_MAX_LEN);
    if (NULL == temperature_data) {
        return;
    }

    (void)memset_s(temperature_data, PD_LOG_DATA_MAX_LEN, 0, PD_LOG_DATA_MAX_LEN);
    errno_t safe_fun_ret = memcpy_s(temperature_data, PD_LOG_DATA_MAX_LEN, pd_log->SASDevice.temperature.data,
        pd_log->SASDevice.temperature.data_length);
    if (safe_fun_ret != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
    }

    if ((temperature_data[0] & 0x3f) != SCSI_LOG_PAGE_TEMPERATURE) {
        pd_log_fprintf(file, "Temperature Log Sense Failed, page mismatch\n");
        g_free(temperature_data);
        return;
    }

    if (JsonObjectCreate(&temp_log_jso) != JSON_OK) {
        g_free(temperature_data);
        return;
    }
    JsonObjectItemSet(pd_log_jso, "temperature_log", temp_log_jso);

    temp = temperature_data[9];
    trip = temperature_data[15];

    if (255 == temp) {
        pd_log_fprintf(file, "Current Drive Temperature:     <not available>\n");
        (void)strncpy_s(tmp_str, TMP_STR_LEN, "not available", strlen("not available"));
    } else {
        pd_log_fprintf(file, "Current Drive Temperature:     %d C\n", temp);
        (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%u", temp);
    }
    Json *str_obj = NULL;
    JsonStringCreate(tmp_str, &str_obj);
    JsonObjectItemSet(temp_log_jso, "current", str_obj);

    (void)memset_s(tmp_str, TMP_STR_LEN, 0, TMP_STR_LEN);
    if (255 == trip) {
        pd_log_fprintf(file, "Drive Trip Temperature:        <not available>\n");
        (void)strncpy_s(tmp_str, TMP_STR_LEN, "not available", strlen("not available"));
    } else {
        pd_log_fprintf(file, "Drive Trip Temperature:        %d C\n", trip);
        (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%u", trip);
    }
    Json *str_reference = NULL;
    JsonStringCreate(tmp_str, &str_reference);
    JsonObjectItemSet(temp_log_jso, "reference", str_reference);

    g_free(temperature_data);
}

/*
 * Description: 处理BMS的cylinder、head、sector信息
 */
static void pd_log_handle_sas_bms_chs(FILE *file, guchar *p_data, Json *chs_jso)
{
    gchar tmp_str[TMP_STR_LEN] = {0};

    if (NULL == file || NULL == p_data) {
        return;
    }

    (void)snprintf_s(tmp_str, sizeof(tmp_str), sizeof(tmp_str) - 1, "[%d:%d:%d]",
        (((p_data[11] & 0x0f) << 16) | (p_data[12] << 8) | p_data[13]), ((p_data[11] & 0xf0) >> 4),
        ((p_data[14] << 8) | p_data[15]));
    pd_log_fprintf(file, "%-20s\t", tmp_str);

    if (NULL != chs_jso) {
        (void)memset_s(tmp_str, TMP_STR_LEN, 0, TMP_STR_LEN);
        (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%d",
            (((p_data[11] & 0x0f) << 16) | (p_data[12] << 8) | p_data[13]));
        Json *str_obj = NULL;
        JsonStringCreate(tmp_str, &str_obj);
        JsonObjectItemSet(chs_jso, "cylinder", str_obj);
        (void)memset_s(tmp_str, TMP_STR_LEN, 0, TMP_STR_LEN);
        (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%d", ((p_data[11] & 0xf0) >> 4));
        Json *str_head_obj = NULL;
        JsonStringCreate(tmp_str, &str_head_obj);
        JsonObjectItemSet(chs_jso, "head", str_head_obj);
        (void)memset_s(tmp_str, TMP_STR_LEN, 0, TMP_STR_LEN);
        (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%d", ((p_data[14] << 8) | p_data[15]));
        Json *str_sector_obj = NULL;
        JsonStringCreate(tmp_str, &str_sector_obj);
        JsonObjectItemSet(chs_jso, "sector", str_sector_obj);
    }
}

/*
 * Description: 处理BMS的asc和ascq信息
 */
static void pd_log_handle_sas_bms_asc(FILE *file, guchar *p_data, Json *out_put_jso)
{
    gint32 asc = 0;
    gint32 ascq = 0;
    gchar tmp_str[TMP_STR_LEN] = {0};

    if (NULL == file || NULL == p_data) {
        return;
    }

    asc = p_data[9];
    ascq = p_data[10];
    pd_log_fprintf(file, "0x%02x 0x%02x\t", asc, ascq);

    if (NULL != out_put_jso) {
        (void)memset_s(tmp_str, TMP_STR_LEN, 0, TMP_STR_LEN);
        (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "0x%02x", asc);
        Json *str_obj = NULL;
        JsonStringCreate(tmp_str, &str_obj);
        JsonObjectItemSet(out_put_jso, "asc", str_obj);
        (void)memset_s(tmp_str, TMP_STR_LEN, 0, TMP_STR_LEN);
        (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "0x%02x", ascq);
        Json *str_ascq_obj = NULL;
        JsonStringCreate(tmp_str, &str_ascq_obj);
        JsonObjectItemSet(out_put_jso, "ascq", str_ascq_obj);
    }
}

/*
 * Description: 处理Background Medium Scan数据
 * History: 1.2018年5月11日
 * 新生成函数
 * 2.2018年7月25日
 */
void pd_log_handle_sas_bms(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *pd_log_jso)
{
    gint32 i = 0, j = 0, num = 0, tmp = 0;
    gint32 sense_key = 0;
    guint32 extra = 0, bms_list_num, start_pos;
    guchar reassign[20] = {0};
    guchar *p_tmp_data = NULL;
    GSList *bms_list = NULL;
    GSList *bms_node = NULL;
    gchar tmp_str[TMP_STR_LEN] = {0};
    errno_t errno_val = EOK;

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

    if ((SML_SUCCESS != pd_log->SASDevice.bms.result &&
        SML_ERR_PD_SCSI_RESP_TRUNCATED != pd_log->SASDevice.bms.result) ||
        NULL == pd_log->SASDevice.bms.data || SCSI_LOG_PAGE_HEADER_SIZE >= pd_log->SASDevice.bms.data_length ||
        (PD_LOG_DATA_MAX_LEN < pd_log->SASDevice.bms.data_length)) {
        return;
    }

    guint8 *bms_data = (guint8 *)g_malloc0(PD_LOG_DATA_MAX_LEN);
    if (NULL == bms_data) {
        return;
    }

    (void)memset_s(bms_data, PD_LOG_DATA_MAX_LEN, 0, PD_LOG_DATA_MAX_LEN);
    errno_t safe_fun_ret =
        memcpy_s(bms_data, PD_LOG_DATA_MAX_LEN, pd_log->SASDevice.bms.data, pd_log->SASDevice.bms.data_length);
    if (safe_fun_ret != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
    }

    if ((bms_data[0] & 0x3f) != SCSI_LOG_PAGE_BACKGROUND_RESULTS) {
        pd_log_fprintf(file, "BMS Log Sense Failed, page mismatch\n");
        g_free(bms_data);
        return;
    }

    // compute page length
    num = (gint32)(pd_log->SASDevice.bms.data_length - SCSI_LOG_PAGE_HEADER_SIZE);
    guchar *p_data = &bms_data[0] + SCSI_LOG_PAGE_HEADER_SIZE;
    extra = p_data[3] + SCSI_LOG_PAGE_HEADER_SIZE;
    pd_log_fprintf(file, "%-25s\t", "Power on time: ");
    j = (p_data[4] << 24) + (p_data[5] << 16) + (p_data[6] << 8) + p_data[7];
    pd_log_fprintf(file, "%.2f\n", (gfloat)j / 60.0);
    pd_log_fprintf(file, "%-25s\t", "BMS status: ");
    j = p_data[9];

    if (j < (gint32)(sizeof(g_bms_status) / sizeof(g_bms_status[0]))) {
        pd_log_fprintf(file, "%s\n", g_bms_status[j]);
    } else {
        pd_log_fprintf(file, "unknown [0x%x]\n", j);
    }

    pd_log_fprintf(file, "%-25s\t%d\n", "Number of scans performed: ", (p_data[10] << 8) + p_data[11]);
    pd_log_fprintf(file, "%-25s\t%.2f%%\n\n",
        "Progress of medium scan: ", (gdouble)((p_data[12] << 8) + p_data[13]) * 100.0 / 65536.0);
    num -= (gint32)extra;
    if (extra < (pd_log->SASDevice.bms.data_length - SCSI_LOG_PAGE_HEADER_SIZE - SCSI_LOG_PAGE_HEADER_SIZE)) {
        p_data += extra;
    }

    while (num > 3) {
        tmp = (p_data[0] << 8) | p_data[1];
        extra = p_data[3] + SCSI_LOG_PAGE_HEADER_SIZE;
        if (0 != tmp) {
            if (extra < 24) {
                break;
            }

            // 将有效数据的起始地址放入链表
            bms_list = g_slist_append(bms_list, (gpointer)p_data);
        }

        num -= (gint32)extra;
        if (extra < pd_log->SASDevice.bms.data_length) {
            p_data += extra;
        }
    }

    bms_list_num = g_slist_length(bms_list);
    if (0 == bms_list_num) {
        g_slist_free(bms_list);
        g_free(bms_data);
        return;
    }

    // 只解析最后的20组数据
    if (bms_list_num <= 20) {
        start_pos = 0;
        pd_log_fprintf(file, "Background Medium Scan Number: %d\n", bms_list_num);
    } else {
        start_pos = bms_list_num - 20;
        pd_log_fprintf(file, "Background Medium Scan Number: %d (device log contains only the most recent 20)\n",
            bms_list_num);
    }
    (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%u", bms_list_num);
    Json *str_obj = NULL;
    JsonStringCreate(tmp_str, &str_obj);
    JsonObjectItemSet(pd_log_jso, "background_medium_scan_count", str_obj);

    pd_log_fprintf(file, "%-4s\t%-8s\t%-26s\t%-18s\t%-20s\t%-4s\t%-10s\n", "Num", "POT", "Reassign status", "LBA",
        "[cyl:head:sec]", "key", "asc  ascq");
    pd_log_fprintf(file,
        "--------------------------------------------------------------------------------------------------------------"
        "-----------\n");
    Json *bms_log_array = NULL;
    if (JsonArrayCreate(&bms_log_array) != JSON_OK) {
        g_slist_free(bms_list);
        g_free(bms_data);
        return;
    }
    JsonObjectItemSet(pd_log_jso, "background_medium_scan_log", bms_log_array);
    for (bms_node = g_slist_nth(bms_list, start_pos); bms_node; bms_node = bms_node->next) {
        p_tmp_data = (guchar *)bms_node->data;
        tmp = (p_tmp_data[0] << 8) | p_tmp_data[1];

        pd_log_fprintf(file, "%-4d\t", tmp);
        j = (p_tmp_data[4] << 24) + (p_tmp_data[5] << 16) + (p_tmp_data[6] << 8) + p_tmp_data[7];
        pd_log_fprintf(file, "%-8.2f\t", (gfloat)j / 60.0);
        Json *bms_log_node = NULL;
        if (JsonObjectCreate(&bms_log_node) == JSON_OK) {
            memset_s(tmp_str, TMP_STR_LEN, 0, TMP_STR_LEN);
            (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%.2f", (float)j / 60.0);
            Json *str_obj = NULL;
            JsonStringCreate(tmp_str, &str_obj);
            JsonObjectItemSet(bms_log_node, "pot", str_obj);
        }

        j = (p_tmp_data[8] >> 4) & 0xf;
        if (j < (gint32)(sizeof(g_reassign_status) / sizeof(g_reassign_status[0]))) {
            pd_log_fprintf(file, "%-26s\t", g_reassign_status[j]);
            if (NULL != bms_log_node) {
                Json *str_reassign_obj = NULL;
                JsonStringCreate(g_reassign_status[j], &str_reassign_obj);
                JsonObjectItemSet(bms_log_node, "reassign_status", str_reassign_obj);
            }
        } else {
            (void)snprintf_s((gchar *)reassign, sizeof(reassign), sizeof(reassign) - 1, "reserved[0x%x]", j);
            pd_log_fprintf(file, "%-26s\t", reassign);
            if (NULL != bms_log_node) {
                Json *str_status_obj = NULL;
                JsonStringCreate((gchar *)reassign, &str_status_obj);
                JsonObjectItemSet(bms_log_node, "reassign_status", str_status_obj);
            }
        }

        pd_log_fprintf(file, "0x");
        (void)memset_s(tmp_str, TMP_STR_LEN, 0, TMP_STR_LEN);
        errno_val = strncat_s(tmp_str, TMP_STR_LEN, "0x", strlen("0x"));
        if (errno_val != EOK) {
            debug_log(DLOG_ERROR, "%s: strncat_s 0x failed, errno_val = %d", __FUNCTION__, errno_val);
        }

        for (i = 0; i < 8; ++i) {
            pd_log_fprintf(file, "%02x", p_tmp_data[16 + i]);
            if (strlen(tmp_str) < TMP_STR_LEN - 2) { // snprintf_s安全函数参数不越界要求strlen(tmp_str) < TMP_STR_LEN - 2
                gint32 ret = snprintf_s(tmp_str + strlen(tmp_str), TMP_STR_LEN - strlen(tmp_str),
                    TMP_STR_LEN - strlen(tmp_str) - 1, "%02x", p_tmp_data[16 + i]);
                if (ret <= 0) {
                    debug_log(DLOG_ERROR, "%s: snprintf_s fail, ret = %d", __FUNCTION__, ret);
                }
            }
        }

        if (NULL != bms_log_node) {
            Json *str_obj = NULL;
            JsonStringCreate(tmp_str, &str_obj);
            JsonObjectItemSet(bms_log_node, "lba", str_obj);
        }

        pd_log_fprintf(file, "\t");
        pd_log_handle_sas_bms_chs(file, p_tmp_data, bms_log_node);

        sense_key = (p_tmp_data[8] & 0x0f);
        pd_log_fprintf(file, "0x%02x\t", sense_key);
        if (NULL != bms_log_node) {
            memset_s(tmp_str, TMP_STR_LEN, 0, TMP_STR_LEN);
            (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "0x%02x", sense_key);
            Json *str_obj = NULL;
            JsonStringCreate(tmp_str, &str_obj);
            JsonObjectItemSet(bms_log_node, "key", str_obj);
        }

        pd_log_handle_sas_bms_asc(file, p_tmp_data, bms_log_node);
        if (NULL != bms_log_node) {
            guint32 array_size = 0;
            JsonArraySizeGet(bms_log_array, &array_size);
            JsonArrayItemInsert(bms_log_array, array_size, bms_log_node);
        }

        pd_log_fprintf(file, "\n");
    }

    g_slist_free(bms_list);
    g_free(bms_data);
}

/*
 * Description : 处理Solid State Media log的ENDURANCE信息
 * History：2020-10-21  新生成函数
 */
void pd_log_handle_sas_solid_state_media(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *pd_log_jso)
{
    gchar tmp_str[TMP_STR_LEN] = {0};
    Json *solid_state_media_log_jso = NULL;

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

    guint8 media_wearout = pd_log->pd_remnant_media_wearout;

    guint8 disk_endurance = 100 - media_wearout; // 还原剩余寿命检测对硬盘磨损的处理
    pd_log_fprintf(file, "%-25s\t%d\n", "Percentage used endurance: ", disk_endurance);

    guint32 ret = JsonObjectCreate(&solid_state_media_log_jso);
    if (ret == JSON_ERR) {
        debug_log(DLOG_ERROR, "%s: JsonObjectCreate failed.\n", __FUNCTION__);
        return;
    }

    (void)memset_s(tmp_str, TMP_STR_LEN, 0, TMP_STR_LEN);
    (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%u", disk_endurance);
    Json *str_obj = NULL;
    JsonStringCreate(tmp_str, &str_obj);
    JsonObjectItemSet(solid_state_media_log_jso, "disk_endurance", str_obj);
    JsonObjectItemSet(pd_log_jso, "solid_state_media_log", solid_state_media_log_jso);
}

/*
 * Description : 处理kioxia SAS SSD General Statistics and Performance log parameter code 8000h信息
 * Notes：这部分当前只记录log，后续如有需求，再写入数据采集数据库
 * History：2020-10-21  新生成函数
 */
static void pd_log_handle_sas_kioxia_general_statistics(FILE *file, PD_LOG_S *pd_log, void *out_put,
    Json *pd_log_jso)
{
    gint32 i, j, param_code;
    guint64 param_data[9] = {0};
    guint64 temp_value;
    const gint8 statistics_cnt = 9;
    const gint8 value_size = 8;
    const gchar *name_str[] = {
        "read operation stalled:",
        "host write odd start commands:",
        "host write odd end commands:",
        "write operation stalled:",
        "flash memory read commands:",
        "flash memory read blocks:",
        "flash memory write commands:",
        "flash memory write blocks:",
        "flash memory read before write:"
    };

    // kioxia General Statistics and Performance log总数据长度为172
    if (pd_log->SASDevice.general_statistics.data_length < 172) {
        return;
    }

    // 本函数仅处理parameter code为8000h的log，跳过前96个字节。
    guchar *p_data = pd_log->SASDevice.general_statistics.data + 96;
    param_code = (p_data[0] << 8) + p_data[1];
    if (param_code != 0x8000) {
        return;
    }

    p_data += 4; // 第4byte开始为具体统计数据
    for (i = 0; i < statistics_cnt; i++) {
        for (j = 0; j < value_size; j++) {
            temp_value = param_data[i];
            temp_value = temp_value << 8;
            param_data[i] = temp_value + p_data[i * value_size + j];
        }
        pd_log_fprintf(file, "%-65s\t0x%016" G_GUINT64_HEX_FORMAT "\n", name_str[i], param_data[i]);
    }
}

/*
 * Description : 处理SAS SSD General Statistics and Performance信息
 * History：2020-10-21  新生成函数
 */
void pd_log_handle_sas_general_statistics(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *pd_log_jso)
{
    gint32 i, j, param_len, param_code;
    guint64 param_data[8] = {0};
    guint64 temp_value;
    const gint8 statistics_cnt = 8;
    const gint8 value_size = 8;
    gchar tmp_str[TMP_STR_LEN] = {0};
    Json *general_statistics_log_jso = NULL;

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

    if (pd_log->SASDevice.general_statistics.data_length <= SCSI_LOG_PAGE_HEADER_SIZE * 2) {
        return;
    }

    guchar *p_data = pd_log->SASDevice.general_statistics.data + SCSI_LOG_PAGE_HEADER_SIZE; // 数据指向第一个parameter
    param_code = (p_data[0] << 8) + p_data[1];
    if (param_code != 0x0001) {
        return;
    }

    param_len = p_data[3]; // parameter部分第3byte为Parameter length
    if (param_len < statistics_cnt * value_size) {
        return;
    }

    if (JsonObjectCreate(&general_statistics_log_jso) != JSON_OK) {
        debug_log(DLOG_ERROR, "%s: JsonObjectCreate failed.\n", __FUNCTION__);
        return;
    }

    p_data += 4; // parameter从第4byte开始为具体统计数据
    for (i = 0; i < statistics_cnt; i++) {
        for (j = 0; j < value_size; j++) {
            temp_value = param_data[i];
            temp_value = temp_value << 8;
            param_data[i] = temp_value + p_data[i * value_size + j];
        }
        pd_log_fprintf(file, "%-65s\t0x%016" G_GUINT64_HEX_FORMAT "\n", g_general_statistics_log_map[i].name_str,
            param_data[i]);
        (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%" G_GUINT64_FORMAT, param_data[i]);
        Json *str_obj = NULL;
        JsonStringCreate(tmp_str, &str_obj);
        JsonObjectItemSet(general_statistics_log_jso, g_general_statistics_log_map[i].key_str, str_obj);
    }

    if (strstr(pd_log->pd_manufacturer, PD_VENDOR_NAME_KIOXIA) != NULL) {
        pd_log_handle_sas_kioxia_general_statistics(file, pd_log, out_put, general_statistics_log_jso);
    }

    JsonObjectItemSet(pd_log_jso, "general_statistics_log", general_statistics_log_jso);
}

/*
 * Description : 处理huawei SSD vendor specific log(32h)信息
 * History：2020-11-18  新生成函数
 */
void pd_log_handle_sas_huawei_specific32h(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *vendor_log_json)
{
    gint32 cur_temp, thres_temp, highest_temp, lowest_temp, highest_temp_time, accum_time, lowest_temp_time;

    if (pd_log == NULL) {
        return;
    }

    guchar *p_data = pd_log->SASDevice.huawei_specific32h.data;
    gint32 page_len = (p_data[2] << 8) + p_data[3]; // 第2、3byte为Page length
    if (page_len + SCSI_LOG_PAGE_HEADER_SIZE < 20) {
        return;
    }

    cur_temp = p_data[4];
    thres_temp = p_data[5];
    highest_temp = p_data[6];
    lowest_temp = p_data[7];
    highest_temp_time = (p_data[8] << 24) + (p_data[9] << 16) + (p_data[10] << 8) + p_data[11];
    accum_time = (p_data[12] << 24) + (p_data[13] << 16) + (p_data[14] << 8) + p_data[15];
    lowest_temp_time = (p_data[16] << 24) + (p_data[17] << 16) + (p_data[18] << 8) + p_data[19];

    pd_log_fprintf(file, "Current temperature                                      %d\n", cur_temp);
    pd_log_fprintf(file, "Threshold temperature                                    %d\n", thres_temp);
    pd_log_fprintf(file, "Highest temperature                                      %d\n", highest_temp);
    pd_log_fprintf(file, "Lowest temperature                                       %d\n", lowest_temp);
    pd_log_fprintf(file, "Highest temperature time(unit:min)                       %d\n", highest_temp_time);
    pd_log_fprintf(file, "Temperature exceed threshold accumulated time(unit:min)  %d\n", accum_time);
    pd_log_fprintf(file, "Low temperature time(unit:min)                           %d\n", lowest_temp_time);
}

/*
 * Description : 获取华为 SAS SSD硬盘SMART属性名称
 * History：2020-11-2  新生成函数
 */
static const gchar *get_sas_ssd_huawei_smart_attr_name(guint8 attr_id)
{
    gint32 i;
    for (i = 0; i < G_N_ELEMENTS(g_huawei_vendor_specific_log_map); i++) {
        if (attr_id == g_huawei_vendor_specific_log_map[i].attr_id) {
            return g_huawei_vendor_specific_log_map[i].name_str;
        }
    }

    return "Unknown_Attribute";
}

/*
 * Description : 获取华为 SAS SSD硬盘SMART属性数据采集字段名称
 * History：2020-11-2  新生成函数
 */
static const gchar *get_sas_ssd_huawei_smart_key_str(guint8 attr_id)
{
    gint32 i;
    for (i = 0; i < G_N_ELEMENTS(g_huawei_vendor_specific_log_map); i++) {
        if (attr_id == g_huawei_vendor_specific_log_map[i].attr_id) {
            return g_huawei_vendor_specific_log_map[i].key_str;
        }
    }

    return "Unknown";
}

/*
 * Description : 处理huawei SSD vendor specific log(34h)的Data
 * History：2020-11-13  新生成函数
 */
static void pd_log_handle_sas_huawei_specific34h_data(FILE *file, guchar *p_data, Json *smart_log_json)
{
    guint8 smart_id, cur, max, min, thres, flag, i;
    gchar key_str[TMP_STR_LEN] = {0};
    gchar val_str[TMP_STR_LEN] = {0};
    static const gchar* suffix_str[] = {"flag", "cur", "max", "min", "thres"};

    smart_id = p_data[0];
    flag = p_data[1];
    cur = p_data[2];
    max = p_data[3];
    min = p_data[4];
    thres = p_data[5];
    pd_log_fprintf(file, "0x%02x(%3d)   %-30s  %-8d%-8d%-8d%-8d%-8d\n", smart_id, smart_id,
        get_sas_ssd_huawei_smart_attr_name(smart_id), cur, max, min, thres, flag);

    for (i = 0; i < 5; i++) {
        gint32 ret = snprintf_s(key_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%s_%s",
            get_sas_ssd_huawei_smart_key_str(smart_id), suffix_str[i]);
        if (ret <= 0) {
            debug_log(DLOG_ERROR, "%s: snprintf_s smart name fail, ret = %d", __FUNCTION__, ret);
            return;
        }

        ret = snprintf_s(val_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%d", (gchar)p_data[i + 1]);
        if (ret <= 0) {
            debug_log(DLOG_ERROR, "%s: snprintf_s smart value fail, ret = %d", __FUNCTION__, ret);
            return;
        }
        Json *str_obj = NULL;
        JsonStringCreate(val_str, &str_obj);
        JsonObjectItemSet(smart_log_json, key_str, str_obj);
    }
}

/*
 * Description : 处理huawei SSD vendor specific log(34h)信息
 * History：2020-11-9  新生成函数
 */
void pd_log_handle_sas_huawei_specific34h(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *vendor_log_json)
{
    gint32 i, page_len;
    const gint32 smart_cnt = 7;
    const gint8 smart_value_size = 8;
    Json *smart_log_json = NULL;

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

    guchar *p_data = pd_log->SASDevice.huawei_specific34h.data;
    page_len = (p_data[2] << 8) + p_data[3]; // 第2、3byte为Page length
    if (page_len / smart_value_size < smart_cnt) {
        return;
    }

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

    pd_log_fprintf(file, "ID#         ATTRIBUTE_NAME                  Cur     Max     Min     Thres   Flag\n");

    for (i = 0; i < smart_cnt; i++) {
        p_data = pd_log->SASDevice.huawei_specific34h.data + SCSI_LOG_PAGE_HEADER_SIZE + i * smart_value_size;
        pd_log_handle_sas_huawei_specific34h_data(file, p_data, smart_log_json);
    }

    JsonObjectItemSet(vendor_log_json, "vendor_specific_log_34h", smart_log_json);
}

/*
 * Description : 处理huawei SSD vendor specific log(35h)信息
 * History：2020-11-2  新生成函数
 */
void pd_log_handle_sas_huawei_specific35h(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *vendor_log_json)
{
    gint32 i, j, page_len, smart_cnt;
    guint8 smart_id;
    guint64 param_data, temp_value;
    const gint8 smart_value_size = 12;
    gchar tmp_str[TMP_STR_LEN] = {0};
    Json *huawei_specific35h_log_jso = NULL;

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

    guchar *p_data = pd_log->SASDevice.huawei_specific35h.data;
    page_len = (p_data[2] << 8) + p_data[3]; // 第2、3byte为Page length
    if (page_len % smart_value_size != 0) {
        return;
    }

    pd_log_fprintf(file, "ID#         ATTRIBUTE_NAME                  VALUE\n");

    guint32 ret = JsonObjectCreate(&huawei_specific35h_log_jso);
    if (ret == JSON_ERR) {
        debug_log(DLOG_ERROR, "%s: JsonObjectCreate failed.\n", __FUNCTION__);
        return;
    }

    smart_cnt = page_len / smart_value_size;
    for (i = 0; i < smart_cnt; i++) {
        p_data = pd_log->SASDevice.huawei_specific35h.data + SCSI_LOG_PAGE_HEADER_SIZE + i * smart_value_size;
        param_data = 0;
        smart_id = p_data[0];
        if (smart_id == 0) {
            continue;
        }

        for (j = 4; j < smart_value_size; j++) {
            temp_value = param_data;
            temp_value = temp_value << 8;
            param_data = temp_value + p_data[j];
        }
        pd_log_fprintf(file, "0x%02x(%3d)   %-30s  0x%016" G_GUINT64_HEX_FORMAT "\n", smart_id, smart_id,
            get_sas_ssd_huawei_smart_attr_name(smart_id), param_data);
        (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%" G_GUINT64_FORMAT, param_data);
        Json *str_obj = NULL;
        JsonStringCreate(tmp_str, &str_obj);
        JsonObjectItemSet(huawei_specific35h_log_jso, get_sas_ssd_huawei_smart_key_str(smart_id), str_obj);
    }

    JsonObjectItemSet(vendor_log_json, "vendor_specific_log_35h", huawei_specific35h_log_jso);
}

/*
 * Description : 处理huawei SSD IO Info信息
 * History：2020-11-4  新生成函数
 */
void pd_log_handle_sas_huawei_io_info(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *vendor_log_json)
{
    guchar *p_data = NULL;
    guint64 param_data, temp_value;
    const gint8 io_info_value_size = 8;
    gchar tmp_str[TMP_STR_LEN] = {0};
    Json *huawei_io_info_jso = NULL;
    static const gchar* pd_io_info_str[] = {"host read bytes:", "nm read bytes:", "gc read bytes:", "bs read bytes:",
        "host write bytes:", "nm write bytes:", "gc write bytes:", "bs write bytes:"
    };
    static const gchar* key_str[] = {"host_read_byte", "NM_read_byte", "GC_read_byte", "BS_read_byte",
        "host_write_byte", "NM_write_byte", "GC_write_byte", "BS_write_byte"
    };

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

    glong data_len = pd_log->SASDevice.huawei_io_info.data_length;
    if (data_len % io_info_value_size != 0) {
        pd_log_fprintf(file, "data len error:%d\n", data_len % io_info_value_size);
    }

    if (JsonObjectCreate(&huawei_io_info_jso) != JSON_OK) {
        debug_log(DLOG_ERROR, "%s: JsonObjectCreate failed.\n", __FUNCTION__);
        return;
    }

    gint32 io_info_cnt = data_len / io_info_value_size;
    for (gint32 i = 0; i < io_info_cnt; i++) {
        p_data = pd_log->SASDevice.huawei_io_info.data + i * io_info_value_size;
        param_data = 0;
        for (gint32 j = io_info_value_size - 1; j >= 0; j--) {
            temp_value = param_data;
            temp_value = temp_value << 8;
            param_data = temp_value + p_data[j];
        }
        pd_log_fprintf(file, "%-30s\t0x%016" G_GUINT64_HEX_FORMAT "\n", pd_io_info_str[i], param_data);
        (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%" G_GUINT64_FORMAT, param_data);
        Json *str_obj = NULL;
        JsonStringCreate(tmp_str, &str_obj);
        JsonObjectItemSet(huawei_io_info_jso, key_str[i], str_obj);
    }

    JsonObjectItemSet(vendor_log_json, "io_info", huawei_io_info_jso);
}

/*
 * Description : 获取kioxia SAS SSD硬盘SMART属性名称
 * History：2020-11-2  新生成函数
 */
static const gchar *get_sas_ssd_kioxia_specific_attr_name(guint8 attr_id)
{
    gint32 i;
    for (i = 0; i < G_N_ELEMENTS(g_kioxia_vendor_specific_log_map); i++) {
        if (attr_id == g_kioxia_vendor_specific_log_map[i].attr_id) {
            return g_kioxia_vendor_specific_log_map[i].name_str;
        }
    }

    return "Unknown_Attribute";
}

/*
 * Description : 获取kioxia SAS SSD硬盘SMART属性数据采集字段名称
 * History：2020-11-2  新生成函数
 */
static const gchar *get_sas_ssd_kioxia_specific_key_str(guint8 attr_id)
{
    gint32 i;
    for (i = 0; i < G_N_ELEMENTS(g_kioxia_vendor_specific_log_map); i++) {
        if (attr_id == g_kioxia_vendor_specific_log_map[i].attr_id) {
            return g_kioxia_vendor_specific_log_map[i].key_str;
        }
    }

    return "Unknown";
}

/*
 * Description : 处理kioxia SSD Specific log信息中read error rate部分数据
 * History：2020-11-19  新生成函数
 */
static void pd_log_handle_sas_kioxia_read_error_rate(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *log_json)
{
    gint32 i, param_code, param_data[4], param_len;
    const gint32 param_cnt = 18; // 只处理前18项数据
    const gint32 param_head_len = 4;
    gchar tmp_str[TMP_STR_LEN] = {0};

    pd_log_fprintf(file, "\nID#         ATTRIBUTE_NAME                                                          "
        "READ_CLUSTER_COUNT READ_ERROR_COUNT MAXIMUM_READ_CLUSTER_COUNT MAXIMUM_READ_ERROR_COUNT\n");

    guchar *p_data = pd_log->SASDevice.kioxia_ssd_specific.data + SCSI_LOG_PAGE_HEADER_SIZE;
    for (i = 0; i < param_cnt; i++) {
        param_code = (p_data[0] << 8) + p_data[1];
        param_len = p_data[3];
        if ((param_code >= 0x08) && (param_code <= 0x0D)) {
            pd_log_fprintf(file, "0x%02x(%3d)   %-70s", param_code, param_code,
                get_sas_ssd_kioxia_specific_attr_name(param_code));
            param_data[0] = (p_data[4] << 24) + (p_data[5] << 16) + (p_data[6] << 8) + p_data[7];
            pd_log_fprintf(file, "  0x%08x", param_data[0]);
            param_data[1] = (p_data[8] << 24) + (p_data[9] << 16) + (p_data[10] << 8) + p_data[11];
            pd_log_fprintf(file, "         0x%08x", param_data[1]);
            param_data[2] = (p_data[12] << 24) + (p_data[13] << 16) + (p_data[14] << 8) + p_data[15];
            pd_log_fprintf(file, "       0x%08x", param_data[2]);
            param_data[3] = (p_data[16] << 24) + (p_data[17] << 16) + (p_data[18] << 8) + p_data[19];
            pd_log_fprintf(file, "                 0x%08x\n", param_data[3]);
            (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%d %d %d %d", param_data[0], param_data[1],
                param_data[2], param_data[3]);
            Json *str_obj = NULL;
            JsonStringCreate(tmp_str, &str_obj);
            JsonObjectItemSet(log_json, get_sas_ssd_kioxia_specific_key_str(param_code), str_obj);
        }
        p_data += param_head_len + param_len;
    }
}

/*
 * Description : 处理kioxia SSD Specific log信息
 * History：2020-11-19  新生成函数
 */
void pd_log_handle_sas_kioxia_ssd_specific(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *vendor_log_json)
{
    gint32 i, j, page_len, param_code, param_len;
    guint32 param_data, temp_value;
    const gint32 param_cnt = 18; // 只处理前18项数据
    const gint32 param_head_len = 4;
    gchar tmp_str[TMP_STR_LEN] = {0};
    Json *kioxia_ssd_specific_log_jso = NULL;

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

    guchar *p_data = pd_log->SASDevice.kioxia_ssd_specific.data;
    page_len = (p_data[2] << 8) + p_data[3]; // 第2、3byte为Page length
    if (page_len < 220) {                    // 截至parameter code 0x0017，共220字节
        return;
    }

    pd_log_fprintf(file, "ID#         ATTRIBUTE_NAME                                                          VALUE\n");

    guint32 ret = JsonObjectCreate(&kioxia_ssd_specific_log_jso);
    if (ret == JSON_ERR) {
        debug_log(DLOG_ERROR, "%s: JsonObjectCreate failed.\n", __FUNCTION__);
        return;
    }

    p_data = pd_log->SASDevice.kioxia_ssd_specific.data + SCSI_LOG_PAGE_HEADER_SIZE;
    for (i = 0; i < param_cnt; i++) {
        param_data = 0;
        param_code = (p_data[0] << 8) + p_data[1];
        param_len = p_data[3];
        if ((param_code < 0x08) || (param_code > 0x0D)) { // read error rate部分单独处理
            for (j = 0; j < param_len; j++) {
                temp_value = param_data;
                temp_value = temp_value << 8;
                param_data = temp_value + p_data[param_head_len + j];
            }
            pd_log_fprintf(file, "0x%02x(%3d)   %-70s  0x%016x\n", param_code, param_code,
                get_sas_ssd_kioxia_specific_attr_name(param_code), param_data);
            (void)snprintf_s(tmp_str, TMP_STR_LEN, TMP_STR_LEN - 1, "%u", param_data);
            Json *str_obj = NULL;
            JsonStringCreate(tmp_str, &str_obj);
            JsonObjectItemSet(kioxia_ssd_specific_log_jso, get_sas_ssd_kioxia_specific_key_str(param_code),
                str_obj);
        }
        p_data += param_head_len + param_len;
    }

    // read error rate部分数据处理
    pd_log_handle_sas_kioxia_read_error_rate(file, pd_log, out_put, kioxia_ssd_specific_log_jso);

    JsonObjectItemSet(vendor_log_json, "ssd_specific_log", kioxia_ssd_specific_log_jso);
}

/*
 * Description : 处理kioxia Endurance，Over Provisioning，Throttling Log信息
 * Notes：该log暂时没有需求记录数据采集日志，后续如有需求再新增
 * History：2020-11-19  新生成函数
 */
void pd_log_handle_sas_kioxia_eopt(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *vendor_log_json)
{
    gint32 i, page_len, param_code, param_data, reason;
    const gint32 param_cnt = 8;
    const gint8 param_size = 8;
    const gchar* name_str[] = {
        "Endurance indicator:",
        "Endurance threshold:",
        "Over provisioning Indicator:",
        "Over provisioning Threshold:",
        "System Life Indicator:",
        "System Life threshold:",
        "System Wear Indicator"
    };

    if (pd_log == NULL) {
        return;
    }

    guchar *p_data = pd_log->SASDevice.kioxia_eopt.data;
    page_len = (p_data[2] << 8) + p_data[3]; // 第2、3byte为Page length
    if (page_len < param_cnt * param_size) {
        return;
    }

    pd_log_fprintf(file, "ID#         ATTRIBUTE_NAME                  VALUE\n");

    p_data = pd_log->SASDevice.kioxia_eopt.data + SCSI_LOG_PAGE_HEADER_SIZE;
    for (i = 0; i < param_cnt; i++) {
        param_code = (p_data[0] << 8) + p_data[1];
        if (param_code == 0x10) {
            reason = p_data[6];
            param_data = p_data[7];
            pd_log_fprintf(file, "0x%02x(%3d)   Throttling Indicator            reason %d  throttling_indicator %d\n",
                param_code, param_code, reason, param_data);
        } else {
            if (param_code == 6) {
                param_data = (p_data[4] << 24) + (p_data[5] << 16) + (p_data[6] << 8) + p_data[7];
            } else {
                param_data = (p_data[6] << 8) + p_data[7];
            }
            pd_log_fprintf(file, "0x%02x(%3d)   %-30s  %d\n", param_code, param_code, name_str[param_code], param_data);
        }
        p_data += param_size;
    }
}

/*
 * Description : 处理kioxia SMART data信息
 * Notes：因当前缺少SMART 具体数据信息，log中记录原始数据，不进行数据采集
 * History：2020-11-19  新生成函数
 */
void pd_log_handle_sas_kioxia_smart_data(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *vendor_log_json)
{
    guint32 page_len;
    guint32 i = 0;

    if (pd_log == NULL) {
        return;
    }

    guchar *p_data = pd_log->SASDevice.kioxia_smart_data.data;
    page_len = pd_log->SASDevice.kioxia_smart_data.data_length;

    // 以每行16字节输出，并打印行号
    while (i < page_len) {
        if (i % 16 == 0) {
            pd_log_fprintf(file, "%3d:", (i / 16));
        }

        pd_log_fprintf(file, " %02x", p_data[i]);

        if (i % 16 == 15) {
            pd_log_fprintf(file, "\n");
        }
        i++;
    }
    pd_log_fprintf(file, "\n");
}
