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

#include <stdio.h>

#include "sml_errcodes.h"
#include "sml.h"
#include "sml_common.h"
#include "sml_public.h"
#include "sml_physical_drive.h"
#include "histore/tool_lib.h"
#include "histore/error_code.h"
#include "hs_misc.h"
#include "hs_pd_sas_log.h"

/*
 * Description : 组装获取HSSD IO信息的SCSI信令。该命令获取硬盘的读写数据量统计数据, 返回0x40字节数据，每项8字节
 */
void component_hssd_io_info_scsi_command(
    struct cmd_scsi_passthrough *scsi_passthru_cmd, guint16 device_id, guint16 page_length)
{
    if (scsi_passthru_cmd == NULL) {
        debug_log(DLOG_ERROR, "%s, The scsi_passthru_cmd is null.", __FUNCTION__);
        return;
    }

    struct multi_disk_location disk_location;
    (void)memset_s(&disk_location, sizeof(disk_location), 0, sizeof(disk_location));
    disk_location.did = device_id;
    disk_location.flag = DISK_LOC_DID;
    (void)memcpy_s(&scsi_passthru_cmd->loc, sizeof(scsi_passthru_cmd->loc), &disk_location, sizeof(disk_location));

    // 0，1,2,3,4,5,6,7,8,9 huawei scsi协议字段
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->cdb_len = SCSI_CDB_LENGTH10;
    scsi_passthru_cmd->cdb[0] = 0xC0;   // operation Code(C0h)
    scsi_passthru_cmd->cdb[1] = 0x07;   // SubFunCode(07h)
    scsi_passthru_cmd->cdb[2] = 0x00;   // 2: page_length高字节位
    scsi_passthru_cmd->cdb[3] = 0x40;   // 3: page_length低字节位
    scsi_passthru_cmd->cdb[4] = 0x00;   // 4: 后6字节为Reserved
    scsi_passthru_cmd->cdb[5] = 0x00;
    scsi_passthru_cmd->cdb[6] = 0x00;
    scsi_passthru_cmd->cdb[7] = 0x00;
    scsi_passthru_cmd->cdb[8] = page_length & 0xFF;
    scsi_passthru_cmd->cdb[9] = 0x00;

    return;
}

 /*
 * Description : 通过SCSI passthru发送命令读取HSSD IO信息
 */
gint32 send_read_hssd_io_info_scsi_command(
    guint32 ctrl_id, guint16 device_id, guint8 **pbuf, guint32 *buf_size, guint32 *scsi_status)
{
    gint32 ret = SML_SUCCESS;
    const guint16 page_length = 64;

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

    struct cmd_scsi_passthrough *scsi_passthru_cmd =
        (struct cmd_scsi_passthrough *)g_malloc0(sizeof(struct cmd_scsi_passthrough));
    if (scsi_passthru_cmd == NULL) {
        debug_log(DLOG_ERROR, "%s, Can not alloc memory.", __FUNCTION__);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    component_hssd_io_info_scsi_command(scsi_passthru_cmd, device_id, page_length);

    guint8 *data = (guint8 *)g_malloc0(page_length);
    if (data == NULL) {
        debug_log(DLOG_ERROR, "%s, Can not alloc memory.", __FUNCTION__);
        g_free(scsi_passthru_cmd);
        return SML_ERR_NULL_DATA;
    }

    if ((ret = send_scsi_passthru_cmd(ctrl_id, scsi_passthru_cmd, data, page_length)) != SML_SUCCESS) {
        debug_log(DLOG_ERROR, "Get io info data failed, ctrl_id[%u], device_id[%u], return 0x%04x",
            ctrl_id, device_id, ret);
        
        if (scsi_status != NULL) {
            *scsi_status = ret;
        }

        g_free(data);
        g_free(scsi_passthru_cmd);
        return ret;
    }

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

    errno_t safe_ret = memcpy_s(*pbuf, page_length, data, page_length);
    if (safe_ret != EOK) {
        debug_log(DLOG_ERROR, "%s, The memcpy data to buf failed, return %d.", __FUNCTION__, safe_ret);
        g_free(*pbuf);
        *pbuf = NULL;
        g_free(data);
        g_free(scsi_passthru_cmd);
        return SML_ERR_SEC_FUNC_FAILED;
    }
    
    *buf_size = page_length;
    g_free(data);
    g_free(scsi_passthru_cmd);

    return SML_SUCCESS;
}