/* 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 "diagnose_defs.h"
#include "pd_log_process.h"
#include "sata_log_parse.h"

#define ERR_FLAG_LEN 8
#define XERROR_LBA_REGULAR \
    "INTEL SSDSC(1N|2B)[ABPX]((080|100|120|150|160|200|240|300|400|480|600|800)G[3467]T?|(012|016)T[46])"

const gchar g_reserved[] = "[RESERVED]";
const gchar g_vendor_specific[] = "[VENDOR SPECIFIC]";
const gchar g_reserved_sa[] = "[RESERVED FOR SERIAL ATA]";
const gchar g_reserved_cf[] = "[RESERVED FOR COMPACTFLASH ASSOCIATION]";
const gchar g_reserved_mcpt[] = "[RESERVED FOR MEDIA CARD PASS THROUGH]"; // ACS-3: Reserved
const gchar g_recalibrate_ret4[] = "RECALIBRATE [RET-4]";
const gchar g_seek_ret4[] = "SEEK [RET-4]";

ATA_SMART_CMD_DESC_S g_cmd_desc_nop[] = {
    {0x0, "NOP [Abort queued commands]"},
    {0x1, "NOP [Don't abort queued commands] [OBS-ACS-2]"}
};

ATA_SMART_CMD_DESC_S g_cmd_desc_download_mc[] = {
    {0x01, "DOWNLOAD MICROCODE [Temporary] [OBS-8]"},
    {0x03, "DOWNLOAD MICROCODE [Save with offsets]"},
    {0x0e, "DOWNLOAD MICROCODE [Save for future use]"},
    {0x0f, "DOWNLOAD MICROCODE [Activate]"}
};

ATA_SMART_CMD_DESC_S g_cmd_desc_smart[] = {
    {0xD0, "SMART READ DATA"},
    {0xD1, "SMART READ ATTRIBUTE THRESHOLDS [OBS-4]"},
    {0xD2, "SMART ENABLE/DISABLE ATTRIBUTE AUTOSAVE"},
    {0xD3, "SMART SAVE ATTRIBUTE VALUES [OBS-6]"},
    {0xD4, "SMART EXECUTE OFF-LINE IMMEDIATE"},
    {0xD5, "SMART READ LOG"},
    {0xD6, "SMART WRITE LOG"},
    {0xD7, "SMART WRITE ATTRIBUTE THRESHOLDS [NS, OBS-4]"},
    {0xD8, "SMART ENABLE OPERATIONS"},
    {0xD9, "SMART DISABLE OPERATIONS"},
    {0xDA, "SMART RETURN STATUS"},
    {0xDB, "SMART EN/DISABLE AUTO OFFLINE [NS (SFF-8035i)]"}
};

ATA_SMART_CMD_DESC_S g_cmd_desc_device_cfg[] = {
    {0xC0, "DEVICE CONFIGURATION RESTORE [OBS-ACS-3]"},
    {0xC1, "DEVICE CONFIGURATION FREEZE LOCK [OBS-ACS-3]"},
    {0xC2, "DEVICE CONFIGURATION IDENTIFY [OBS-ACS-3]"},
    {0xC3, "DEVICE CONFIGURATION SET [OBS-ACS-3]"}
};

ATA_SMART_CMD_DESC_S g_cmd_desc_set_features[] = {
    {0x01, "SET FEATURES [Enable 8-bit PIO] [OBS-3]"},
    {0x02, "SET FEATURES [Enable write cache]"},
    {0x03, "SET FEATURES [Set transfer mode]"},
    {0x04, "SET FEATURES [Enable auto DR] [OBS-4]"},
    {0x05, "SET FEATURES [Enable APM]"},
    {0x06, "SET FEATURES [Enable Pwr-Up In Standby]"},
    {0x07, "SET FEATURES [Set device spin-up]"},
    {0x09, "SET FEATURES [Reserved (address offset)] [OPS-ACS-3]"},
    {0x0A, "SET FEATURES [Enable CFA power mode 1]"},
    {0x10, "SET FEATURES [Enable SATA feature]"},
    {0x20, "SET FEATURES [Set Time-ltd R/W WCT]"},
    {0x21, "SET FEATURES [Set Time-ltd R/W EH]"},
    {0x31, "SET FEATURES [Disable Media Status Notf] [OBS-8]"},
    {0x33, "SET FEATURES [Disable retry] [OBS-4]"},
    {0x41, "SET FEATURES [Enable Free-fall Control]"},
    {0x42, "SET FEATURES [Enable AAM] [OBS-ACS-2]"},
    {0x43, "SET FEATURES [Set Max Host I/F S Times]"},
    {0x44, "SET FEATURES [Length of VS data] [OBS-4]"},
    {0x4a, "SET FEATURES [Ext. Power Conditions]"},
    {0x54, "SET FEATURES [Set cache segs] [OBS-4]"},
    {0x55, "SET FEATURES [Disable read look-ahead]"},
    {0x5D, "SET FEATURES [Enable release interrupt] [OBS-ACS-2]"},
    {0x5E, "SET FEATURES [Enable SERVICE interrupt] [OBS-ACS-2]"},
    {0x66, "SET FEATURES [Disable revert defaults]"},
    {0x69, "SET FEATURES [LPS Error Reporting Control]"},
    {0x77, "SET FEATURES [Disable ECC] [OBS-4]"},
    {0x81, "SET FEATURES [Disable 8-bit PIO] [OBS-3]"},
    {0x82, "SET FEATURES [Disable write cache]"},
    {0x84, "SET FEATURES [Disable auto DR] [OBS-4]"},
    {0x85, "SET FEATURES [Disable APM]"},
    {0x86, "SET FEATURES [Disable Pwr-Up In Standby]"},
    {0x88, "SET FEATURES [Disable ECC] [OBS-4]"},
    {0x89, "SET FEATURES [Reserved (address offset)]"},
    {0x8A, "SET FEATURES [Disable CFA power mode 1]"},
    {0x90, "SET FEATURES [Disable SATA feature]"},
    {0x95, "SET FEATURES [Enable Media Status Notf] [OBS-8]"},
    {0x99, "SET FEATURES [Enable retries] [OBS-4]"},
    {0x9A, "SET FEATURES [Set max avg curr] [OBS-4]"},
    {0xAA, "SET FEATURES [Enable read look-ahead]"},
    {0xAB, "SET FEATURES [Set max prefetch] [OBS-4]"},
    {0xBB, "SET FEATURES [4 bytes VS data] [OBS-4]"},
    {0xC1, "SET FEATURES [Disable Free-fall Control]"},
    {0xC2, "SET FEATURES [Disable AAM] [OBS-ACS-2]"},
    {0xC3, "SET FEATURES [Sense Data Reporting]"},
    {0xCC, "SET FEATURES [Enable revert to defaults]"},
    {0xDD, "SET FEATURES [Disable release interrupt] [OBS-ACS-2]"},
    {0xDE, "SET FEATURES [Disable SERVICE interrupt] [OBS-ACS-2]"},
    {0xE0, "SET FEATURES [Vendor specific] [OBS-7]"}
};

ATA_SMART_CMD_DESC_S g_cmd_desc_set_max[] = {
    {0x00, "SET MAX ADDRESS [OBS-6]"},
    {0x01, "SET MAX SET PASSWORD [OBS-ACS-3]"},
    {0x02, "SET MAX LOCK [OBS-ACS-3]"},
    {0x03, "SET MAX UNLOCK [OBS-ACS-3]"},
    {0x04, "SET MAX FREEZE LOCK [OBS-ACS-3]"}
};

// ATAATAPI-6文档8节内容
const gchar * const g_cmd_table[256] = {
    // 00h-0Fh
    "NOP", // 00h
    g_reserved,
    g_reserved,
    "CFA REQUEST EXTENDED ERROR", // 03h
    g_reserved,
    g_reserved,
    "DATA SET MANAGEMENT", // 06h
    g_reserved,
    "DEVICE RESET", // 08h
    g_reserved,
    g_reserved,
    "REQUEST SENSE DATA EXT", // 0Bh
    g_reserved,
    g_reserved,
    g_reserved,
    g_reserved,
    // 10h-1Fh
    "RECALIBRATE [OBS-4]", // 10h
    g_recalibrate_ret4, g_recalibrate_ret4, g_recalibrate_ret4,
    g_recalibrate_ret4, g_recalibrate_ret4, g_recalibrate_ret4,
    g_recalibrate_ret4, g_recalibrate_ret4, g_recalibrate_ret4,
    g_recalibrate_ret4, g_recalibrate_ret4, g_recalibrate_ret4,
    g_recalibrate_ret4, g_recalibrate_ret4, g_recalibrate_ret4,
    // 20h-2Fh
    "READ SECTOR(S)",                          // 20h
    "READ SECTOR(S) [OBS-5]",                  // 21h
    "READ LONG [OBS-4]",                       // 22h
    "READ LONG (w/o retry) [OBS-4]",           // 23h
    "READ SECTOR(S) EXT",                      // 24h
    "READ DMA EXT",                            // 25h
    "READ DMA QUEUED EXT [OBS-ACS-2]",         // 26h
    "READ NATIVE MAX ADDRESS EXT [OBS-ACS-3]", // 27h
    g_reserved,
    "READ MULTIPLE EXT", // 29h
    "READ STREAM DMA",   // 2Ah
    "READ STREAM",       // 2Bh
    g_reserved,
    g_reserved,
    g_reserved,
    "READ LOG EXT",                              // 2Fh
                                                 // 30h-3Fh
    "WRITE SECTOR(S)",                           // 30h
    "WRITE SECTOR(S) (w/o retry) [OBS-5]",       // 31h
    "WRITE LONG [OBS-4]",                        // 32h
    "WRITE LONG (w/o retry) [OBS-4]",            // 33h
    "WRITE SECTORS(S) EXT",                      // 34h
    "WRITE DMA EXT",                             // 35h
    "WRITE DMA QUEUED EXT [OBS-ACS-2]",          // 36h
    "SET NATIVE MAX ADDRESS EXT [OBS-ACS-3]",    // 37h
    "CFA WRITE SECTORS WITHOUT ERASE",           // 38h
    "WRITE MULTIPLE EXT",                        // 39h
    "WRITE STREAM DMA",                          // 3Ah
    "WRITE STREAM",                              // 3Bh
    "WRITE VERIFY [OBS-4]",                      // 3Ch
    "WRITE DMA FUA EXT",                         // 3Dh
    "WRITE DMA QUEUED FUA EXT [OBS-ACS-2]",      // 3Eh
    "WRITE LOG EXT",                             // 3Fh
                                                 // 40h-4Fh
    "READ VERIFY SECTOR(S)",                     // 40h
    "READ VERIFY SECTOR(S) (w/o retry) [OBS-5]", // 41h
    "READ VERIFY SECTOR(S) EXT",                 // 42h
    g_reserved,
    g_reserved,
    "WRITE UNCORRECTABLE EXT", // 45h
    g_reserved,
    "READ LOG DMA EXT", // 47h
    g_reserved,
    g_reserved,
    g_reserved,
    g_reserved,
    g_reserved,
    g_reserved,
    g_reserved,
    g_reserved,
    // 50h-5Fh
    "FORMAT TRACK [OBS-4]", // 50h
    "CONFIGURE STREAM",     // 51h
    g_reserved,
    g_reserved,
    g_reserved,
    g_reserved,
    g_reserved,
    "WRITE LOG DMA EXT", // 57h
    g_reserved,
    g_reserved,
    g_reserved,
    "TRUSTED NON-DATA",    // 5Bh
    "TRUSTED RECEIVE",     // 5Ch
    "TRUSTED RECEIVE DMA", // 5Dh
    "TRUSTED SEND",        // 5Eh
    "TRUSTED SEND DMA",    // 5Fh
                           // 60h-6Fh
    "READ FPDMA QUEUED",   // 60h
    "WRITE FPDMA QUEUED",  // 61h
    g_reserved_sa,
    "NCQ QUEUE MANAGEMENT", // 63h
    "SEND FPDMA QUEUED",    // 64h
    "RECEIVE FPDMA QUEUED", // 65h
    g_reserved_sa,
    g_reserved_sa,
    g_reserved,
    g_reserved,
    g_reserved,
    g_reserved,
    g_reserved,
    g_reserved,
    g_reserved,
    g_reserved,
    // 70h-7Fh
    "SEEK [OBS-7]", // 70h
    g_seek_ret4,
    g_seek_ret4,
    g_seek_ret4,
    g_seek_ret4,
    g_seek_ret4,
    g_seek_ret4,
    "SET DATE & TIME EXT",                  // 76h
    "ACCESSIBLE MAX ADDRESS CONFIGURATION", // 77h
    g_seek_ret4,
    g_seek_ret4,
    g_seek_ret4,
    g_seek_ret4,
    g_seek_ret4,
    g_seek_ret4,
    g_seek_ret4,
    // 80h-8Fh
    g_vendor_specific,
    g_vendor_specific,
    g_vendor_specific,
    g_vendor_specific,
    g_vendor_specific,
    g_vendor_specific,
    g_vendor_specific,
    "CFA TRANSLATE SECTOR [VS IF NO CFA]", // 87h
    g_vendor_specific,
    g_vendor_specific,
    g_vendor_specific,
    g_vendor_specific,
    g_vendor_specific,
    g_vendor_specific,
    g_vendor_specific,
    g_vendor_specific,
    // 90h-9Fh
    "EXECUTE DEVICE DIAGNOSTIC",            // 90h
    "INITIALIZE DEVICE PARAMETERS [OBS-6]", // 91h
    "DOWNLOAD MICROCODE",                   // 92h
    "DOWNLOAD MICROCODE DMA",               // 93h
    "STANDBY IMMEDIATE [RET-4]",            // 94h
    "IDLE IMMEDIATE [RET-4]",               // 95h
    "STANDBY [RET-4]",                      // 96h
    "IDLE [RET-4]",                         // 97h
    "CHECK POWER MODE [RET-4]",             // 98h
    "SLEEP [RET-4]",                        // 99h
    g_vendor_specific,
    g_reserved,
    g_reserved,
    g_reserved,
    g_reserved,
    g_reserved,
    // A0h-AFh
    "PACKET",                 // A0h
    "IDENTIFY PACKET DEVICE", // A1h
    "SERVICE [OBS-ACS-2]",    // A2h
    g_reserved, g_reserved, g_reserved,
    g_reserved, g_reserved, g_reserved,
    g_reserved, g_reserved, g_reserved,
    g_reserved, g_reserved, g_reserved,
    g_reserved,
    // B0h-BFh
    "SMART",                            // B0h
    "DEVICE CONFIGURATION [OBS-ACS-3]", // B1h
    g_reserved,
    g_reserved,
    "SANITIZE DEVICE", // B4h
    g_reserved,
    "NV CACHE [OBS-ACS-3]", // B6h
    g_reserved_cf,
    g_reserved_cf,
    g_reserved_cf,
    g_reserved_cf,
    g_reserved_cf,
    g_reserved,
    g_reserved,
    g_reserved,
    g_reserved,
    // C0h-CFh
    "CFA ERASE SECTORS [VS IF NO CFA]", // C0h
    g_vendor_specific,
    g_vendor_specific,
    g_vendor_specific,
    "READ MULTIPLE",                    // C4h
    "WRITE MULTIPLE",                   // C5h
    "SET MULTIPLE MODE",                // C6h
    "READ DMA QUEUED [OBS-ACS-2]",      // C7h
    "READ DMA",                         // C8h
    "READ DMA (w/o retry) [OBS-5]",     // C9h
    "WRITE DMA",                        // CAh
    "WRITE DMA (w/o retry) [OBS-5]",    // CBh
    "WRITE DMA QUEUED [OBS-ACS-2]",     // CCh
    "CFA WRITE MULTIPLE WITHOUT ERASE", // CDh
    "WRITE MULTIPLE FUA EXT",           // CEh
    g_reserved,
    // D0h-DFh
    g_reserved,
    "CHECK MEDIA CARD TYPE [OBS-ACS-2]", // D1h
    g_reserved_mcpt,
    g_reserved_mcpt,
    g_reserved_mcpt,
    g_reserved,
    g_reserved,
    g_reserved,
    g_reserved,
    g_reserved,
    "GET MEDIA STATUS [OBS-8]",         // DAh
    "ACKNOWLEDGE MEDIA CHANGE [RET-4]", // DBh
    "BOOT POST-BOOT [RET-4]",           // DCh
    "BOOT PRE-BOOT [RET-4]",            // DDh
    "MEDIA LOCK [OBS-8]",               // DEh
    "MEDIA UNLOCK [OBS-8]",             // DFh
                                        // E0h-EFh
    "STANDBY IMMEDIATE",                // E0h
    "IDLE IMMEDIATE",                   // E1h
    "STANDBY",                          // E2h
    "IDLE",                             // E3h
    "READ BUFFER",                      // E4h
    "CHECK POWER MODE",                 // E5h
    "SLEEP",                            // E6h
    "FLUSH CACHE",                      // E7h
    "WRITE BUFFER",                     // E8h
    "READ BUFFER DMA",                  // E9h
    "FLUSH CACHE EXT",                  // EAh
    "WRITE BUFFER DMA",                 // EBh
    "IDENTIFY DEVICE",                  // ECh
    "MEDIA EJECT [OBS-8]",              // EDh
    "IDENTIFY DEVICE DMA [OBS-4]",      // EEh
    "SET FEATURES",                     // EFh
                                        // F0h-FFh
    g_vendor_specific,
    "SECURITY SET PASSWORD",     // F1h
    "SECURITY UNLOCK",           // F2h
    "SECURITY ERASE PREPARE",    // F3h
    "SECURITY ERASE UNIT",       // F4h
    "SECURITY FREEZE LOCK",      // F5h
    "SECURITY DISABLE PASSWORD", // F6h
    g_vendor_specific,
    "READ NATIVE MAX ADDRESS [OBS-ACS-3]", // F8h
    "SET MAX ADDRESS [OBS-ACS-3]",         // F9h
    g_vendor_specific,
    g_vendor_specific,
    g_vendor_specific,
    g_vendor_specific,
    g_vendor_specific,
    g_vendor_specific
};

ATA_SMART_CMD_DESC_S g_selftest_desc[] = {
    {0x00, "Offline"},
    {0x01, "Short offline"},
    {0x02, "Extended offline"},
    {0x03, "Conveyance offline"},
    {0x04, "Selective offline"},
    {0x7f, "Abort offline test"},
    {0x81, "Short captive"},
    {0x82, "Extended captive"},
    {0x83, "Conveyance captive"},
    {0x84, "Selective captive"}
};

guint16 IS_ATA_SMART_ATTRIBUTE_FLAGS_VALID(guint16 num, guint16 offset)
{
    return num & (1 << offset);
}

/*
 * Description: 诊断sata盘的Reallocated sector count属性
 * History: 1.2019年3月2日,
 * 新生成函数
 */
static void pd_log_sata_smart_reallocated_diagnose(PD_LOG_S *pd_log, ATA_SMART_ATTRIBUTE_S *attr_info,
    ATA_SMART_THRESHOLD_ENTRY_S *threshold_entry, SML_PD_FAULT_ANALYSIS *result)
{
    if (NULL == pd_log || NULL == attr_info || NULL == result || 1 == result->o_fault_bitmap.pd_smart_log_error ||
        NULL == threshold_entry || PD_MEDIA_TYPE_SSD == pd_log->pd_media_type) {
        return;
    }

    guint8 reallocated_default = 100;
    guint8 wd_reallocated_default = 200;
    gchar key_name_cur[MAX_FILEPATH_LENGTH + 1] = {0};
    gchar key_name_thre[MAX_FILEPATH_LENGTH + 1] = {0};

    // 根据厂商获取default值
    if (NULL != strstr(pd_log->pd_manufacturer, PD_VENDOR_NAME_WDC)) {
        reallocated_default = wd_reallocated_default;
    }

    (void)snprintf_s(key_name_cur, MAX_FILEPATH_LENGTH + 1, MAX_FILEPATH_LENGTH, "SMARTAttribute%hhu", attr_info->id);

    (void)snprintf_s(key_name_thre, MAX_FILEPATH_LENGTH + 1, MAX_FILEPATH_LENGTH, "SMARTAttributeThreshold%hhu",
        attr_info->id);

    // 诊断故障
    if (attr_info->id == threshold_entry->id &&
        attr_info->current < ((guint16)threshold_entry->threshold + reallocated_default) / 2) { // 取平均值作为阈值
        result->o_fault_bitmap.pd_smart_log_error = 1;
        (void)snprintf_s(result->io_buf, sizeof(result->io_buf), sizeof(result->io_buf) - 1,
            "smart attribute id: %hhu, current: %hhu, threshold: %d", attr_info->id, attr_info->current,
            ((guint16)threshold_entry->threshold + reallocated_default) / 2); // 取平均值作为阈值
    }

    return;
}

/*
 * Description: 诊断sata盘Pending Sector属性
 * History: 1.2019年3月2日,
 * 新生成函数
 */
static void pd_log_sata_smart_pending_diagnose(PD_LOG_S *pd_log, ATA_SMART_ATTRIBUTE_S *attr_info,
    SML_PD_FAULT_ANALYSIS *result)
{
    if (NULL == pd_log || NULL == attr_info || NULL == result || 1 == result->o_fault_bitmap.pd_smart_log_error ||
        PD_MEDIA_TYPE_SSD == pd_log->pd_media_type) {
        return;
    }

    gint32 ret = 0;
    const guint64 pending_sector_threshold = 100;
    guint32 idx = 0;
    guint64 raw_value = 0;
    guint64 temp_value = 0;
    guint8 raw_value_size = 0;
    gchar key_name_cur[MAX_FILEPATH_LENGTH + 1] = {0};

    raw_value_size = (guint8)G_N_ELEMENTS(attr_info->raw);
    (void)snprintf_s(key_name_cur, MAX_FILEPATH_LENGTH + 1, MAX_FILEPATH_LENGTH, "SMARTAttribute%hhu", attr_info->id);

    for (idx = 0; idx < raw_value_size; idx++) { /* 结构体中数组的大小为6 */
        temp_value = attr_info->raw[idx];
        temp_value = temp_value << (sizeof(guint64) * idx);
        raw_value |= temp_value;
    }

    // 诊断故障
    if (raw_value > pending_sector_threshold) {
        result->o_fault_bitmap.pd_smart_log_error = 1;
        ret = snprintf_s(result->io_buf, sizeof(result->io_buf), sizeof(result->io_buf) - 1,
            "smart attribute id: %d, current: %" G_GUINT64_FORMAT ", threshold: %" G_GUINT64_FORMAT, attr_info->id,
            raw_value, pending_sector_threshold);
        if (0 >= ret) {
            debug_log(DLOG_ERROR, "%s: snprintf_s error.", __FUNCTION__);
        }
    }

    return;
}

/*
 * Description: 诊断sata盘的CRC Error Count属性
 * History: 1.2019年3月2日,
 * 新生成函数
 */
static void pd_log_sata_smart_crc_diagnose(PD_LOG_S *pd_log, ATA_SMART_ATTRIBUTE_S *attr_info,
    SML_PD_FAULT_ANALYSIS *result)
{
    if (NULL == pd_log || NULL == attr_info || NULL == result || 1 == result->o_fault_bitmap.pd_smart_log_error) {
        return;
    }

    gint32 ret = 0;
    const guint64 crc_error_threshold = 50;
    guint32 idx = 0;
    guint64 raw_value = 0;
    guint64 temp_value = 0;
    guint8 raw_value_size = 0;
    gchar key_name_cur[MAX_FILEPATH_LENGTH + 1] = {0};

    raw_value_size = (guint8)G_N_ELEMENTS(attr_info->raw);
    (void)snprintf_s(key_name_cur, MAX_FILEPATH_LENGTH + 1, MAX_FILEPATH_LENGTH, "SMARTAttribute%hhu", attr_info->id);

    for (idx = 0; idx < raw_value_size; idx++) { /* 结构体中数组的大小为6 */
        temp_value = attr_info->raw[idx];
        temp_value = temp_value << (sizeof(guint64) * idx);
        raw_value |= temp_value;
    }

    // 诊断故障
    if (raw_value > crc_error_threshold) {
        result->o_fault_bitmap.pd_crc_error = 1;
        ret = snprintf_s(result->io_buf, sizeof(result->io_buf), sizeof(result->io_buf) - 1,
            "smart attribute id: %d, current: %" G_GUINT64_FORMAT ", threshold: %" G_GUINT64_FORMAT, attr_info->id,
            raw_value, crc_error_threshold);
        if (0 >= ret) {
            debug_log(DLOG_ERROR, "%s: snprintf_s error.", __FUNCTION__);
        }
    }

    return;
}

/*
 * Description: 获取硬盘剩余寿命smart id
 * History: 1.2019年2月14日,
 * 新生成函数
 */
static guint8 pd_log_get_smart_wearout_id(PD_LOG_S *pd_log)
{
    if (pd_log == NULL) {
        return G_MAXUINT8;
    }

    guint8 i;
    PD_VENDOR_NAME_ATTR_ID_S vendor_attr_id[] = {
        {PD_VENDOR_NAME_INTEL,        ATA_SMART_ATTRIBUTE_ID_MEDIA_WEAROUT_INDICATOR},            // INTEL
        {PD_VENDOR_NAME_SAMSUNG,      ATA_SMART_ATTRIBUTE_ID_WEAR_LEVELING_COUNT},              // SAMSUNG
        {PD_VENDOR_NAME_MICRON,       ATA_SMART_ATTRIBUTE_ID_PERCENT_LIFETIME_REMAINING},        // MICRON
        {PD_VENDOR_NAME_SANDISK,      ATA_SMART_ATTRIBUTE_ID_DRIVE_LIFETIME_REMAINNING},        // SANDISK
        {PD_VENDOR_NAME_SMI,          ATA_SMART_ATTRIBUTE_ID_DRIVE_TEMPERATURE},                    // SMI
        {PD_VENDOR_NAME_LITE_ON,      ATA_SMART_ATTRIBUTE_ID_DRIVE_LIFETIME_REMAINNING},        // LITE ON
        {PD_VENDOR_NAME_PHISON,       ATA_SMART_ATTRIBUTE_ID_DRIVE_TEMPERATURE},                 // PHISON
        {PD_VENDOR_NAME_SSSTC,        ATA_SMART_ATTRIBUTE_ID_DRIVE_TEMPERATURE},                  // SSSTC
        {PD_VENDOR_NAME_HYNIX,        ATA_SMART_ATTRIBUTE_ID_DRIVE_TEMPERATURE},                  // HYNIX
        {PD_VENDOR_NAME_HUAWEI,       ATA_SMART_ATTRIBUTE_ID_DRIVE_TEMPERATURE},                 // HUAWEI
        {PD_VENDOR_NAME_YANGTZE_MEMORY,  ATA_SMART_ATTRIBUTE_ID_DRIVE_LIFETIME_REMAINNING}, // YANGTZE MEMORY
        {PD_VENDOR_NAME_RAMAXEL,       ATA_SMART_ATTRIBUTE_ID_DRIVE_TEMPERATURE},                // RAMAXEL
        {PD_VENDOR_NAME_UMIS,          ATA_SMART_ATTRIBUTE_ID_DRIVE_TEMPERATURE},                   // UMIS
        {PD_VENDOR_NAME_DERA,          ATA_SMART_ATTRIBUTE_ID_PERCENT_WEAROUT_REMAINING},           // DERA
        {PD_VENDOR_NAME_DATSSD,        ATA_SMART_ATTRIBUTE_ID_MEDIA_WEAROUT_INDICATOR},     // DATSSD
        {PD_VENDOR_NAME_HUADIAN,       ATA_SMART_ATTRIBUTE_ID_AVAILABLE_RESERVED_SPACE},  // HUADIAN SSD
        {NULL},                                                                           // 必须放在最后
    };
    // 使用厂商获取id
    for (i = 0; vendor_attr_id[i].vendor_name != NULL; i++) {
        if (strncasecmp(pd_log->pd_manufacturer, vendor_attr_id[i].vendor_name,
            strlen(vendor_attr_id[i].vendor_name)) == 0 ||
            strstr(pd_log->pd_manufacturer, vendor_attr_id[i].vendor_name) != NULL ||
            strncasecmp(pd_log->pd_model, vendor_attr_id[i].vendor_name, strlen(vendor_attr_id[i].vendor_name)) == 0 ||
            strstr(pd_log->pd_model, vendor_attr_id[i].vendor_name) != NULL) {
            return vendor_attr_id[i].attr_id;
        }
    }
    return G_MAXUINT8;
}

/*
 * Description: 诊断sata盘的Endurance Indicator属性 剩余寿命
 * History: 1.2019年3月2日,
 * 新生成函数
 */
static void pd_log_sata_smart_endurance_diagnose(PD_LOG_S *pd_log, ATA_SMART_ATTRIBUTE_S *attr_info,
    ATA_SMART_THRESHOLD_ENTRY_S *threshold_entry, SML_PD_FAULT_ANALYSIS *result)
{
    if (NULL == pd_log || NULL == attr_info || NULL == result || 1 == result->o_fault_bitmap.pd_smart_log_error ||
        NULL == threshold_entry || PD_MEDIA_TYPE_SSD != pd_log->pd_media_type) {
        return;
    }

    gchar key_name_cur[MAX_FILEPATH_LENGTH + 1] = {0};
    gchar key_name_thre[MAX_FILEPATH_LENGTH + 1] = {0};

    // 剩余寿命检测，需要根据厂商获取id
    if (attr_info->id != pd_log_get_smart_wearout_id(pd_log)) {
        return;
    }
    (void)snprintf_s(key_name_cur, MAX_FILEPATH_LENGTH + 1, MAX_FILEPATH_LENGTH, "SMARTAttribute%hhu", attr_info->id);

    (void)snprintf_s(key_name_thre, MAX_FILEPATH_LENGTH + 1, MAX_FILEPATH_LENGTH, "SMARTAttributeThreshold%hhu",
        attr_info->id);

    // 诊断故障
    if (attr_info->current < (threshold_entry->threshold + 1)) {
        result->o_fault_bitmap.pd_smart_log_error = 1;
        (void)snprintf_s(result->io_buf, sizeof(result->io_buf), sizeof(result->io_buf) - 1,
            "smart attribute id: %hhu, current: %hhu, threshold: %u", attr_info->id, attr_info->current,
            threshold_entry->threshold + 1);
    }

    return;
}

/*
 * Description: 根据smart信息诊断硬盘故障
 * History: 1.2019年1月4日,
 * 新生成函数          PN:UADP135084
 */
static void pd_log_handle_sata_smart_diagnose(PD_LOG_S *pd_log, ATA_SMART_ATTRIBUTE_S *attr_info,
    ATA_SMART_THRESHOLD_ENTRY_S *threshold_entry, SML_PD_FAULT_ANALYSIS *result)
{
    if (NULL == pd_log || NULL == attr_info || NULL == result || 1 == result->o_fault_bitmap.pd_smart_log_error) {
        return;
    }

    switch (attr_info->id) {
        case ATA_SMART_ATTRIBUTE_ID_REALLOCATED_SECTORS_COUNT:
            pd_log_sata_smart_reallocated_diagnose(pd_log, attr_info, threshold_entry, result);
            break;

        case ATA_SMART_ATTRIBUTE_ID_CURRENT_PENDING_SECTOR:
            pd_log_sata_smart_pending_diagnose(pd_log, attr_info, result);
            break;

        case ATA_SMART_ATTRIBUTE_ID_UDMA_CRC_ERROR_COUNT:
            pd_log_sata_smart_crc_diagnose(pd_log, attr_info, result);
            break;
        default:
            break;
    }

    if (1 == result->o_fault_bitmap.pd_smart_log_error) {
        return;
    }

    // 剩余寿命检测
    pd_log_sata_smart_endurance_diagnose(pd_log, attr_info, threshold_entry, result);

    return;
}

/*
 * Description: 处理SATA盘的SMART Attribute数据
 * History: 1.2018年1月13日
 * 新生成函数
 */
void pd_log_handle_sata_smart(FILE *file, PD_LOG_S *pd_log, void *output)
{
    guint32 idx = 0;
    gchar  raw_data_str[ATA_SMART_DATA_LENGTH] = {0};
    ATA_SMART_DATA_S *smart_data = NULL;
    ATA_SMART_THRESHOLDS_S *smart_threshold = NULL;
    ATA_SMART_ATTRIBUTE_S *attr_info = NULL;
    ATA_SMART_THRESHOLD_ENTRY_S *threshold_entry = NULL;
    const gchar *attr_status = NULL;
    const gchar *disk_type = NULL, *disk_update = NULL;
    gint32 failed_now = 0, failed_ever = 0;
    gchar thresholdstr[ATA_LOG_STRING_LENGTH] = {0};
    SML_PD_FAULT_ANALYSIS *result = (SML_PD_FAULT_ANALYSIS *)output;
    guint8 tmp_data_error = 0;

    if (pd_log == NULL) {
        return;
    }

    debug_log(DLOG_INFO, "Handle physical drive %s log SMART Attribute.", pd_log->pd_device_name);

    tmp_data_error = (SML_SUCCESS != pd_log->SATADevice.smart_attribute.result &&
        SML_ERR_PD_SCSI_RESP_TRUNCATED != pd_log->SATADevice.smart_attribute.result &&
        SML_ERR_PD_SCSI_RESP_NO_DATA != pd_log->SATADevice.smart_attribute.result);
    if (tmp_data_error) {
        pd_log_fprintf(file, "Get SMART Attribute failed.");
        tmp_data_error = ((SML_ERR_PD_SCSI_STATUS_BUSY == pd_log->SATADevice.smart_attribute.result ||
            SML_ERR_PD_SCSI_CMD_FAIL == pd_log->SATADevice.smart_attribute.result) &&
            0 != pd_log->SATADevice.smart_attribute.scsi_status_code);
        if (tmp_data_error) {
            pd_log_fprintf(file, "SCSI command is busy or failed, status code : 0x%02x .\n",
                pd_log->SATADevice.smart_attribute.scsi_status_code);
        } else {
            pd_log_fprintf(file, "\n");
        }
        return;
    }

    tmp_data_error = (SML_SUCCESS != pd_log->SATADevice.smart_attribute_threshold.result &&
        SML_ERR_PD_SCSI_RESP_TRUNCATED != pd_log->SATADevice.smart_attribute_threshold.result &&
        SML_ERR_PD_SCSI_RESP_NO_DATA != pd_log->SATADevice.smart_attribute_threshold.result);
    if (tmp_data_error) {
        pd_log_fprintf(file, "Get SMART Attribute Threshold failed.\n");
        tmp_data_error = ((SML_ERR_PD_SCSI_STATUS_BUSY == pd_log->SATADevice.smart_attribute_threshold.result ||
            SML_ERR_PD_SCSI_CMD_FAIL == pd_log->SATADevice.smart_attribute_threshold.result) &&
            0 != pd_log->SATADevice.smart_attribute_threshold.scsi_status_code);
        if (tmp_data_error) {
            pd_log_fprintf(file, "SCSI command is busy or failed, status code : 0x%02x .\n",
                pd_log->SATADevice.smart_attribute_threshold.scsi_status_code);
        } else {
            pd_log_fprintf(file, "\n");
        }
        return;
    }

    if (SML_ERR_PD_SCSI_RESP_NO_DATA == pd_log->SATADevice.smart_attribute.result ||
        NULL == pd_log->SATADevice.smart_attribute.data || 0 == pd_log->SATADevice.smart_attribute.data_length) {
        pd_log_fprintf(file, "SMART Attribute Data is empty.\n");
        return;
    }

    if (SML_ERR_PD_SCSI_RESP_NO_DATA == pd_log->SATADevice.smart_attribute_threshold.result ||
        NULL == pd_log->SATADevice.smart_attribute_threshold.data ||
        0 == pd_log->SATADevice.smart_attribute_threshold.data_length) {
        pd_log_fprintf(file, "SMART Attribute Threshold Data is empty.\n");
        return;
    }

    smart_data = (ATA_SMART_DATA_S *)pd_log->SATADevice.smart_attribute.data;
    smart_threshold = (ATA_SMART_THRESHOLDS_S *)pd_log->SATADevice.smart_attribute_threshold.data;

    pd_log_fprintf(file, "-----------------------------------------------------------------------------------------\n");
    pd_log_fprintf(file, "SMART ATTRIBIUTE DATA version NO: %d\n", smart_data->revNumber);
    pd_log_fprintf(file, "+-----+--------------------------------+--------+-------+-------+-----------+----------");
    pd_log_fprintf(file, "+-----------+-------------+--------------------------------+\n");
    pd_log_fprintf(file, "|  ID |       ATTRIBUTE_NAME           |  FLAG  | VALUE | WORST | THRESHOLD |   TYPE   ");
    pd_log_fprintf(file, "|  UPDATED  | WHEN_FAILED |           RAW_VALUE            |\n");
    pd_log_fprintf(file, "+-----+--------------------------------+--------+-------+-------+-----------+----------");
    pd_log_fprintf(file, "+-----------+-------------+--------------------------------+\n");

    for (idx = 0; idx < GET_ARRAY_ITEMS(smart_data->smartAttribute);
        idx++) { /* smart 信息的个数为30 */
        attr_info = &smart_data->smartAttribute[idx];
        threshold_entry = &smart_threshold->thresholdEntries[idx];
        if (attr_info->id) {
            // 诊断故障
            /* BEGIN: Added by, 2019/1/16   PN:UADP135084 */
            // 诊断出故障后，无需继续遍历下一个SMART属性，直接返回
            pd_log_handle_sata_smart_diagnose(pd_log, attr_info, threshold_entry, result);
            if (NULL != result && 1 == result->o_fault_bitmap.pd_smart_log_error) {
                return;
            }
            /* END:   Added by, 2019/1/16 */
            if (threshold_entry->threshold != 0) {
                failed_now = 0;
                failed_ever = 0;
            } else {
                failed_now = (attr_info->current <= threshold_entry->threshold);
                failed_ever = (attr_info->worst <= threshold_entry->threshold);
            }

            if (attr_info->id != threshold_entry->id) {
                (void)snprintf_s(thresholdstr, sizeof(thresholdstr), sizeof(thresholdstr) - 1, "---");
            } else {
                (void)snprintf_s(thresholdstr, sizeof(thresholdstr), sizeof(thresholdstr) - 1, "%.3hhu",
                    threshold_entry->threshold);
            }

            // 判断是否有历史失败记录
            if (failed_now) {
                attr_status = "FAILING_NOW";
            } else if (failed_ever) {
                attr_status = "IN_THE_PAST";
            } else {
                attr_status = "    -";
            }

            disk_type = IS_ATA_SMART_ATTRIBUTE_FLAGS_VALID(attr_info->flags, 0) ? "Pre-fail" : "Old_age";
            disk_update = IS_ATA_SMART_ATTRIBUTE_FLAGS_VALID(attr_info->flags, 1) ? "Always" : "Offline";
            sml_adapter_parse_ata_smart_attr_raw_value(raw_data_str, sizeof(raw_data_str), attr_info, NULL);

            pd_log_fprintf(file, "| %3hu | %-30s ", attr_info->id, sml_adapter_get_ata_smart_attr_name(attr_info->id));
            pd_log_fprintf(file, "| 0x%04x | %.5d ", attr_info->flags, attr_info->current);
            pd_log_fprintf(file, "| %.5d | %-9s | %-8s ", attr_info->worst, thresholdstr, disk_type);
            pd_log_fprintf(file, "| %-9s | %-11s | %-30s |\n", disk_update, attr_status, raw_data_str);
        }
    }

    pd_log_fprintf(file, "+-----+--------------------------------+--------+-------+-------+-----------+----------");
    pd_log_fprintf(file, "+-----------+-------------+--------------------------------+\n");

    return;
}

/*
 * Description: 获取错误类型描述
 * History: 1.2018年4月13日
 * 新生成函数
 */
static void pd_log_err_desc(ATA_SMART_ERRLOG_INPUT_S *input, const ATA_SMART_ERRLOG_ERR_S *error_log_error,
    const ATA_SMART_EXTERRLOG_ERROR_S *extent_error_log_error, gchar *desc, size_t desc_len, Json *out_put_jso)
{
    errno_t safe_fun_ret = EOK;
    const gchar *err_flag[ERR_FLAG_LEN];
    size_t str_len = 0;
    gint32 i, num, lba_print = 0, sector_print = 0;
    guint32 err_lba;
    guint64 ext_err_lba;
    gchar tmp_buf[ATA_LOG_STRING_LENGTH] = {0};

    if (input == NULL || desc == NULL || desc_len == 0 || desc_len < ATA_LOG_STRING_LENGTH || out_put_jso == NULL) {
        return;
    }

    (void)memset_s(desc, desc_len, 0, desc_len);

    /* 初始化为NULL 表示flag 未使用 */
    for (i = 0; i < ERR_FLAG_LEN; i++) {
        err_flag[i] = NULL;
    }

    switch (input->commandReg) {
        case ATA_CMD_RECALIBRATE:
            err_flag[2] = ERR_CODE_ABORTED;
            err_flag[1] = ERR_CODE_TRACK0_NOT_FOUND;
            break;

        case ATA_CMD_READ_SECTORS:
        case ATA_CMD_READ_SECTORS_NEW:
        case ATA_CMD_READ_SECTORS_EXT:
        case ATA_CMD_READ_MULTIPLE:
        case ATA_CMD_READ_MULTIPLE_EXT:
            err_flag[6] = ERR_CODE_UNCORRECTABLE;
            err_flag[5] = ERR_CODE_MEDIA_CHANGED;
            err_flag[4] = ERR_CODE_ID_NOT_FOUND;
            err_flag[3] = ERR_CODE_MEDIA_CHANGE_REQUEST;
            err_flag[2] = ERR_CODE_ABORTED;
            err_flag[1] = ERR_CODE_NO_MEDIA;
            err_flag[0] = ERR_CODE_ADDR_MARK_NOT_FOUND;
            lba_print = 1;
            break;

        case ATA_CMD_READ_LONG_RETRY:
        case ATA_CMD_READ_LONG:
            err_flag[4] = ERR_CODE_ID_NOT_FOUND;
            err_flag[2] = ERR_CODE_ABORTED;
            err_flag[0] = ERR_CODE_ADDR_MARK_NOT_FOUND;
            lba_print = 1;
            break;

        case ATA_CMD_READ_STREAM_DMA:
        case ATA_CMD_READ_STREAM_PIO:
            if (input->commandReg == 0x2a) {
                err_flag[7] = ERR_CODE_INTERFACE_CRC_ERROR;
            }

            err_flag[6] = ERR_CODE_UNCORRECTABLE;
            err_flag[5] = ERR_CODE_MEDIA_CHANGED;
            err_flag[4] = ERR_CODE_ID_NOT_FOUND;
            err_flag[3] = ERR_CODE_MEDIA_CHANGE_REQUEST;
            err_flag[2] = ERR_CODE_ABORTED;
            err_flag[1] = ERR_CODE_NO_MEDIA;
            err_flag[0] = ERR_CODE_CMD_COMPLETION_TIMEOUT;
            lba_print = 1;
            sector_print = input->sectorCount;
            break;

        case ATA_CMD_WRITE_STREAM_DMA:
        case ATA_CMD_WRITE_STREAM_PIO:
            if (input->commandReg == 0x3A) {
                err_flag[7] = ERR_CODE_INTERFACE_CRC_ERROR;
            }

            err_flag[6] = ERR_CODE_WRITE_PROTECTED;
            err_flag[5] = ERR_CODE_MEDIA_CHANGED;
            err_flag[4] = ERR_CODE_ID_NOT_FOUND;
            err_flag[3] = ERR_CODE_MEDIA_CHANGE_REQUEST;
            err_flag[2] = ERR_CODE_ABORTED;
            err_flag[1] = ERR_CODE_NO_MEDIA;
            err_flag[0] = ERR_CODE_CMD_COMPLETION_TIMEOUT;
            lba_print = 1;
            sector_print = input->sectorCount;
            break;

        case ATA_CMD_READ_DMA_EXT:
        case ATA_CMD_READ_DMA_QUEUED_EXT:
        case ATA_CMD_READ_DMA_QUEUED:
        case ATA_CMD_READ_DMA:
        case ATA_CMD_READ_DMA_RETRY:
        case ATA_CMD_READ_FPDMA_QUEUED:
            err_flag[7] = ERR_CODE_INTERFACE_CRC_ERROR;
            err_flag[6] = ERR_CODE_UNCORRECTABLE;
            err_flag[5] = ERR_CODE_MEDIA_CHANGED;
            err_flag[4] = ERR_CODE_ID_NOT_FOUND;
            err_flag[3] = ERR_CODE_MEDIA_CHANGE_REQUEST;
            err_flag[2] = ERR_CODE_ABORTED;
            err_flag[1] = ERR_CODE_NO_MEDIA;
            err_flag[0] = ERR_CODE_ADDR_MARK_NOT_FOUND;
            lba_print = 1;
            if (input->commandReg == 0x25 || input->commandReg == 0xC8) {
                sector_print = input->sectorCount;
            }

            break;

        case ATA_CMD_WRITE_SECTORS:
        case ATA_CMD_WRITE_SECTORS_NEW:
        case ATA_CMD_WRITE_SECTORS_EXT:
        case ATA_CMD_WRITE_MULTIPLE:
        case ATA_CMD_WRITE_MULTIPLE_EXT:
        case ATA_CMD_WRITE_MULTIPLE_FUA_EXT:
            err_flag[6] = ERR_CODE_WRITE_PROTECTED;
            err_flag[5] = ERR_CODE_MEDIA_CHANGED;
            err_flag[4] = ERR_CODE_ID_NOT_FOUND;
            err_flag[3] = ERR_CODE_MEDIA_CHANGE_REQUEST;
            err_flag[2] = ERR_CODE_ABORTED;
            err_flag[1] = ERR_CODE_NO_MEDIA;
            lba_print = 1;
            break;

        case ATA_CMD_WRITE_LONG_RETRY:
        case ATA_CMD_WRITE_LONG:
            err_flag[4] = ERR_CODE_ID_NOT_FOUND;
            err_flag[2] = ERR_CODE_ABORTED;
            lba_print = 1;
            break;

        case ATA_CMD_WRITE_VERIFY:
            err_flag[6] = ERR_CODE_UNCORRECTABLE;
            err_flag[4] = ERR_CODE_ID_NOT_FOUND;
            err_flag[2] = ERR_CODE_ABORTED;
            err_flag[0] = ERR_CODE_ADDR_MARK_NOT_FOUND;
            lba_print = 1;
            break;

        case ATA_CMD_READ_VERIFY_SECTORS:
        case ATA_CMD_READ_VERIFY_SECTORS_NEW:
        case ATA_CMD_READ_VERIFY_SECTORS_EXT:
            err_flag[6] = ERR_CODE_UNCORRECTABLE;
            err_flag[5] = ERR_CODE_MEDIA_CHANGED;
            err_flag[4] = ERR_CODE_ID_NOT_FOUND;
            err_flag[3] = ERR_CODE_MEDIA_CHANGE_REQUEST;
            err_flag[2] = ERR_CODE_ABORTED;
            err_flag[1] = ERR_CODE_NO_MEDIA;
            err_flag[0] = ERR_CODE_ADDR_MARK_NOT_FOUND;
            lba_print = 1;
            break;

        case ATA_CMD_PACKET:
            err_flag[7] = "Sense key (bit 3)";
            err_flag[6] = "Sense key (bit 2)";
            err_flag[5] = "Sense key (bit 1)";
            err_flag[4] = "Sense key (bit 0)";
            err_flag[2] = ERR_CODE_ABORTED;
            err_flag[1] = ERR_CODE_END_OF_MEDIA;
            err_flag[0] = ERR_CODE_ILI;
            break;

        case ATA_CMD_IDENTIFY_PACKET_DEVICE:
        case ATA_CMD_SET_FEATURES:
        case ATA_CMD_NOP:
        case ATA_CMD_SET_MULTIPLE_MODE:
            err_flag[2] = ERR_CODE_ABORTED;
            break;

        case ATA_CMD_READ_LOG_EXT:
            err_flag[6] = ERR_CODE_UNCORRECTABLE;
            err_flag[4] = ERR_CODE_ID_NOT_FOUND;
            err_flag[2] = ERR_CODE_ABORTED;
            err_flag[0] = ERR_CODE_OBSOLETE;
            break;

        case ATA_CMD_WRITE_LOG_EXT:
            err_flag[4] = ERR_CODE_ID_NOT_FOUND;
            err_flag[2] = ERR_CODE_ABORTED;
            err_flag[0] = ERR_CODE_OBSOLETE;
            break;

        case ATA_CMD_SMART:
            switch (input->featuresReg) {
                case ATA_CMD_SMART_READ_DATA:
                case ATA_CMD_READ_ATTRIBUTE_THRESHOLDS:
                case ATA_CMD_SMART_READ_LOG:
                    err_flag[6] = ERR_CODE_UNCORRECTABLE;
                    err_flag[4] = ERR_CODE_ID_NOT_FOUND;
                    err_flag[2] = ERR_CODE_ABORTED;
                    err_flag[0] = ERR_CODE_OBSOLETE;
                    break;

                case ATA_CMD_SMART_WRITE_LOG:
                    err_flag[4] = ERR_CODE_ID_NOT_FOUND;
                    err_flag[2] = ERR_CODE_ABORTED;
                    err_flag[0] = ERR_CODE_OBSOLETE;
                    break;

                case ATA_CMD_SMART_ENABLE_DISABLE_AUTOSAVE:
                case ATA_CMD_SMART_SAVE_ATTRIBUTE_VALUES:
                case ATA_CMD_SMART_ENABLE_OPERATIONS:
                case ATA_CMD_SMART_DISABLE_OPERATIONS:
                case ATA_CMD_SMART_RETURN_STATUS:
                case ATA_CMD_ENABLE_DISABLE_AUTO_OFFLINE:
                    err_flag[2] = ERR_CODE_ABORTED;
                    break;

                case ATA_CMD_SMART_EXECUTE_OFFLINE_IMMEDIATE:
                    err_flag[4] = ERR_CODE_ID_NOT_FOUND;
                    err_flag[2] = ERR_CODE_ABORTED;
                    break;

                default:
                    return;
            }

            break;

        case ATA_CMD_DEVICE_CONFIGURATION:
            switch (input->featuresReg) {
                case ATA_CMD_DEVICE_CONFIGURATION_RESTORE:
                    err_flag[2] = ERR_CODE_ABORTED;
                    break;

                default:
                    return;
            }

            break;

        case ATA_CMD_WRITE_DMA:
        case ATA_CMD_WRITE_DMA_NEW:
        case ATA_CMD_WRITE_DMA_EXT:
        case ATA_CMD_WRITE_DMA_FUA_EXT:
        case ATA_CMD_WRITE_DMA_QUEUED:
        case ATA_CMD_WRITE_DMA_QUEUED_EXT:
        case ATA_CMD_WRITE_DMA_QUEUED_FUA_EXT:
        case ATA_CMD_WRITE_FPDMA_QUEUED:
            err_flag[7] = ERR_CODE_INTERFACE_CRC_ERROR;
            err_flag[6] = ERR_CODE_WRITE_PROTECTED;
            err_flag[5] = ERR_CODE_MEDIA_CHANGED;
            err_flag[4] = ERR_CODE_ID_NOT_FOUND;
            err_flag[3] = ERR_CODE_MEDIA_CHANGE_REQUEST;
            err_flag[2] = ERR_CODE_ABORTED;
            err_flag[1] = ERR_CODE_NO_MEDIA;
            err_flag[0] = ERR_CODE_ADDR_MARK_NOT_FOUND;
            lba_print = 1;
            if (input->commandReg == 0x35) {
                sector_print = input->sectorCount;
            }

            break;

        case ATA_CMD_READ_BUFFER:
        case ATA_CMD_WRITE_BUFFER:
            err_flag[2] = ERR_CODE_ABORTED;
            break;

        default:
            return;
    }

    /* Device Fault and Error 进行处理 */
    if (input->status & (1 << 5)) {
        (void)strncpy_s(desc, desc_len, "Device Fault", strlen("Device Fault"));

        if (input->status & 1) {
            safe_fun_ret = strncat_s(desc, desc_len, "; ", strlen("; "));
            if (safe_fun_ret != EOK) {
                debug_log(DLOG_ERROR, "%s: strncat_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
            }
        }
    }

    if (input->status & 1) {
        num = 0;
        safe_fun_ret = strncat_s(desc, desc_len, "Error: ", strlen("Error: "));
        if (safe_fun_ret != EOK) {
            debug_log(DLOG_ERROR, "%s: strncat_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
        }

        for (i = (ERR_FLAG_LEN - 1); i >= 0; i--) {
            if ((input->errorRegister & (1 << (guint32)i)) && (err_flag[i])) {
                if (num > 0) {
                    safe_fun_ret = strncat_s(desc, desc_len, ", ", strlen(", "));
                    if (safe_fun_ret != EOK) {
                        debug_log(DLOG_ERROR, "%s: strncat_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
                    }

                    safe_fun_ret = strncat_s(tmp_buf, ATA_LOG_STRING_LENGTH, ",", strlen(","));
                    if (safe_fun_ret != EOK) {
                        debug_log(DLOG_ERROR, "%s: strncat_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
                    }
                }

                num++;
                safe_fun_ret = strncat_s(desc, desc_len, err_flag[i], strlen(err_flag[i]));
                if (safe_fun_ret != EOK) {
                    debug_log(DLOG_ERROR, "%s: strncat_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
                }
                safe_fun_ret = strncat_s(tmp_buf, ATA_LOG_STRING_LENGTH, err_flag[i], strlen(err_flag[i]));
                if (safe_fun_ret != EOK) {
                    debug_log(DLOG_ERROR, "%s: strncat_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
                }
            }
        }

        if (strlen(tmp_buf) != 0) {
            Json *str_obj = NULL;
            JsonStringCreate(tmp_buf, &str_obj);
            JsonObjectItemSet(out_put_jso, "error_type", str_obj);
        }
    }

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

    if (lba_print) {
        if (sector_print) {
            str_len = strlen(desc);
            (void)snprintf_s(desc + str_len, desc_len - str_len, desc_len - str_len - 1, " %d sectors", sector_print);
        }

        if (error_log_error) {
            err_lba = 0xf & error_log_error->driveHead;
            err_lba <<= 8;
            err_lba |= error_log_error->cylinderHigh;
            err_lba <<= 8;
            err_lba |= error_log_error->cylinderLow;
            err_lba <<= 8;
            err_lba |= error_log_error->sectorNumber;

            str_len = strlen(desc);
            (void)snprintf_s(desc + str_len, desc_len - str_len, desc_len - str_len - 1, " at LBA = 0x%08x = %u",
                err_lba, err_lba);
            (void)snprintf_s(tmp_buf, ATA_LOG_STRING_LENGTH, ATA_LOG_STRING_LENGTH - 1, "%u", err_lba);
        } else if (extent_error_log_error) {
            ext_err_lba = extent_error_log_error->lbaHighRegHi;
            ext_err_lba <<= 8;
            ext_err_lba |= extent_error_log_error->lbaMidRegHi;
            ext_err_lba <<= 8;
            ext_err_lba |= extent_error_log_error->lbaLowRegHi;
            ext_err_lba |= extent_error_log_error->deviceReg & 0xf;
            ext_err_lba <<= 8;
            ext_err_lba |= extent_error_log_error->lbaHighReg;
            ext_err_lba <<= 8;
            ext_err_lba |= extent_error_log_error->lbaMidReg;
            ext_err_lba <<= 8;
            ext_err_lba |= extent_error_log_error->lbaLowReg;

            str_len = strlen(desc);
            (void)snprintf_s(desc + str_len, desc_len - str_len, desc_len - str_len - 1,
                " at LBA = 0x%08" G_GUINT64_HEX_FORMAT " = %" G_GUINT64_FORMAT, ext_err_lba, ext_err_lba);
            (void)snprintf_s(tmp_buf, ATA_LOG_STRING_LENGTH, ATA_LOG_STRING_LENGTH - 1, "%" G_GUINT64_FORMAT,
                ext_err_lba);
        }
        Json *str_obj = NULL;
        JsonStringCreate(tmp_buf, &str_obj);
        JsonObjectItemSet(out_put_jso, "lba", str_obj);
    }

    return;
}


/*
 * Description: 获取error log的state的描述
 * History: 1.2018年3月30日
 * 新生成函数
 */
static const gchar *pd_log_get_sata_error_state_desc(guint32 state)
{
    state = state & 0x0f;

    switch (state) {
        case 0x0:
            return "in an unknown state";

        case 0x1:
            return "sleeping";

        case 0x2:
            return "in standby mode";

        case 0x3:
            return "active or idle";

        case 0x4:
            return "doing SMART offline or self-test";

        default:
            return (state < 0xb ? "in a reserved state" : "in a vendor specific state");
    }
}

/*
 * Description: 校验数据有效性(至少有一个非0)
 * History: 1.2018年3月30日                AR.SR.SFEA02130924.009.001
 * 新生成函数
 */
static gint32 pd_log_check_data(const void *data, gint32 len)
{
    gint32 i;
    if (NULL == data || 0 == len) {
        return FALSE;
    }

    for (i = 0; i < len; i++) {
        if (((const guchar *)data)[i]) {
            return TRUE;
        }
    }

    return FALSE;
}

/*
 * Description: 获取命令描述
 * History: 1.2018年4月13日
 * 新生成函数
 */
static const gchar *pd_log_get_ata_command(guint8 code, guint8 reg)
{
    const gchar *desc = NULL;
    guint32 i = 0;

    switch (code) {
        case ATA_CMD_NOP:
            desc = "NOP [Reserved subcommand] [OBS-ACS-2]";

            for (i = 0; i < GET_ARRAY_ITEMS(g_cmd_desc_nop); i++) {
                if (reg == g_cmd_desc_nop[i].reg) {
                    desc = g_cmd_desc_nop[i].desc;
                    break;
                }
            }

            break;

        case ATA_CMD_DOWNLOAD_MICROCODE:
            desc = "DOWNLOAD MICROCODE [Reserved subcommand]";

            for (i = 0; i < GET_ARRAY_ITEMS(g_cmd_desc_download_mc); i++) {
                if (reg == g_cmd_desc_download_mc[i].reg) {
                    desc = g_cmd_desc_download_mc[i].desc;
                    break;
                }
            }

            break;

        case ATA_CMD_SMART:
            if (reg >= 0xE0) {
                desc = "SMART [Vendor specific subcommand]";
            } else {
                desc = "SMART [Reserved subcommand]";
            }

            for (i = 0; i < GET_ARRAY_ITEMS(g_cmd_desc_smart); i++) {
                if (reg == g_cmd_desc_smart[i].reg) {
                    desc = g_cmd_desc_smart[i].desc;
                    break;
                }
            }

            break;

        case ATA_CMD_DEVICE_CONFIGURATION:
            desc = "DEVICE CONFIGURATION [Reserved subcommand] [OBS-ACS-3]";

            for (i = 0; i < GET_ARRAY_ITEMS(g_cmd_desc_device_cfg); i++) {
                if (reg == g_cmd_desc_device_cfg[i].reg) {
                    desc = g_cmd_desc_device_cfg[i].desc;
                    break;
                }
            }

            break;

        case ATA_CMD_SET_FEATURES:
            if (reg >= 0xF0) {
                desc = "SET FEATURES [Reserved for CFA]";
            } else {
                desc = "SET FEATURES [Reserved subcommand]";
            }

            for (i = 0; i < GET_ARRAY_ITEMS(g_cmd_desc_set_features); i++) {
                if (reg == g_cmd_desc_set_features[i].reg) {
                    desc = g_cmd_desc_set_features[i].desc;
                    break;
                }
            }

            break;

        case ATA_CMD_SET_MAX:
            desc = "SET MAX [Reserved subcommand] [OBS-ACS-3]";

            for (i = 0; i < GET_ARRAY_ITEMS(g_cmd_desc_set_max); i++) {
                if (reg == g_cmd_desc_set_max[i].reg) {
                    desc = g_cmd_desc_set_max[i].desc;
                    break;
                }
            }

            break;

        default:
            desc = g_cmd_table[code];
    }

    return desc;
}

/*
 * Description: 处理sata盘的error log数据
 * History: 1.2018年3月28日
 * 新生成函数
 */
void pd_log_handle_sata_error(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *pd_log_jso)
{
    gchar  err_desc[ATA_LOG_STRING_LENGTH] = {0};
    gchar  tmp_str[ATA_LOG_STRING_LENGTH] = {0};

    ATA_SMART_ERRLOG_INPUT_S input_desc;
    ATA_SMART_ERRLOG_S *err_log = NULL;
    const ATA_SMART_ERRLOG_ENTRY_S *entry = NULL;
    const ATA_SMART_ERRLOG_ERR_S *err = NULL;
    const ATA_SMART_ERRLOG_CMD_S *cmd = NULL;
    gint32 i, j, k, day;
    Json *err_log_array = NULL;

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

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

    err_log = (ATA_SMART_ERRLOG_S *)pd_log->SATADevice.error.data;
    pd_log_fprintf(file,
        "--------------------------------------------------------------------------------------------------\n");

    pd_log_fprintf(file, "SMART Error Log Version: %d\n", (gint32)err_log->revNumber);

    if (0 == err_log->errorLogPointer) {
        pd_log_fprintf(file, "No Errors Logged\n\n");
        return;
    }

    if ((err_log->errorLogPointer > ATA_LOG_ERR_ERR_NUM) || (err_log->errorLogPointer > err_log->errorCount)) {
        pd_log_fprintf(file,
            "Invalid Error Log index = 0x%02x (T13/1410D revision 3b Section 8.51.6.8.2.2 gives valid range from 0 to "
            "5)\n\n",
            (gint32)err_log->errorLogPointer);
        pd_log_fprintf(file, "ATA Error Count: %d\n", (gint32)err_log->errorCount);
        return;
    }

    if ((err_log->errorCount - err_log->errorLogPointer) % ATA_LOG_ERR_ERR_NUM) {
        pd_log_fprintf(file, "Warning: ATA error count %d inconsistent with error entry pointer %d\n\n",
            err_log->errorCount, err_log->errorLogPointer);
    }

    if (err_log->errorCount <= ATA_LOG_ERR_ERR_NUM) {
        pd_log_fprintf(file, "ATA Error Count: %d\n", (gint32)err_log->errorCount);
    } else {
        pd_log_fprintf(file, "ATA Error Count: %d (device log contains only the most recent five errors)\n",
            (gint32)err_log->errorCount);
    }

    (void)snprintf_s(tmp_str, ATA_LOG_STRING_LENGTH, ATA_LOG_STRING_LENGTH - 1, "%hu", err_log->errorCount);
    Json *str_obj = NULL;
    JsonStringCreate(tmp_str, &str_obj);
    (void)JsonObjectItemSet(pd_log_jso, "error_log_count", str_obj);
    if (JsonArrayCreate(&err_log_array) != JSON_OK) {
        return;
    }
    JsonObjectItemSet(pd_log_jso, "error_log", err_log_array);

    pd_log_fprintf(file, " +---------+---------+--------------+-------------+-------------+--------------+");
    pd_log_fprintf(file, "------------+---------------+----------------+-----------------+\n");
    pd_log_fprintf(file, " | Command | Feature | SectorNumber | SectorCount | CylinderLow | CylinderHigh |");
    pd_log_fprintf(file, " DeviceHead | DeviceCommand | Error Register | Status Register |\n");
    pd_log_fprintf(file, " +---------+---------+--------------+-------------+-------------+--------------+");
    pd_log_fprintf(file, "------------+---------------+----------------+-----------------+\n");

    // 倒序遍历每个error
    for (k = (ATA_LOG_ERR_ERR_NUM - 1); k >= 0; k--) {
        i = (err_log->errorLogPointer + k) % ATA_LOG_ERR_ERR_NUM;
        entry = err_log->errorlog + i;
        if (NULL == entry) {
            continue;
        }

        err = &(entry->error);

        // 过滤无效数据
        if (FALSE == pd_log_check_data(entry, sizeof(ATA_SMART_ERRLOG_ENTRY_S))) {
            continue;
        }
        Json *err_log_node = NULL;
        if (JsonObjectCreate(&err_log_node) != JSON_OK) {
            continue;
        }

        day = (gint32)err->timestamp / 24;

        pd_log_fprintf(file, "Error %d occurred at disk power-on lifetime: %d hours (%d days + %d hours)\n",
            (gint32)(err_log->errorCount + k - ATA_LOG_ERR_ERR_NUM + 1), (gint32)err->timestamp, day,
            (gint32)(err->timestamp - 24 * day));
        (void)memset_s(tmp_str, ATA_LOG_STRING_LENGTH, 0, ATA_LOG_STRING_LENGTH);
        (void)snprintf_s(tmp_str, ATA_LOG_STRING_LENGTH, ATA_LOG_STRING_LENGTH - 1, "%hu", err->timestamp);
        Json *str_obj = NULL;
        JsonStringCreate(tmp_str, &str_obj);
        JsonObjectItemSet(err_log_node, "pot", str_obj);

        pd_log_fprintf(file,
            "  When the command that caused the error occurred, the device was %s.\n\n  After command completion "
            "occurred, registers were:\n"
            "  ER ST SC SN CL CH DH\n  -- -- -- -- -- -- --\n  %02x %02x %02x %02x %02x %02x %02x",
            pd_log_get_sata_error_state_desc(err->state), (gint32)err->errorRegister, (gint32)err->status,
            (gint32)err->sectorCount, (gint32)err->sectorNumber, (gint32)err->cylinderLow, (gint32)err->cylinderHigh,
            (gint32)err->driveHead);

        (void)memset_s(&input_desc, sizeof(ATA_SMART_ERRLOG_INPUT_S), 0, sizeof(ATA_SMART_ERRLOG_INPUT_S));
        input_desc.commandReg = entry->commands[ATA_LOG_ERR_CMD_NUM - 1].commandReg;
        input_desc.featuresReg = entry->commands[ATA_LOG_ERR_CMD_NUM - 1].featuresReg;
        input_desc.status = entry->error.status;
        input_desc.errorRegister = entry->error.errorRegister;
        input_desc.sectorCount = (guint16)entry->error.sectorCount;

        pd_log_err_desc(&input_desc, &entry->error, (const ATA_SMART_EXTERRLOG_ERROR_S *)NULL, err_desc,
            sizeof(err_desc), err_log_node);

        if (0 != strlen(err_desc)) {
            pd_log_fprintf(file, "  %s", err_desc);
        }
        gchar *json_str = JsonPrint(err_log_node);
        if (0 != g_strcmp0(json_str, "{ }")) {
            guint32 array_size;
            JsonArraySizeGet(err_log_array, &array_size);
            JsonArrayItemInsert(err_log_array, array_size, err_log_node);
        } else {
            JsonObjectRelease(err_log_node);
        }
        JsonStringValueFree(json_str);
        pd_log_fprintf(file, "-------------------------------------------------------------------------------------\n");
        pd_log_fprintf(file, " +---------+---------+--------------+-------------+-------------+--------------+");
        pd_log_fprintf(file, "------------+---------------+----------------+-----------------+-----------------+-------"
            "---------------+\n");
        pd_log_fprintf(file, " | Command | Feature | SectorNumber | SectorCount | CylinderLow | CylinderHigh |");
        pd_log_fprintf(file, " DeviceHead | DeviceCommand | Error Register | Status Register | Powered_Up_Time | "
            "Command/Feature_Name |\n");
        pd_log_fprintf(file, " +---------+---------+--------------+-------------+-------------+--------------+");
        pd_log_fprintf(file, "------------+---------------+----------------+-----------------+-----------------+-------"
            "---------------+\n");
        for (j = (ATA_LOG_ERR_CMD_NUM - 1); j >= 0; j--) {
            cmd = entry->commands + j;
            if (FALSE == pd_log_check_data(cmd, sizeof(ATA_SMART_ERRLOG_CMD_S))) {
                continue;
            }

            memset_s(tmp_str, ATA_LOG_STRING_LENGTH, 0, ATA_LOG_STRING_LENGTH);
            pd_log_format_time(cmd->timestamp, tmp_str, sizeof(tmp_str));
            pd_log_fprintf(file, "| 0X%02x    | 0X%02x    | 0X%02x         ", (int)cmd->commandReg,
                (int)cmd->featuresReg, (int)cmd->sectorNumber);
            pd_log_fprintf(file, "| 0X%02x        | 0X%02x        ", (int)cmd->sectorCount, (int)cmd->cylinderLow);
            pd_log_fprintf(file, "| 0X%02x         | 0X%02x       ", (int)cmd->cylinderHigh, (int)cmd->driveHead);
            pd_log_fprintf(file, "| 0X%02x          | 0X%02x           |", (int)cmd->deviceControlReg,
                (int)err->errorRegister);
            pd_log_fprintf(file, "| 0X%02x            |%-16s", (int)err->status, tmp_str);
            pd_log_fprintf(file, "| %-21s", pd_log_get_ata_command(cmd->commandReg, cmd->featuresReg));
        }

        pd_log_fprintf(file, " +---------+---------+--------------+-------------+-------------+--------------+");
        pd_log_fprintf(file, "------------+---------------+----------------+-----------------+-----------------+-------"
            "---------------+\n");
    }

    return;
}

/*
 * Description: 匹配extended error log的lba特殊处理型号
 * History: 1.2018年4月25日
 * 新生成函数
 */
static gboolean pd_log_match_xerror_lba(const gchar *model)
{
    GRegex *regex = NULL;
    GMatchInfo *match_info = NULL;
    gboolean b_ret = FALSE;

    if (NULL == model) {
        return b_ret;
    }

    regex = g_regex_new(XERROR_LBA_REGULAR, (GRegexCompileFlags)0, (GRegexMatchFlags)0, NULL);

    b_ret = g_regex_match(regex, model, (GRegexMatchFlags)0, &match_info);
    if (FALSE == b_ret || 0 >= g_match_info_get_match_count(match_info)) {
        debug_log(DLOG_ERROR, "[%s]: Model[%s] matching failed.", __FUNCTION__, model);
        g_match_info_free(match_info);
        g_regex_unref(regex);
        return FALSE;
    }

    g_match_info_free(match_info);
    g_regex_unref(regex);
    return TRUE;
}

/*
 * Description: extended error log的lba特殊处理
 * History: 1.2018年4月25日
 * 新生成函数
 */
static void pd_log_fix_ext_err_lba(ATA_SMART_EXTERRLOG_ERROR_S *ext_err_err, ATA_SMART_EXTERRLOG_CMD_S *ext_err_cmd)
{
    ATA_SMART_EXTERRLOG_ERROR_S error_org;
    ATA_SMART_EXTERRLOG_CMD_S cmd_org;

    if (ext_err_err) {
        (void)memcpy_s(&error_org, sizeof(ATA_SMART_EXTERRLOG_ERROR_S), ext_err_err,
            sizeof(ATA_SMART_EXTERRLOG_ERROR_S));
        ext_err_err->lbaMidRegHi = error_org.lbaHighReg;
        ext_err_err->lbaLowRegHi = error_org.lbaMidRegHi;
        ext_err_err->lbaHighReg = error_org.lbaMidReg;
        ext_err_err->lbaMidReg = error_org.lbaLowRegHi;
    } else if (ext_err_cmd) {
        (void)memcpy_s(&cmd_org, sizeof(ATA_SMART_EXTERRLOG_CMD_S), ext_err_cmd, sizeof(ATA_SMART_EXTERRLOG_CMD_S));
        ext_err_cmd->lbaMidRegHi = cmd_org.lbaHighReg;
        ext_err_cmd->lbaLowRegHi = cmd_org.lbaMidRegHi;
        ext_err_cmd->lbaHighReg = cmd_org.lbaMidReg;
        ext_err_cmd->lbaMidReg = cmd_org.lbaLowRegHi;
    }
}

/*
 * Description: 处理sata盘的extent error log数据
 * History: 1.2018年4月13日
 * 新生成函数
 */
void pd_log_handle_sata_ext_error(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *pd_log_jso)
{
    gchar  st_er_desc[ATA_LOG_STRING_LENGTH] = {0};
    gchar  tmp_str[ATA_LOG_STRING_LENGTH] = {0};

    ATA_SMART_ERRLOG_INPUT_S input_desc;
    ATA_SMART_EXTERRLOG_S *ext_err_log = NULL;
    ATA_SMART_EXTERRLOG_ENTRY_S *entry = NULL;
    ATA_SMART_EXTERRLOG_ERROR_S *err = NULL;
    ATA_SMART_EXTERRLOG_CMD_S *cmd = NULL;

    guint32 max_err_num, err_index, err_count;
    gint32 i, j, err_no;
    guint32 k;
    gboolean need_fix_bugs;
    SML_PD_FAULT_ANALYSIS *result = (SML_PD_FAULT_ANALYSIS *)out_put;
    const gchar* error_type[] = {ERR_CODE_ADDR_MARK_NOT_FOUND, ERR_CODE_UNCORRECTABLE, ERR_CODE_WRITE_PROTECTED};
    const guint32 threshold = 100;
    gchar *error_type_tmp = NULL;
    Json *extend_log_array = NULL;
    gint32 i_ret;

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

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

    ext_err_log = (ATA_SMART_EXTERRLOG_S *)pd_log->SATADevice.extent_error.data;
    pd_log_fprintf(file,
        "--------------------------------------------------------------------------------------------------\n");

    debug_log(DLOG_INFO, "Handle physical drive %s log Extended Comprehensive Error Log, sector number = %d.",
        pd_log->pd_device_name, pd_log->SATADevice.extent_error.max_raw_data_size.sectors);

    pd_log_fprintf(file, "SMART Extended Comprehensive Error Log Version: %u (%u sectors)\n",
        (gint32)ext_err_log->version, pd_log->SATADevice.extent_error.max_raw_data_size.sectors);

    if (0 == ext_err_log->deviceErrorCount) {
        pd_log_fprintf(file, "No Errors Logged\n\n");
        return;
    }

    need_fix_bugs = pd_log_match_xerror_lba(pd_log->pd_model);
    /* 一个sector最多有4个error log data，最后一个sector可能不满4个，
            (max_sector - 1) * 4  + 最后一个sector所包含的error */
    max_err_num = (pd_log->SATADevice.extent_error.max_raw_data_size.sectors - 1) * ATA_LOG_EXT_ERR_NUM +
        ((ext_err_log->errorLogIndex - 1) % ATA_LOG_EXT_ERR_NUM) + 1;
    err_index = ext_err_log->errorLogIndex;

    // 原始数据index 从1开始的
    if (0 != err_index) {
        err_index--;
    }

    err_count = ext_err_log->deviceErrorCount;

    // 诊断故障
    if (NULL != result && err_count > threshold) {
        result->o_fault_bitmap.pd_smart_log_error = 1;
        i_ret = snprintf_s(result->io_buf, sizeof(result->io_buf), sizeof(result->io_buf) - 1,
            "error count: %u, threshold: %u", err_count, threshold);
        if (i_ret <= 0) {
            debug_log(DLOG_ERROR, "%s: snprintf_s fail, ret = %d\n", __FUNCTION__, i_ret);
        }
        debug_log(DLOG_INFO, "Extent error count(%d) error of %s.", err_count, pd_log->pd_device_name);
        return;
    }

    if (err_count <= max_err_num) {
        pd_log_fprintf(file, "Device Error Count: %u\n", ext_err_log->deviceErrorCount);
    } else {
        err_count = max_err_num;
        pd_log_fprintf(file, "Device Error Count: %u (device log contains only the most recent %u errors)\n",
            ext_err_log->deviceErrorCount, err_count);
    }

    pd_log_fprintf(file, "Error_Count: %u \n", ext_err_log->deviceErrorCount);

    if (JsonArrayCreate(&extend_log_array) != JSON_OK) {
        return;
    }

    // 倒序遍历error
    for (i = (gint32)(err_count - 1), err_no = ext_err_log->deviceErrorCount; i >= 0; i--, err_no--, err_index--) {
        entry = (ext_err_log + i / ATA_LOG_EXT_ERR_NUM)->errorLogs + (err_index % ATA_LOG_EXT_ERR_NUM);

        // 跳过无效的数据
        if (FALSE == pd_log_check_data(entry, sizeof(ATA_SMART_EXTERRLOG_ENTRY_S))) {
            pd_log_fprintf(file, "Error %u [%u] log entry is empty\n", err_no, err_index);
            continue;
        }

        err = &entry->error;
        if (TRUE == need_fix_bugs) {
            pd_log_fix_ext_err_lba(err, (ATA_SMART_EXTERRLOG_CMD_S *)NULL);
        }

        pd_log_fprintf(file, "Error %u [%u] occurred at disk power-on lifetime: %u hours (%u days + %u hours)\n",
            err_no, err_index, err->timestamp, err->timestamp / 24, err->timestamp % 24);
        Json *extend_log_node = NULL;
        if (JsonObjectCreate(&extend_log_node) != JSON_OK) {
            continue;
        }
        memset_s(tmp_str, ATA_LOG_STRING_LENGTH, 0, ATA_LOG_STRING_LENGTH);
        (void)snprintf_s(tmp_str, ATA_LOG_STRING_LENGTH, ATA_LOG_STRING_LENGTH - 1, "%u", err->timestamp);
        Json *str_obj = NULL;
        JsonStringCreate(tmp_str, &str_obj);
        (void)JsonObjectItemSet(extend_log_node, "pot", str_obj);

        pd_log_fprintf(file,
            " +---------------+----------------+---------------+--------------+----------+---------+---------+"
            "----------------+-----------------------+\n"
            " | ErrorRegister | StatusRegister | CountRegister |     LBA_Register     | LBA_High | LBA_Mid | LBA_Low |"
            " DeviceRegister | DeviceControlRegister |\n"
            " +---------------+----------------+---------------+--------------+----------+---------+---------+"
            "----------------+-----------------------+\n"
            " 0X%02x          | 0X%02x         | 0X%02x 0X%02x | 0X%02x 0X%02x 0X%02x | 0X%02x   | 0X%02x  | 0X%02x  |"
            " 0X%02x         | 0X%02x                |\n"
            " +---------------+----------------+---------------+--------------+----------+---------+---------+"
            "----------------+-----------------------+\n",
            pd_log_get_sata_error_state_desc(err->state), err->errorReg, err->statusReg, err->countRegHi, err->countReg,
            err->lbaHighRegHi, err->lbaMidRegHi, err->lbaLowRegHi, err->lbaHighReg, err->lbaMidReg, err->lbaLowReg,
            err->deviceReg, err->deviceControlReg);

        (void)memset_s(&input_desc, sizeof(ATA_SMART_ERRLOG_INPUT_S), 0, sizeof(ATA_SMART_ERRLOG_INPUT_S));
        input_desc.commandReg = entry->commands[ATA_LOG_ERR_CMD_NUM - 1].commandReg;
        input_desc.featuresReg = entry->commands[ATA_LOG_ERR_CMD_NUM - 1].featuresReg;
        input_desc.status = entry->error.statusReg;
        input_desc.errorRegister = entry->error.errorReg;
        input_desc.sectorCount = (guint16)entry->error.countRegHi << 8 | entry->error.countReg;

        pd_log_err_desc(&input_desc, (const ATA_SMART_ERRLOG_ERR_S *)NULL, &entry->error, st_er_desc,
            sizeof(st_er_desc), extend_log_node);
        if (0 != strlen(st_er_desc)) {
            pd_log_fprintf(file, "  %s", st_er_desc);
        }
        gchar *json_str = JsonPrint(extend_log_node);
        if (0 != g_strcmp0(json_str, "{ }")) {
            guint32 array_size = 0;
            JsonArraySizeGet(extend_log_array, &array_size);
            JsonArrayItemInsert(extend_log_array, array_size, extend_log_node);
        } else {
            JsonObjectRelease(extend_log_node);
        }
        JsonStringValueFree(json_str);

        // 诊断故障
        /* BEGIN: Added by, 2019/1/17   PN:UADP135084 */
        if (NULL != result && 1 != result->o_fault_bitmap.pd_smart_log_error) {
            for (k = 0; k < GET_ARRAY_ITEMS(error_type); ++k) {
                error_type_tmp = strstr(st_er_desc, error_type[k]);
                if (NULL != error_type_tmp) {
                    result->o_fault_bitmap.pd_smart_log_error = 1;
                    i_ret = snprintf_s(result->io_buf, sizeof(result->io_buf), sizeof(result->io_buf) - 1,
                        "error type is %s", error_type[k]);
                    if (i_ret <= 0) {
                        debug_log(DLOG_ERROR, "%s: snprintf_s fail, ret = %d\n", __FUNCTION__, i_ret);
                    }
                    debug_log(DLOG_INFO, "Extent error status(%s) error of %s.", error_type[k], pd_log->pd_device_name);
                    JsonObjectRelease(extend_log_array);
                    return;
                }
            }
        }
        pd_log_fprintf(file, " +-----------------+------------------+---------------+--------------+"
            " ---------+------- -+---------+----------------+-----------------------+"
            " ----------------+----------------------+\n"
            " | CommandRegister | FeaturesRegister | CountRegister |      LBA_Register     |"
            " LBA_High | LBA_Mid | LBA_Low | DeviceRegister | DeviceControlRegister |"
            " Powered_up_time | Command/Feature_Name |\n"
            " +-----------------+------------------+---------------+--------------+"
            " ---------+------- -+---------+----------------+-----------------------+"
            " ----------------+----------------------+\n");

        for (j = (ATA_LOG_ERR_CMD_NUM - 1); j >= 0; j--) {
            cmd = entry->commands + j;

            // 跳过无效的数据
            if (FALSE == pd_log_check_data(cmd, sizeof(ATA_SMART_EXTERRLOG_CMD_S))) {
                continue;
            }

            if (TRUE == need_fix_bugs) {
                pd_log_fix_ext_err_lba((ATA_SMART_EXTERRLOG_ERROR_S *)NULL, cmd);
            }

            memset_s(tmp_str, ATA_LOG_STRING_LENGTH, 0, ATA_LOG_STRING_LENGTH);
            pd_log_format_time(cmd->timestamp, tmp_str, sizeof(tmp_str));
            pd_log_fprintf(file,
                " | 0X%02x          | 0X%02x 0X%02x    | 0X%02x 0X%02x | 0X%02x 0X%02x 0X%02x  |"
                " 0X%02x   | 0X%02x  | 0X%02x  | 0X%02x        | 0X%02x                 |\n"
                " %-16s | %-21s |",
                cmd->commandReg, cmd->featuresRegHi, cmd->featuresReg, cmd->countRegHi, cmd->countReg,
                cmd->lbaHighRegHi, cmd->lbaMidRegHi, cmd->lbaLowRegHi, cmd->lbaHighReg, cmd->lbaMidReg, cmd->lbaLowReg,
                cmd->deviceReg, cmd->deviceControlReg, tmp_str,
                pd_log_get_ata_command(cmd->commandReg, cmd->featuresReg));
        }
        pd_log_fprintf(file, " +-----------------+------------------+---------------+--------------+"
            " ---------+------- -+---------+----------------+-----------------------+"
            " ----------------+----------------------+\n");
    }

    if (NULL != pd_log_jso) {
        (void)memset_s(tmp_str, ATA_LOG_STRING_LENGTH, 0, ATA_LOG_STRING_LENGTH);
        (void)snprintf_s(tmp_str, ATA_LOG_STRING_LENGTH, ATA_LOG_STRING_LENGTH - 1, "%u", err_count);
        Json *str_obj = NULL;
        JsonStringCreate(tmp_str, &str_obj);
        (void)JsonObjectItemSet(pd_log_jso, "extend_err_log_count", str_obj);
        JsonObjectItemSet(pd_log_jso, "extend_err_log", extend_log_array);
    } else {
        JsonObjectRelease(extend_log_array);
    }

    return;
}

/*
 * Description: 打印处理每个测试项
 * History: 1.2018年4月13日
 * 新生成函数
 */
static gint32 pd_log_handle_sata_self_test_item(guint32 num, guchar type, guchar status, guint16 timestamp,
    guint64 failing_lba, guchar *header_print, FILE *file, Json *out_put_jso)
{
    gint32 retval = 0; // extended self-test not completed
    gchar  test_str[ATA_LOG_STRING_LENGTH] = {0};
    gchar  status_str[ATA_LOG_STRING_LENGTH] = {0};
    gchar  lba_str[ATA_LOG_STRING_LENGTH] = {0};
    guint32 i = 0;
    gchar tmp_str[ATA_LOG_STRING_LENGTH] = {0};

    if (NULL == header_print) {
        return retval;
    }

    if ((0x40 <= type && type <= 0x7e) || 0x90 <= type) {
        (void)snprintf_s(test_str, sizeof(test_str), sizeof(test_str) - 1, "Vendor (0x%02x)", type);
    } else {
        (void)snprintf_s(test_str, sizeof(test_str), sizeof(test_str) - 1, "Reserved (0x%02x)", type);
    }

    for (i = 0; i < GET_ARRAY_ITEMS(g_selftest_desc); i++) {
        if (type == g_selftest_desc[i].reg) {
            (void)strncpy_s(test_str, sizeof(test_str), g_selftest_desc[i].desc, strlen(g_selftest_desc[i].desc));
            break;
        }
    }
    switch (status >> 4) {
        case 0x0:
            (void)strncpy_s(status_str, sizeof(status_str), "Completed without error",
                strlen("Completed without error"));

            if (0x02 == (type & 0x0f)) {
                retval = 1; // extended self-test completed without error
            }

            break;

        case 0x1:
            (void)strncpy_s(status_str, sizeof(status_str), "Aborted by host", strlen("Aborted by host"));
            break;

        case 0x2:
            (void)strncpy_s(status_str, sizeof(status_str), "Interrupted (host reset)",
                strlen("Interrupted (host reset)"));
            break;

        case 0x3:
            (void)strncpy_s(status_str, sizeof(status_str), "Fatal or unknown error", strlen("Fatal or unknown error"));
            retval = -1;
            break;

        case 0x4:
            (void)strncpy_s(status_str, sizeof(status_str), "Completed: unknown failure",
                strlen("Completed: unknown failure"));
            (void)snprintf_s(tmp_str, ATA_LOG_STRING_LENGTH, ATA_LOG_STRING_LENGTH - 1, "%u", timestamp);
            Json *str_obj = NULL;
            JsonStringCreate(tmp_str, &str_obj);
            (void)JsonObjectItemSet(out_put_jso, "pot", str_obj);
            Json *str_failure_obj = NULL;
            JsonStringCreate(status_str, &str_failure_obj);
            (void)JsonObjectItemSet(out_put_jso, "failure_status", str_failure_obj);
            retval = -1;
            break;

        case 0x5:
            (void)strncpy_s(status_str, sizeof(status_str), "Completed: electrical failure",
                strlen("Completed: electrical failure"));
            (void)snprintf_s(tmp_str, ATA_LOG_STRING_LENGTH, ATA_LOG_STRING_LENGTH - 1, "%u", timestamp);
            Json *str_obj5 = NULL;
            JsonStringCreate(tmp_str, &str_obj5);
            (void)JsonObjectItemSet(out_put_jso, "pot", str_obj5);
            Json *str_failure_obj5 = NULL;
            JsonStringCreate(status_str, &str_failure_obj5);
            (void)JsonObjectItemSet(out_put_jso, "failure_status", str_failure_obj5);
            retval = -1;
            break;

        case 0x6:
            (void)strncpy_s(status_str, sizeof(status_str), "Completed: servo/seek failure",
                strlen("Completed: servo/seek failure"));
            (void)snprintf_s(tmp_str, ATA_LOG_STRING_LENGTH, ATA_LOG_STRING_LENGTH - 1, "%u", timestamp);
            Json *str_obj6 = NULL;
            JsonStringCreate(tmp_str, &str_obj6);
            (void)JsonObjectItemSet(out_put_jso, "pot", str_obj6);
            Json *str_failure_obj6 = NULL;
            JsonStringCreate(status_str, &str_failure_obj6);
            (void)JsonObjectItemSet(out_put_jso, "failure_status", str_failure_obj6);
            retval = -1;
            break;

        case 0x7:
            (void)strncpy_s(status_str, sizeof(status_str), "Completed: read failure",
                strlen("Completed: read failure"));
            (void)snprintf_s(tmp_str, ATA_LOG_STRING_LENGTH, ATA_LOG_STRING_LENGTH - 1, "%u", timestamp);
            Json *str_obj7 = NULL;
            JsonStringCreate(tmp_str, &str_obj7);
            (void)JsonObjectItemSet(out_put_jso, "pot", str_obj7);
            Json *str_failure_obj7 = NULL;
            JsonStringCreate(status_str, &str_failure_obj7);
            (void)JsonObjectItemSet(out_put_jso, "failure_status", str_failure_obj7);
            retval = -1;
            break;

        case 0x8:
            (void)strncpy_s(status_str, sizeof(status_str), "Completed: handling damage??",
                strlen("Completed: handling damage??"));
            retval = -1;
            break;

        case 0xf:
            (void)strncpy_s(status_str, sizeof(status_str), "Self-test routine in progress",
                strlen("Self-test routine in progress"));
            break;

        default:
            (void)snprintf_s(status_str, sizeof(status_str), sizeof(status_str) - 1, "Unknown status (0x%x)",
                status >> 4);
    }

    if (TRUE == *header_print) {
        *header_print = FALSE;
        pd_log_fprintf(file,
            "Num  Test_Description    Status                  Remaining  LifeTime(hours)  LBA_of_first_error\n");
    }

    if (retval < 0 && failing_lba < 0xffffffffffffULL) {
        (void)snprintf_s(lba_str, sizeof(lba_str), sizeof(lba_str) - 1, "%" G_GUINT64_FORMAT, failing_lba);
    } else {
        lba_str[0] = '-';
        lba_str[1] = 0;
    }

    pd_log_fprintf(file, "#%2u  %-19s %-29s %1d0%%  %8u         %s\n", num, test_str, status_str, status & 0x0f,
        timestamp, lba_str);

    return retval;
}

/*
 * Description: 诊断sata盘的self test结果
 * History: 1.2019年1月14日,
 * 新生成函数          PN:UADP135084
 */
static void pd_log_handle_sata_ext_self_test_diagnose(guint8 *find_short_long_dst_flag,
    const ATA_SMART_EXTSELFTESTLOG_DESC_S *desc, gint32 state, PD_SMART_TEST_ANALYSIS *diagnose_result)
{
    if (NULL == find_short_long_dst_flag || NULL == desc || NULL == diagnose_result) {
        return;
    }
    /* Type :  0(Offline),            1(Short offline),      2(Extended offline),
               3(Conveyance offline), 4(Selective offline),  127(Abort offline test),
               129(Short captive),    130(Extended captive), 131(Conveyance captive),
               132(Selective captive)
       Result: 0(Completed without error),       1(Aborted by host),            2(Interrupted (host reset)),
               3(Fatal or unknown error),        4(Completed: unknown failure), 5(Completed: electrical failure),
               6(Completed: servo/seek failure), 7(Completed: read failure),    8(Completed: handling damage??),
               15(Self-test routine in progress)
    */
    guint8 short_long_dst_flag = 0;

    debug_log(DLOG_INFO, "Diagnose SATA drive short dst item : find_short_long_dst_flag = %d, state = %d, type = %d.",
        *find_short_long_dst_flag, state, desc->selfTestType);

    // 确认是short dst或者long dst
    if (1 == desc->selfTestType || 2 == desc->selfTestType) {
        short_long_dst_flag = 1;
    }

    // 未找到short 或 long dst记录
    if (!(*find_short_long_dst_flag)) {
        // 首条short 或long dst记录
        if (short_long_dst_flag) {
            // 故障标记返回
            if (state < 0 && NULL != diagnose_result->result) {
                diagnose_result->result->o_fault_bitmap.pd_short_dst_error = 1;
                debug_log(DLOG_INFO, "SATA drive first self test is error.");
                return;
            }
        }
    // 非首条查找到的short 或 long dst，仅判断long dst的测试结果
    } else if (desc->selfTestType == 2) {
        // 故障标记返回
        if (state < 0 && NULL != diagnose_result->result) {
            diagnose_result->result->o_fault_bitmap.pd_short_dst_error = 1;
            debug_log(DLOG_INFO, "SATA drive self test is error.");
            return;
        }
    }
    // 更新find_short_long_dst
    if (short_long_dst_flag) {
        *find_short_long_dst_flag = 1;
    }
    return;
}

/*
 * Description: 输出self test结果
 */
static void print_self_test_result(PD_SMART_TEST_ANALYSIS *diagnose_result, const ATA_SMART_EXTSELFTESTLOG_DESC_S *desc,
    PD_LOG_S *pd_log)
{
    gint ret;
    const gchar* self_test_result[] = {
        "Completed without error", "Aborted by host", "Interrupted (host reset)",
        "Fatal or unknown error", "Completed: unknown failure",
        "Completed: electrical failure", "Completed: servo/seek failure",
        "Completed: read failure", "Completed: handling damage??",
        "Reserved(9)              ", "Reserved(10)             ",
        "Reserved(11)             ", "Reserved(12)             ",
        "Reserved(13)             ", "Reserved(14)             ",
        "Self-test routine in progress"
    };

    if (diagnose_result == NULL || diagnose_result->result == NULL ||
        diagnose_result->result->o_fault_bitmap.pd_short_dst_error != 1) {
        return;
    }

    // 不是short dst也不是long dst
    if (desc->selfTestType != 1 && desc->selfTestType != 2) {
        return;
    }

    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", g_selftest_desc[desc->selfTestType].desc,
        self_test_result[(desc->selfTestStatus >> 4) & 0xf]);
    if (ret <= 0) {
        debug_log(DLOG_ERROR, "%s: snprintf_s failed.", __FUNCTION__);
        return;
    }

    // 测试结果
    debug_log(DLOG_INFO, "Self test error of %s.", pd_log->pd_device_name);
    return;
}

/*
 * Description: 处理sata盘的extent self test log数据
 * History: 1.2018年4月13日
 * 新生成函数
 */
void pd_log_handle_sata_ext_self_test(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *pd_log_jso)
{
    ATA_SMART_EXTSELFTESTLOG_S *ext_self_test_log = NULL;
    const ATA_SMART_EXTSELFTESTLOG_DESC_S *desc = NULL;

    guint32 i, test_num, max_test_num, test_index, err_count, ign_count;
    guint64 ext_lba;
    gint32 state, ok_test_num;
    const guint8 *lba = NULL;
    guchar header_print = TRUE;
    PD_SMART_TEST_ANALYSIS *diagnose_result = (PD_SMART_TEST_ANALYSIS *)out_put;
    guint8 find_short_long_dst = 0;
    guint8 tmp_data_error = 0;
    Json *self_test_array = NULL;

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

    tmp_data_error = ((SML_SUCCESS != pd_log->SATADevice.extended_selftest.result &&
        SML_ERR_PD_SCSI_RESP_TRUNCATED != pd_log->SATADevice.extended_selftest.result) ||
        NULL == pd_log->SATADevice.extended_selftest.data || 0 == pd_log->SATADevice.extended_selftest.data_length);

    if (tmp_data_error) {
        return;
    }

    ext_self_test_log = (ATA_SMART_EXTSELFTESTLOG_S *)pd_log->SATADevice.extended_selftest.data;

    pd_log_fprintf(file, "SMART Extended Self-test Log Version: %u \n", ext_self_test_log->version);

    if (0 == ext_self_test_log->logDescIndex) {
        pd_log_fprintf(file, "No self-tests have been logged.\n\n");
        return;
    }

    max_test_num = pd_log->SATADevice.extended_selftest.max_raw_data_size.sectors * ATA_LOG_EXT_SELF_TEST_LOG_NUM;
    test_index = ext_self_test_log->logDescIndex;
    if (test_index > max_test_num) {
        pd_log_fprintf(file, "Invalid Self-test Log test_index = 0x%04x (reserved = 0x%02x)\n", test_index,
            ext_self_test_log->reserved1);
        return;
    }

    // 原始数据index 从1 开始
    test_index--;

    err_count = 0;
    ign_count = 0;
    ok_test_num = -1;
    if (JsonArrayCreate(&self_test_array) != JSON_OK) {
        return;
    }

    for (i = 0, test_num = 1; i < max_test_num && test_num <= ATA_LOG_EXT_SELF_TEST_LOG_MAX_NUM;
        i++, test_index = (test_index > 0 ? test_index - 1 : max_test_num - 1)) {
        desc = (ext_self_test_log + test_index / ATA_LOG_EXT_SELF_TEST_LOG_NUM)->logDescs +
            (test_index % ATA_LOG_EXT_SELF_TEST_LOG_NUM);

        // 跳过无效的数据
        if (FALSE == pd_log_check_data(desc, sizeof(ATA_SMART_EXTSELFTESTLOG_DESC_S))) {
            continue;
        }

        lba = desc->failingLba;
        ext_lba = lba[0] | (lba[1] << 8) | (lba[2] << 16) | ((guint64)lba[3] << 24) | ((guint64)lba[4] << 32) |
            ((guint64)lba[5] << 40);
        Json *self_test_node = NULL;
        if (JsonObjectCreate(&self_test_node) != JSON_OK) {
            continue;
        }

        state = pd_log_handle_sata_self_test_item(test_num, desc->selfTestType, desc->selfTestStatus, desc->timestamp,
            ext_lba, &header_print, file, self_test_node);
        char *json_str = JsonPrint(self_test_node);
        if (0 != g_strcmp0(json_str, "{ }")) {
            guint32 array_size;
            JsonArraySizeGet(self_test_array, &array_size);
            JsonArrayItemInsert(self_test_array, array_size, self_test_node);
        } else {
            JsonObjectRelease(self_test_node);
        }
        JsonStringValueFree(json_str);

        // 故障诊断
        /* BEGIN: Added by, 2019/1/17   PN:UADP135084 */
        pd_log_handle_sata_ext_self_test_diagnose(&find_short_long_dst, desc, state, diagnose_result);
        print_self_test_result(diagnose_result, desc, pd_log);

        if (NULL != diagnose_result && NULL != diagnose_result->result &&
            (1 == diagnose_result->in_progress || 1 == diagnose_result->result->o_fault_bitmap.pd_short_dst_error)) {
            JsonObjectRelease(self_test_array);
            return;
        }
        /* END:   Added by, 2019/1/17 */

        if (state < 0) {
            if (ok_test_num < 0) {
                err_count++;
            } else {
                ign_count++;
            }
        } else if (state > 0 && ok_test_num < 0) {
            ok_test_num = (gint32)test_num;
        }

        test_num++;
    }

    if (ign_count) {
        pd_log_fprintf(file,
            "%d of %d failed self-tests are outdated by newer successful extended offline self-test #%2d\n", ign_count,
            ign_count + err_count, ok_test_num);
    }

    pd_log_fprintf(file, "\n");
    if (NULL != pd_log_jso) {
        (void)JsonObjectItemSet(pd_log_jso, "selftest_log", self_test_array);
    } else {
        JsonObjectRelease(self_test_array);
    }
    return;
}

/*
 * Description: 处理sata盘的phy ecent log数据
 * History: 1.2018年4月13日
 * 新生成函数
 */
void pd_log_handle_sata_phy_event(FILE *file, PD_LOG_S *pd_log, void *out_put, Json *pd_log_jso)
{
    guchar *phy_event = NULL;
    guint32 i, j, id, size;
    guint64 value = 0;
    guint64 max_value = 0;
    const gchar *desc = NULL;
    guint32 icrc_count = 0;
    gchar tmp_str[ATA_LOG_STRING_LENGTH] = {0};

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

    if (SML_SUCCESS != pd_log->SATADevice.phy_event.result || NULL == pd_log->SATADevice.phy_event.data ||
        0 == pd_log->SATADevice.phy_event.data_length) {
        return;
    }

    phy_event = pd_log->SATADevice.phy_event.data;
    if (phy_event[0] || phy_event[1] || phy_event[2] || phy_event[3]) {
        pd_log_fprintf(file, "[Reserved: 0x%02x 0x%02x 0x%02x 0x%02x]\n", phy_event[0], phy_event[1], phy_event[2],
            phy_event[3]);
    }

    pd_log_fprintf(file, "ID      Size     Value  Description\n");

    for (i = 4;;) {
        // 获取id 和size (bits 14:12)
        id = phy_event[i] | (phy_event[i + 1] << 8);
        size = ((id >> 12) & 0x7) << 1;
        id = id & 0x8fff;

        // id 无效则结束
        if (id == 0) {
            break;
        }

        i = i + 2;
        // size 无效则结束
        if (2 > size || size > 8 || i + size >= ATA_LOG_DATA_MAX_LEN) {
            pd_log_fprintf(file, "0x%04x  %u: Invalid entry\n", id, size);
            break;
        }

        value = 0;
        max_value = 0;

        for (j = 0; j < size; j += 2) {
            value |= (guint64)(phy_event[i + j] | (phy_event[i + j + 1] << 8)) << (j * 8);
            max_value |= (guint64)0xffffU << (j * 8);
        }

        i = i + size;

        switch (id) {
            case 0x001:
                desc = "Command failed due to ICRC error";
                icrc_count++;
                break;

            case 0x002:
                desc = "R_ERR response for data FIS";
                break;

            case 0x003:
                desc = "R_ERR response for device-to-host data FIS";
                break;

            case 0x004:
                desc = "R_ERR response for host-to-device data FIS";
                break;

            case 0x005:
                desc = "R_ERR response for non-data FIS";
                break;

            case 0x006:
                desc = "R_ERR response for device-to-host non-data FIS";
                break;

            case 0x007:
                desc = "R_ERR response for host-to-device non-data FIS";
                break;

            case 0x008:
                desc = "Device-to-host non-data FIS retries";
                break;

            case 0x009:
                desc = "Transition from drive PhyRdy to drive PhyNRdy";
                break;

            case 0x00A:
                desc = "Device-to-host register FISes sent due to a COMRESET";
                break;

            case 0x00B:
                desc = "CRC errors within host-to-device FIS";
                break;

            case 0x00D:
                desc = "Non-CRC errors within host-to-device FIS";
                break;

            case 0x00F:
                desc = "R_ERR response for host-to-device data FIS, CRC";
                break;

            case 0x010:
                desc = "R_ERR response for host-to-device data FIS, non-CRC";
                break;

            case 0x012:
                desc = "R_ERR response for host-to-device non-data FIS, CRC";
                break;

            case 0x013:
                desc = "R_ERR response for host-to-device non-data FIS, non-CRC";
                break;

            default:
                desc = ((id & 0x8000) ? "Vendor specific" : "Unknown");
                break;
        }

        pd_log_fprintf(file, "0x%04x  %u %12llu%c %s\n", id, size, value, (value == max_value ? '+' : ' '), desc);
    }

    pd_log_fprintf(file, "\n");
    (void)snprintf_s(tmp_str, ATA_LOG_STRING_LENGTH, ATA_LOG_STRING_LENGTH - 1, "%u", icrc_count);
    Json *str_obj = NULL;
    JsonStringCreate(tmp_str, &str_obj);
    JsonObjectItemSet(pd_log_jso, "phy_event_icrc_count", str_obj);
}
