2100 lines
66 KiB
C
2100 lines
66 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Huawei Fabric Channel Linux driver
|
|
* Copyright(c) 2018 Huawei Technologies Co., Ltd
|
|
*
|
|
*/
|
|
|
|
#include "unf_common.h"
|
|
#include "hifc_chipitf.h"
|
|
|
|
#define HIFC_MBOX_TIME_SEC_MAX 60
|
|
|
|
#define HIFC_LINK_UP_COUNT 1
|
|
#define HIFC_LINK_DOWN_COUNT 2
|
|
#define HIFC_FC_DELETE_CMND_COUNT 3
|
|
|
|
#define HIFC_MBX_MAX_TIMEOUT 10000
|
|
|
|
void hifc_get_red_info_by_rw_type(struct unf_rw_reg_param_s *param,
|
|
struct hifc_inmbox_get_reg_info_s *v_reg_info);
|
|
void hifc_initial_dynamic_info(struct hifc_hba_s *v_fc_port);
|
|
|
|
static unsigned int hifc_recv_fc_link_up(struct hifc_hba_s *v_hba,
|
|
void *v_buf_in);
|
|
static unsigned int hifc_recv_fc_link_down(struct hifc_hba_s *v_hba,
|
|
void *v_buf_in);
|
|
static unsigned int hifc_recv_fc_del_cmd(struct hifc_hba_s *v_hba,
|
|
void *v_buf_in);
|
|
static unsigned int hifc_recv_fc_error(struct hifc_hba_s *v_hba,
|
|
void *v_buf_in);
|
|
|
|
static struct hifc_up_2_drv_msg_handle_s up_msg_handle[] = {
|
|
{ HIFC_MBOX_RECV_FC_LINKUP, hifc_recv_fc_link_up },
|
|
{ HIFC_MBOX_RECV_FC_LINKDOWN, hifc_recv_fc_link_down },
|
|
{ HIFC_MBOX_RECV_FC_DELCMD, hifc_recv_fc_del_cmd },
|
|
{ HIFC_MBOX_RECV_FC_ERROR, hifc_recv_fc_error }
|
|
};
|
|
|
|
void hifc_up_msg_2_driver_proc(void *v_hwdev_handle, void *v_pri_handle,
|
|
unsigned char v_cmd, void *v_buf_in,
|
|
unsigned short v_in_size, void *v_buf_out,
|
|
unsigned short *v_out_size)
|
|
{
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
unsigned int index = 0;
|
|
struct hifc_hba_s *hba = NULL;
|
|
struct hifc_mbox_header_s *mbx_header = NULL;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, v_hwdev_handle, return);
|
|
HIFC_CHECK(INVALID_VALUE32, v_pri_handle, return);
|
|
HIFC_CHECK(INVALID_VALUE32, v_buf_in, return);
|
|
HIFC_CHECK(INVALID_VALUE32, v_buf_out, return);
|
|
HIFC_CHECK(INVALID_VALUE32, v_out_size, return);
|
|
|
|
hba = (struct hifc_hba_s *)v_pri_handle;
|
|
if (!hba) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_EVENT, UNF_ERR,
|
|
"[err]Hba is null");
|
|
|
|
return;
|
|
}
|
|
|
|
mbx_header = (struct hifc_mbox_header_s *)v_buf_in;
|
|
if (mbx_header->cmnd_type != v_cmd) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_EVENT, UNF_ERR,
|
|
"[err]Port(0x%x) cmd(0x%x) is not matched with header cmd type(0x%x)",
|
|
hba->port_cfg.port_id, v_cmd,
|
|
mbx_header->cmnd_type);
|
|
return;
|
|
}
|
|
|
|
while (index < (sizeof(up_msg_handle) /
|
|
sizeof(struct hifc_up_2_drv_msg_handle_s))) {
|
|
if ((v_cmd == up_msg_handle[index].cmd) &&
|
|
(up_msg_handle[index].pfn_hifc_msg_up2drv_handler)) {
|
|
ret =
|
|
up_msg_handle[index].pfn_hifc_msg_up2drv_handler(
|
|
hba,
|
|
v_buf_in);
|
|
if (ret != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_EVENT,
|
|
UNF_ERR,
|
|
"[warn]Port(0x%x) process up cmd(0x%x) failed",
|
|
hba->port_cfg.port_id, v_cmd);
|
|
}
|
|
|
|
/* Process Done & return */
|
|
return;
|
|
}
|
|
index++;
|
|
}
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_EVENT, UNF_ERR,
|
|
"[err]Port(0x%x) process up cmd(0x%x) failed",
|
|
hba->port_cfg.port_id, v_cmd);
|
|
|
|
PRINT_OUTBOUND_IOB(UNF_MAJOR, v_buf_in, ((unsigned int)v_in_size));
|
|
}
|
|
|
|
unsigned int hifc_get_chip_msg(void *v_hba, void *v_mac)
|
|
{
|
|
struct hifc_hba_s *hba = NULL;
|
|
struct unf_get_chip_info_argout *wwn = NULL;
|
|
struct hifc_inbox_get_chip_info_s get_chip_info;
|
|
union hifc_outmbox_generic_u *chip_info_sts = NULL;
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, v_hba, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, v_mac, return UNF_RETURN_ERROR);
|
|
|
|
hba = (struct hifc_hba_s *)v_hba;
|
|
wwn = (struct unf_get_chip_info_argout *)v_mac;
|
|
|
|
memset(&get_chip_info, 0, sizeof(struct hifc_inbox_get_chip_info_s));
|
|
|
|
chip_info_sts = kmalloc(sizeof(union hifc_outmbox_generic_u),
|
|
GFP_ATOMIC);
|
|
if (!chip_info_sts) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"malloc outmbox memory failed");
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
memset(chip_info_sts, 0, sizeof(union hifc_outmbox_generic_u));
|
|
|
|
get_chip_info.header.cmnd_type = HIFC_MBOX_GET_CHIP_INFO;
|
|
get_chip_info.header.length =
|
|
HIFC_BYTES_TO_DW_NUM(sizeof(struct hifc_inbox_get_chip_info_s));
|
|
|
|
if (hifc_mb_send_and_wait_mbox(hba, &get_chip_info,
|
|
sizeof(get_chip_info), chip_info_sts) !=
|
|
RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"hifc can't send and wait mailbox, command type: 0x%x.",
|
|
get_chip_info.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (chip_info_sts->get_chip_info_sts.status != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"Port(0x%x) mailbox status incorrect status(0x%x) .",
|
|
hba->port_cfg.port_id,
|
|
chip_info_sts->get_chip_info_sts.status);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (chip_info_sts->get_chip_info_sts.header.cmnd_type !=
|
|
HIFC_MBOX_GET_CHIP_INFO_STS) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"Port(0x%x) receive mailbox type incorrect type: 0x%x.",
|
|
hba->port_cfg.port_id,
|
|
chip_info_sts->get_chip_info_sts.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
wwn->board_type = chip_info_sts->get_chip_info_sts.board_type;
|
|
hba->card_info.card_type = chip_info_sts->get_chip_info_sts.board_type;
|
|
wwn->wwpn = chip_info_sts->get_chip_info_sts.wwpn;
|
|
wwn->wwnn = chip_info_sts->get_chip_info_sts.wwnn;
|
|
wwn->sys_mac = chip_info_sts->get_chip_info_sts.sys_mac;
|
|
|
|
ret = RETURN_OK;
|
|
exit:
|
|
kfree(chip_info_sts);
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_get_chip_capability(void *hw_dev_handle,
|
|
struct hifc_chip_info_s *v_chip_info)
|
|
{
|
|
struct hifc_inbox_get_chip_info_s get_chip_info;
|
|
union hifc_outmbox_generic_u *chip_info_sts = NULL;
|
|
unsigned short out_size = 0;
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, hw_dev_handle, return UNF_RETURN_ERROR);
|
|
|
|
memset(&get_chip_info, 0, sizeof(struct hifc_inbox_get_chip_info_s));
|
|
|
|
chip_info_sts = kmalloc(sizeof(union hifc_outmbox_generic_u),
|
|
GFP_ATOMIC);
|
|
if (!chip_info_sts) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"malloc outmbox memory failed");
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
memset(chip_info_sts, 0, sizeof(union hifc_outmbox_generic_u));
|
|
|
|
get_chip_info.header.cmnd_type = HIFC_MBOX_GET_CHIP_INFO;
|
|
get_chip_info.header.length =
|
|
HIFC_BYTES_TO_DW_NUM(sizeof(struct hifc_inbox_get_chip_info_s));
|
|
out_size = sizeof(union hifc_outmbox_generic_u);
|
|
|
|
if (hifc_msg_to_mgmt_sync(hw_dev_handle, HIFC_MOD_FC,
|
|
HIFC_MBOX_GET_CHIP_INFO,
|
|
(void *)&get_chip_info.header,
|
|
sizeof(struct hifc_inbox_get_chip_info_s),
|
|
(union hifc_outmbox_generic_u *)chip_info_sts,
|
|
&out_size,
|
|
(HIFC_MBX_MAX_TIMEOUT)) != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"hifc can't send and wait mailbox, command type: 0x%x.",
|
|
HIFC_MBOX_GET_CHIP_INFO);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (chip_info_sts->get_chip_info_sts.status != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"Port mailbox status incorrect status(0x%x) .",
|
|
chip_info_sts->get_chip_info_sts.status);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (chip_info_sts->get_chip_info_sts.header.cmnd_type !=
|
|
HIFC_MBOX_GET_CHIP_INFO_STS) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"Port receive mailbox type incorrect type: 0x%x.",
|
|
chip_info_sts->get_chip_info_sts.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
v_chip_info->wwnn = chip_info_sts->get_chip_info_sts.wwnn;
|
|
v_chip_info->wwpn = chip_info_sts->get_chip_info_sts.wwpn;
|
|
v_chip_info->tape_support = (unsigned char)
|
|
chip_info_sts->get_chip_info_sts.tape_support;
|
|
ret = RETURN_OK;
|
|
exit:
|
|
kfree(chip_info_sts);
|
|
return ret;
|
|
}
|
|
|
|
void hifc_get_red_info_by_rw_type(struct unf_rw_reg_param_s *param,
|
|
struct hifc_inmbox_get_reg_info_s *v_reg_info)
|
|
{
|
|
if ((param->rw_type == UNF_READ) ||
|
|
(param->rw_type == UNF_READ_64)) {
|
|
v_reg_info->op_code = 0;
|
|
} else if ((param->rw_type == UNF_WRITE) ||
|
|
(param->rw_type == UNF_WRITE_64)) {
|
|
v_reg_info->op_code = 1;
|
|
}
|
|
|
|
if ((param->rw_type == UNF_READ) ||
|
|
(param->rw_type == UNF_WRITE)) {
|
|
v_reg_info->reg_len = 32;
|
|
} else if ((param->rw_type == UNF_READ_64) ||
|
|
(param->rw_type == UNF_WRITE_64)) {
|
|
v_reg_info->reg_len = 64;
|
|
}
|
|
}
|
|
|
|
unsigned int hifc_rw_reg(void *v_hba, void *v_params)
|
|
{
|
|
struct hifc_hba_s *hba = NULL;
|
|
struct unf_rw_reg_param_s *param = NULL;
|
|
struct hifc_inmbox_get_reg_info_s reg_info;
|
|
union hifc_outmbox_generic_u *reg_info_sts = NULL;
|
|
unsigned int para_value_out_l = 0;
|
|
unsigned int para_value_out_h = 0;
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, v_hba, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, v_params, return UNF_RETURN_ERROR);
|
|
|
|
hba = (struct hifc_hba_s *)v_hba;
|
|
param = (struct unf_rw_reg_param_s *)v_params;
|
|
|
|
memset(®_info, 0, sizeof(struct hifc_inmbox_get_reg_info_s));
|
|
reg_info_sts = kmalloc(sizeof(union hifc_outmbox_generic_u),
|
|
GFP_ATOMIC);
|
|
if (!reg_info_sts) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR, "malloc outmbox memory failed");
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
memset(reg_info_sts, 0, sizeof(union hifc_outmbox_generic_u));
|
|
|
|
hifc_get_red_info_by_rw_type(param, ®_info);
|
|
|
|
reg_info.reg_addr = param->offset;
|
|
reg_info.reg_value_l32 = (param->value) & VALUEMASK_L;
|
|
reg_info.reg_value_h32 = ((param->value) & VALUEMASK_H) >> 32;
|
|
|
|
reg_info.header.cmnd_type = HIFC_MBOX_REG_RW_MODE;
|
|
reg_info.header.length =
|
|
HIFC_BYTES_TO_DW_NUM(sizeof(struct hifc_inmbox_get_reg_info_s));
|
|
|
|
if (hifc_mb_send_and_wait_mbox(hba, ®_info,
|
|
sizeof(reg_info),
|
|
reg_info_sts) != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"hifc can't send and wait mailbox, command type: 0x%x.",
|
|
reg_info.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (reg_info_sts->get_reg_info_sts.status != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"Port(0x%x) mailbox status incorrect status(0x%x) .",
|
|
hba->port_cfg.port_id,
|
|
reg_info_sts->get_reg_info_sts.status);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (reg_info_sts->get_reg_info_sts.header.cmnd_type !=
|
|
HIFC_MBOX_REG_RW_MODE_STS) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"Port(0x%x) receive mailbox type incorrect type: 0x%x.",
|
|
hba->port_cfg.port_id,
|
|
reg_info_sts->get_reg_info_sts.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
para_value_out_l = reg_info_sts->get_reg_info_sts.reg_value_l32;
|
|
para_value_out_h = reg_info_sts->get_reg_info_sts.reg_value_h32;
|
|
param->value = (unsigned long long)para_value_out_l |
|
|
((unsigned long long)para_value_out_h << 32);
|
|
|
|
ret = RETURN_OK;
|
|
exit:
|
|
kfree(reg_info_sts);
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_config_port_table(struct hifc_hba_s *v_hba)
|
|
{
|
|
struct hifc_inbox_config_api_s config_api;
|
|
union hifc_outmbox_generic_u *out_mbox = NULL;
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, NULL != v_hba, return UNF_RETURN_ERROR);
|
|
|
|
memset(&config_api, 0, sizeof(config_api));
|
|
out_mbox = kmalloc(sizeof(union hifc_outmbox_generic_u), GFP_ATOMIC);
|
|
if (!out_mbox) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR, "malloc outmbox memory failed");
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
memset(out_mbox, 0, sizeof(union hifc_outmbox_generic_u));
|
|
|
|
config_api.header.cmnd_type = HIFC_MBOX_CONFIG_API;
|
|
config_api.header.length =
|
|
HIFC_BYTES_TO_DW_NUM(sizeof(struct hifc_inbox_config_api_s));
|
|
|
|
config_api.op_code = UNDEFINEOPCODE;
|
|
|
|
/* change switching top cmd of CM to the cmd that up recognize */
|
|
/* if the cmd equals UNF_TOP_P2P_MASK sending in CM means that it
|
|
* should be changed into P2P top, LL using HIFC_TOP_NON_LOOP_MASK
|
|
*/
|
|
if ((unsigned char)v_hba->port_topo_cfg == UNF_TOP_P2P_MASK) {
|
|
config_api.topy_mode = 0x2;
|
|
/* if the cmd equals UNF_TOP_LOOP_MASK sending in CM means that it
|
|
* should be changed into loop top, LL using HIFC_TOP_LOOP_MASK
|
|
*/
|
|
} else if ((unsigned char)v_hba->port_topo_cfg == UNF_TOP_LOOP_MASK) {
|
|
config_api.topy_mode = 0x1;
|
|
|
|
/* if the cmd equals UNF_TOP_AUTO_MASK sending in CM means that it
|
|
* should be changed into loop top, LL using HIFC_TOP_AUTO_MASK
|
|
*/
|
|
} else if ((unsigned char)v_hba->port_topo_cfg == UNF_TOP_AUTO_MASK) {
|
|
config_api.topy_mode = 0x0;
|
|
} else {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"[err]Port(0x%x) topo cmd is error, command type: 0x%x",
|
|
v_hba->port_cfg.port_id,
|
|
(unsigned char)v_hba->port_topo_cfg);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
/* About speed */
|
|
config_api.sfp_speed = (unsigned char)(v_hba->port_speed_cfg);
|
|
config_api.max_speed = (unsigned char)(v_hba->max_support_speed);
|
|
|
|
config_api.rx_bbcredit_32g = HIFC_LOWLEVEL_DEFAULT_32G_BB_CREDIT;
|
|
config_api.rx_bbcredit_16g = HIFC_LOWLEVEL_DEFAULT_16G_BB_CREDIT;
|
|
config_api.rx_bbcredit_842g = HIFC_LOWLEVEL_DEFAULT_842G_BB_CREDIT;
|
|
config_api.rdy_cnt_bf_fst_frm = HIFC_LOWLEVEL_DEFAULT_LOOP_BB_CREDIT;
|
|
config_api.esch_value_32g = HIFC_LOWLEVEL_DEFAULT_32G_ESCH_VALUE;
|
|
config_api.esch_value_16g = HIFC_LOWLEVEL_DEFAULT_16G_ESCH_VALUE;
|
|
config_api.esch_value_8g = HIFC_LOWLEVEL_DEFAULT_842G_ESCH_VALUE;
|
|
config_api.esch_value_4g = HIFC_LOWLEVEL_DEFAULT_842G_ESCH_VALUE;
|
|
config_api.esch_value_2g = HIFC_LOWLEVEL_DEFAULT_842G_ESCH_VALUE;
|
|
config_api.esch_bust_size = HIFC_LOWLEVEL_DEFAULT_ESCH_BUS_SIZE;
|
|
|
|
/* default value:0xFF */
|
|
config_api.hard_alpa = 0xFF;
|
|
memcpy(config_api.port_name, v_hba->sys_port_name, UNF_WWN_LEN);
|
|
|
|
/* if only for slave, the value is 1; if participate master choosing,
|
|
* the value is 0
|
|
*/
|
|
config_api.slave = v_hba->port_loop_role;
|
|
|
|
/* 1:auto negotiate, 0:fixed mode negotiate */
|
|
if (config_api.sfp_speed == 0)
|
|
config_api.auto_sneg = 0x1;
|
|
else
|
|
config_api.auto_sneg = 0x0;
|
|
|
|
/* send & wait */
|
|
if (hifc_mb_send_and_wait_mbox(v_hba, &config_api,
|
|
sizeof(config_api),
|
|
out_mbox) != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"[warn]Port(0x%x) HIFC can't send and wait mailbox, command type: 0x%x",
|
|
v_hba->port_cfg.port_id,
|
|
config_api.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
/* mailbox status check */
|
|
if (out_mbox->config_api_sts.status != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
|
|
"[err]Port(0x%x) receive mailbox type(0x%x) with status(0x%x) error",
|
|
v_hba->port_cfg.port_id,
|
|
out_mbox->config_api_sts.header.cmnd_type,
|
|
out_mbox->config_api_sts.status);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
/* RSP type check */
|
|
if (out_mbox->config_api_sts.header.cmnd_type !=
|
|
HIFC_MBOX_CONFIG_API_STS) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
|
|
"[err]Port(0x%x) receive mailbox type(0x%x) error",
|
|
v_hba->port_cfg.port_id,
|
|
out_mbox->config_api_sts.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
ret = RETURN_OK;
|
|
exit:
|
|
kfree(out_mbox);
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_port_switch(struct hifc_hba_s *v_hba, int turn_on)
|
|
{
|
|
struct hifc_inbox_port_switch_s port_switch;
|
|
union hifc_outmbox_generic_u *port_switch_sts = NULL;
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, NULL != v_hba, return UNF_RETURN_ERROR);
|
|
|
|
memset(&port_switch, 0, sizeof(port_switch));
|
|
|
|
port_switch_sts = kmalloc(sizeof(union hifc_outmbox_generic_u),
|
|
GFP_ATOMIC);
|
|
if (!port_switch_sts) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR, "malloc outmbox memory failed");
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
memset(port_switch_sts, 0, sizeof(union hifc_outmbox_generic_u));
|
|
|
|
port_switch.header.cmnd_type = HIFC_MBOX_PORT_SWITCH;
|
|
port_switch.header.length =
|
|
HIFC_BYTES_TO_DW_NUM(sizeof(struct hifc_inbox_port_switch_s));
|
|
port_switch.op_code = (unsigned char)turn_on;
|
|
port_switch.port_type = (unsigned char)v_hba->port_type;
|
|
|
|
/* set the value is 0 first, vn2vf mode, vlan discovery automatically */
|
|
port_switch.host_id = 0;
|
|
port_switch.pf_id =
|
|
(unsigned char)(hifc_global_func_id(v_hba->hw_dev_handle));
|
|
port_switch.fcoe_mode = HIFC_FIP_MODE_VN2VF;
|
|
port_switch.conf_vlan = 0xffff;
|
|
port_switch.sys_node_name = *(unsigned long long *)v_hba->sys_node_name;
|
|
port_switch.sys_port_wwn = *(unsigned long long *)v_hba->sys_port_name;
|
|
|
|
/* send & wait mailbox */
|
|
if (hifc_mb_send_and_wait_mbox(v_hba, &port_switch, sizeof(port_switch),
|
|
port_switch_sts) != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"[warn]Port(0x%x) HIFC can't send and wait mailbox, command type(0x%x) opcode(0x%x)",
|
|
v_hba->port_cfg.port_id,
|
|
port_switch.header.cmnd_type, port_switch.op_code);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
/* check mailbox rsp status */
|
|
if (port_switch_sts->port_switch_sts.status != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
|
|
"[err]Port(0x%x) receive mailbox type(0x%x) status(0x%x) error",
|
|
v_hba->port_cfg.port_id,
|
|
port_switch_sts->port_switch_sts.header.cmnd_type,
|
|
port_switch_sts->port_switch_sts.status);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
/* check mailbox rsp type */
|
|
if (port_switch_sts->port_switch_sts.header.cmnd_type !=
|
|
HIFC_MBOX_PORT_SWITCH_STS) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
|
|
"[err]Port(0x%x) receive mailbox type(0x%x) error",
|
|
v_hba->port_cfg.port_id,
|
|
port_switch_sts->port_switch_sts.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_SUC, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
|
|
"[event]Port(0x%x) switch succeed, turns to %s",
|
|
v_hba->port_cfg.port_id,
|
|
(turn_on) ? "on" : "off");
|
|
|
|
ret = RETURN_OK;
|
|
exit:
|
|
kfree(port_switch_sts);
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_config_login_api(struct hifc_hba_s *v_hba,
|
|
struct unf_port_login_parms_s *v_login_para)
|
|
{
|
|
#define HIFC_LOOP_RDYNUM 8
|
|
int async_ret = RETURN_OK;
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
struct hifc_inmbox_config_login_s cfg_login;
|
|
union hifc_outmbox_generic_u *cfg_login_sts = NULL;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, NULL != v_hba, return UNF_RETURN_ERROR);
|
|
|
|
memset(&cfg_login, 0, sizeof(cfg_login));
|
|
cfg_login_sts = kmalloc(sizeof(union hifc_outmbox_generic_u),
|
|
GFP_ATOMIC);
|
|
if (!cfg_login_sts) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR, "malloc outmbox memory failed");
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
memset(cfg_login_sts, 0, sizeof(union hifc_outmbox_generic_u));
|
|
|
|
cfg_login.header.cmnd_type = HIFC_MBOX_CONFIG_LOGIN_API;
|
|
cfg_login.header.length =
|
|
HIFC_BYTES_TO_DW_NUM(sizeof(struct hifc_inmbox_config_login_s));
|
|
cfg_login.header.port_id = v_hba->port_index;
|
|
|
|
cfg_login.op_code = UNDEFINEOPCODE;
|
|
|
|
cfg_login.tx_bb_credit = v_hba->remote_bbcredit;
|
|
|
|
cfg_login.etov = v_hba->compared_edtov_val;
|
|
cfg_login.rtov = v_hba->compared_ratov_val;
|
|
|
|
cfg_login.rt_tov_tag = v_hba->remote_rttov_tag;
|
|
cfg_login.ed_tov_tag = v_hba->remote_edtov_tag;
|
|
cfg_login.bb_credit = v_hba->remote_bbcredit;
|
|
cfg_login.bbscn = HIFC_LSB(v_hba->compared_bbscn);
|
|
|
|
if (cfg_login.bbscn) {
|
|
cfg_login.lr_flag =
|
|
(v_login_para->els_cmnd_code == ELS_PLOGI) ? 0 : 1;
|
|
ret = hifc_mb_send_and_wait_mbox(v_hba, &cfg_login,
|
|
sizeof(cfg_login),
|
|
cfg_login_sts);
|
|
if (ret != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_WARN, UNF_LOG_REG_ATT,
|
|
UNF_WARN,
|
|
"Port(0x%x) HIFC can't send and wait mailbox, command type: 0x%x.",
|
|
v_hba->port_cfg.port_id,
|
|
cfg_login.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (cfg_login_sts->config_login_sts.header.cmnd_type !=
|
|
HIFC_MBOX_CONFIG_LOGIN_API_STS) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_REG_ATT,
|
|
UNF_INFO, "Port(0x%x) Receive mailbox type incorrect. Type: 0x%x.",
|
|
v_hba->port_cfg.port_id,
|
|
cfg_login_sts->config_login_sts.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (cfg_login_sts->config_login_sts.status != STATUS_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_WARN, UNF_LOG_LOGIN_ATT,
|
|
UNF_WARN, "Port(0x%x) Receive mailbox type(0x%x) status incorrect. Status: 0x%x.",
|
|
v_hba->port_cfg.port_id,
|
|
cfg_login_sts->config_login_sts.header.cmnd_type,
|
|
cfg_login_sts->config_login_sts.status);
|
|
|
|
goto exit;
|
|
}
|
|
} else {
|
|
async_ret = hifc_msg_to_mgmt_async(v_hba->hw_dev_handle,
|
|
HIFC_MOD_FC,
|
|
HIFC_MBOX_CONFIG_LOGIN_API,
|
|
&cfg_login,
|
|
sizeof(cfg_login));
|
|
|
|
if (async_ret != 0) {
|
|
HIFC_MAILBOX_STAT(v_hba,
|
|
HIFC_SEND_CONFIG_LOGINAPI_FAIL);
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT,
|
|
UNF_ERR,
|
|
"Port(0x%x) hifc can't send config login cmd to up,ret:%d.",
|
|
v_hba->port_cfg.port_id, async_ret);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
HIFC_MAILBOX_STAT(v_hba, HIFC_SEND_CONFIG_LOGINAPI);
|
|
}
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_SUC, UNF_LOG_LOGIN_ATT, UNF_MAJOR,
|
|
"Port(0x%x) Topo(0x%x) Config login param to up: txbbcredit(0x%x), BB_SC_N(0x%x).",
|
|
v_hba->port_cfg.port_id, v_hba->active_topo,
|
|
cfg_login.tx_bb_credit, cfg_login.bbscn);
|
|
|
|
ret = RETURN_OK;
|
|
exit:
|
|
kfree(cfg_login_sts);
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_mb_send_and_wait_mbox(struct hifc_hba_s *v_hba,
|
|
const void *v_in_mbox,
|
|
unsigned short in_size,
|
|
union hifc_outmbox_generic_u *out_mbox)
|
|
{
|
|
void *handle = NULL;
|
|
unsigned short out_size = 0;
|
|
unsigned long time_out = 0;
|
|
int ret = 0;
|
|
struct hifc_mbox_header_s *header;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, v_hba, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, v_in_mbox, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, out_mbox, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, v_hba->hw_dev_handle,
|
|
return UNF_RETURN_ERROR);
|
|
|
|
header = (struct hifc_mbox_header_s *)v_in_mbox;
|
|
out_size = sizeof(union hifc_outmbox_generic_u);
|
|
handle = v_hba->hw_dev_handle;
|
|
|
|
/* Wait for las mailbox completion: */
|
|
time_out = wait_for_completion_timeout(
|
|
&v_hba->mbox_complete,
|
|
(unsigned long)msecs_to_jiffies(HIFC_MBOX_TIME_SEC_MAX * 1000));
|
|
if (time_out == UNF_ZERO) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
|
|
"[err]Port(0x%x) wait mailbox(0x%x) completion timeout: %d sec",
|
|
v_hba->port_cfg.port_id, header->cmnd_type,
|
|
HIFC_MBOX_TIME_SEC_MAX);
|
|
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
|
|
/* Send Msg to uP Sync: timer 10s */
|
|
ret = hifc_msg_to_mgmt_sync(handle, HIFC_MOD_FC, header->cmnd_type,
|
|
(void *)v_in_mbox, in_size,
|
|
(union hifc_outmbox_generic_u *)out_mbox,
|
|
&out_size,
|
|
HIFC_MBX_MAX_TIMEOUT);
|
|
if (ret != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"[warn]Port(0x%x) can not send mailbox(0x%x) with ret:%d",
|
|
v_hba->port_cfg.port_id, header->cmnd_type, ret);
|
|
|
|
complete(&v_hba->mbox_complete);
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
|
|
complete(&v_hba->mbox_complete);
|
|
return RETURN_OK;
|
|
}
|
|
|
|
unsigned short hifc_get_global_base_qpn(void *v_handle)
|
|
{
|
|
#define NIC_UP_CMD_GET_GLOBAL_QPN 102
|
|
|
|
int ret = 0;
|
|
unsigned short out_size = 0;
|
|
struct hifc_get_global_base_qpn_s qpn_base = { 0 };
|
|
|
|
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_handle,
|
|
return INVALID_VALUE16);
|
|
qpn_base.func_id = hifc_global_func_id(v_handle);
|
|
out_size = (u16)sizeof(struct hifc_get_global_base_qpn_s);
|
|
|
|
/* Send Msg to uP Sync: timer 10s */
|
|
ret = hifc_msg_to_mgmt_sync(v_handle,
|
|
HIFC_MOD_L2NIC,
|
|
NIC_UP_CMD_GET_GLOBAL_QPN,
|
|
&qpn_base,
|
|
(u16)sizeof(qpn_base),
|
|
&qpn_base,
|
|
&out_size,
|
|
HIFC_MBX_MAX_TIMEOUT);
|
|
|
|
if (ret || (!out_size) || qpn_base.status) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"[warn]hifc_get_global_base_qpn failed, ret %d, out_size %u, qpn_info.ret%u",
|
|
ret, out_size, qpn_base.status);
|
|
|
|
return 0xFFFF;
|
|
}
|
|
|
|
return (u16)(qpn_base.base_qpn);
|
|
}
|
|
|
|
void hifc_initial_dynamic_info(struct hifc_hba_s *v_fc_port)
|
|
{
|
|
struct hifc_hba_s *hba = v_fc_port;
|
|
unsigned long flag = 0;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, NULL != hba, return);
|
|
|
|
spin_lock_irqsave(&hba->hba_lock, flag);
|
|
hba->active_port_speed = UNF_PORT_SPEED_UNKNOWN;
|
|
hba->active_topo = UNF_ACT_TOP_UNKNOWN;
|
|
hba->phy_link = UNF_PORT_LINK_DOWN;
|
|
hba->q_set_stage = HIFC_QUEUE_SET_STAGE_INIT;
|
|
hba->loop_map_valid = LOOP_MAP_INVALID;
|
|
hba->delay_info.srq_delay_flag = 0;
|
|
hba->delay_info.root_rq_rcvd_flag = 0;
|
|
spin_unlock_irqrestore(&hba->hba_lock, flag);
|
|
}
|
|
|
|
unsigned int hifc_recv_fc_link_up(struct hifc_hba_s *v_hba, void *v_buf_in)
|
|
{
|
|
#define HIFC_LOOP_MASK 0x1
|
|
#define HIFC_LOOPMAP_COUNT 128
|
|
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
struct hifc_link_event_s *buf_in = NULL;
|
|
|
|
buf_in = (struct hifc_link_event_s *)v_buf_in;
|
|
v_hba->phy_link = UNF_PORT_LINK_UP;
|
|
v_hba->active_port_speed = buf_in->speed;
|
|
v_hba->led_states.green_speed_led =
|
|
(unsigned char)(buf_in->green_speed_led);
|
|
v_hba->led_states.yellow_speed_led =
|
|
(unsigned char)(buf_in->yellow_speed_led);
|
|
v_hba->led_states.ac_led = (unsigned char)(buf_in->acled);
|
|
|
|
if ((buf_in->top_type == HIFC_LOOP_MASK) &&
|
|
((buf_in->loop_map_info[1] == UNF_FL_PORT_LOOP_ADDR) ||
|
|
(buf_in->loop_map_info[2] == UNF_FL_PORT_LOOP_ADDR))) {
|
|
v_hba->active_topo = UNF_ACT_TOP_PUBLIC_LOOP; /* Public Loop */
|
|
v_hba->active_al_pa = buf_in->alpa_value; /* AL_PA */
|
|
memcpy(v_hba->loop_map, buf_in->loop_map_info,
|
|
HIFC_LOOPMAP_COUNT);
|
|
v_hba->loop_map_valid = LOOP_MAP_VALID;
|
|
} else if (buf_in->top_type == HIFC_LOOP_MASK) {
|
|
v_hba->active_topo = UNF_ACT_TOP_PRIVATE_LOOP;/* Private Loop */
|
|
v_hba->active_al_pa = buf_in->alpa_value; /* AL_PA */
|
|
memcpy(v_hba->loop_map, buf_in->loop_map_info,
|
|
HIFC_LOOPMAP_COUNT);
|
|
v_hba->loop_map_valid = LOOP_MAP_VALID;
|
|
} else {
|
|
v_hba->active_topo = UNF_TOP_P2P_MASK; /* P2P_D or P2P_F */
|
|
}
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_EVENT, UNF_KEVENT,
|
|
"[event]Port(0x%x) receive link up event(0x%x) with speed(0x%x) uP_topo(0x%x) driver_topo(0x%x)",
|
|
v_hba->port_cfg.port_id, buf_in->link_event,
|
|
buf_in->speed, buf_in->top_type, v_hba->active_topo);
|
|
|
|
/* Set clear & flush state */
|
|
hifc_set_hba_flush_state(v_hba, UNF_FALSE);
|
|
hifc_set_root_sq_flush_state(v_hba, UNF_FALSE);
|
|
hifc_set_rport_flush_state(v_hba, UNF_FALSE);
|
|
|
|
/* Report link up event to COM */
|
|
UNF_LOWLEVEL_PORT_EVENT(ret, v_hba->lport,
|
|
UNF_PORT_LINK_UP, &v_hba->active_port_speed);
|
|
|
|
HIFC_LINK_EVENT_STAT(v_hba, HIFC_LINK_UP_COUNT);
|
|
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_recv_fc_link_down(struct hifc_hba_s *v_hba, void *v_buf_in)
|
|
{
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
struct hifc_link_event_s *buf_in = NULL;
|
|
|
|
buf_in = (struct hifc_link_event_s *)v_buf_in;
|
|
|
|
/* 1. Led state setting */
|
|
v_hba->led_states.green_speed_led =
|
|
(unsigned char)(buf_in->green_speed_led);
|
|
v_hba->led_states.yellow_speed_led =
|
|
(unsigned char)(buf_in->yellow_speed_led);
|
|
v_hba->led_states.ac_led = (unsigned char)(buf_in->acled);
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_EVENT, UNF_KEVENT,
|
|
"[event]Port(0x%x) receive link down event(0x%x) reason(0x%x)",
|
|
v_hba->port_cfg.port_id, buf_in->link_event, buf_in->reason);
|
|
|
|
hifc_initial_dynamic_info(v_hba);
|
|
|
|
/* 2. set HBA flush state */
|
|
hifc_set_hba_flush_state(v_hba, UNF_TRUE);
|
|
|
|
/* 3. set Root SQ flush state */
|
|
hifc_set_root_sq_flush_state(v_hba, UNF_TRUE);
|
|
|
|
/* 4. set R_Port (parent SQ) flush state */
|
|
hifc_set_rport_flush_state(v_hba, UNF_TRUE);
|
|
|
|
/* 5. Report link down event to COM */
|
|
UNF_LOWLEVEL_PORT_EVENT(ret, v_hba->lport, UNF_PORT_LINK_DOWN, 0);
|
|
|
|
/* DFX setting */
|
|
HIFC_LINK_REASON_STAT(v_hba, buf_in->reason);
|
|
HIFC_LINK_EVENT_STAT(v_hba, HIFC_LINK_DOWN_COUNT);
|
|
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_recv_fc_del_cmd(struct hifc_hba_s *v_hba, void *v_buf_in)
|
|
{
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
struct hifc_link_event_s *buf_in = NULL;
|
|
|
|
buf_in = (struct hifc_link_event_s *)v_buf_in;
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_LOGIN_ATT, UNF_KEVENT,
|
|
"[event]Port(0x%x) receive delete cmd event(0x%x)",
|
|
v_hba->port_cfg.port_id, buf_in->link_event);
|
|
|
|
/* Send buffer clear cmnd */
|
|
ret = hifc_clear_fetched_sq_wqe(v_hba);
|
|
|
|
v_hba->q_set_stage = HIFC_QUEUE_SET_STAGE_SCANNING;
|
|
HIFC_LINK_EVENT_STAT(v_hba, HIFC_FC_DELETE_CMND_COUNT);
|
|
|
|
HIFC_REFERNCE_VAR(buf_in, buf_in, ret);
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_recv_fc_error(struct hifc_hba_s *v_hba, void *v_buf_in)
|
|
{
|
|
#define FC_ERR_LEVEL_DEAD 0
|
|
#define FC_ERR_LEVEL_HIGH 1
|
|
#define FC_ERR_LEVEL_LOW 2
|
|
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
struct hifc_up_error_event_s *buf_in = NULL;
|
|
|
|
buf_in = (struct hifc_up_error_event_s *)v_buf_in;
|
|
if (buf_in->error_type >= HIFC_UP_ERR_BUTT ||
|
|
buf_in->error_value >= HIFC_ERR_VALUE_BUTT) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"Port(0x%x) receive a unsupported UP Error Event Type(0x%x) Value(0x%x).",
|
|
v_hba->port_cfg.port_id,
|
|
buf_in->error_type,
|
|
buf_in->error_value);
|
|
return ret;
|
|
}
|
|
|
|
switch (buf_in->error_level) {
|
|
case FC_ERR_LEVEL_DEAD:
|
|
/* todo: chip reset */
|
|
ret = RETURN_OK;
|
|
break;
|
|
|
|
case FC_ERR_LEVEL_HIGH:
|
|
/* port reset */
|
|
UNF_LOWLEVEL_PORT_EVENT(ret, v_hba->lport,
|
|
UNF_PORT_ABNORMAL_RESET, NULL);
|
|
break;
|
|
|
|
case FC_ERR_LEVEL_LOW:
|
|
ret = RETURN_OK;
|
|
break;
|
|
|
|
default:
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"Port(0x%x) receive a unsupported UP Error Event Level(0x%x), Can not Process.",
|
|
v_hba->port_cfg.port_id, buf_in->error_level);
|
|
return ret;
|
|
}
|
|
if (buf_in->error_value < HIFC_ERR_VALUE_BUTT)
|
|
HIFC_UP_ERR_EVENT_STAT(v_hba, buf_in->error_value);
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_KEVENT,
|
|
"[event]Port(0x%x) process UP Error Event Level(0x%x) Type(0x%x) Value(0x%x) %s.",
|
|
v_hba->port_cfg.port_id, buf_in->error_level,
|
|
buf_in->error_type, buf_in->error_value,
|
|
(ret == UNF_RETURN_ERROR) ? "ERROR" : "OK");
|
|
|
|
HIFC_REFERNCE_VAR(buf_in, buf_in, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_get_topo_cfg(void *v_hba, void *v_topo_cfg)
|
|
{
|
|
struct hifc_hba_s *hba = v_hba;
|
|
unsigned int *topo_cfg = v_topo_cfg;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, v_hba, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, v_topo_cfg, return UNF_RETURN_ERROR);
|
|
|
|
*topo_cfg = hba->port_topo_cfg;
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
|
|
"Get topology config: 0x%x.",
|
|
*topo_cfg);
|
|
|
|
return RETURN_OK;
|
|
}
|
|
|
|
unsigned int hifc_get_topo_act(void *v_hba, void *topo_act)
|
|
{
|
|
struct hifc_hba_s *hba = v_hba;
|
|
enum unf_act_topo_e *ret_topo_act = topo_act;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, hba, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, topo_act, return UNF_RETURN_ERROR);
|
|
|
|
/* Get topo from low_level */
|
|
*ret_topo_act = hba->active_topo;
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
|
|
"[info]Get active topology: 0x%x",
|
|
*ret_topo_act);
|
|
|
|
return RETURN_OK;
|
|
}
|
|
|
|
unsigned int hifc_get_loop_alpa(void *v_hba, void *v_alpa)
|
|
{
|
|
unsigned long flags = 0;
|
|
struct hifc_hba_s *hba = v_hba;
|
|
unsigned char *alpa = v_alpa;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, hba, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, v_alpa, return UNF_RETURN_ERROR);
|
|
|
|
spin_lock_irqsave(&hba->hba_lock, flags);
|
|
*alpa = hba->active_al_pa;
|
|
spin_unlock_irqrestore(&hba->hba_lock, flags);
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_REG_ATT, UNF_INFO,
|
|
"[info]Get active AL_PA(0x%x)", *alpa);
|
|
|
|
return RETURN_OK;
|
|
}
|
|
|
|
unsigned int hifc_get_lport_led(void *v_hba, void *v_led_state)
|
|
{
|
|
unsigned int ret = RETURN_OK;
|
|
struct hifc_hba_s *hba = v_hba;
|
|
struct hifc_led_state_s *led_state = v_led_state;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, v_hba, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, v_led_state, return UNF_RETURN_ERROR);
|
|
|
|
led_state->green_speed_led = hba->led_states.green_speed_led;
|
|
led_state->yellow_speed_led = hba->led_states.yellow_speed_led;
|
|
led_state->ac_led = hba->led_states.ac_led;
|
|
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_get_hardware_version(void *v_fc_port, void *v_version)
|
|
{
|
|
struct hifc_hba_s *fc_port = (struct hifc_hba_s *)v_fc_port;
|
|
struct unf_version_str_s *version =
|
|
(struct unf_version_str_s *)v_version;
|
|
char *hard_ware_ver = NULL;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, version, return UNF_RETURN_ERROR);
|
|
hard_ware_ver = version->buf;
|
|
HIFC_CHECK(INVALID_VALUE32, hard_ware_ver, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, fc_port, return UNF_RETURN_ERROR);
|
|
|
|
hard_ware_ver[UNF_HW_VERSION_LEN - 1] = 0;
|
|
|
|
return RETURN_OK;
|
|
}
|
|
|
|
unsigned int hifc_get_sfp_info(void *v_fc_port, void *v_sfp_info)
|
|
{
|
|
struct unf_lport_sfp_info *sfp_info =
|
|
(struct unf_lport_sfp_info *)v_sfp_info;
|
|
struct hifc_hba_s *hba = (struct hifc_hba_s *)v_fc_port;
|
|
struct hifc_inmbox_get_sfp_info_s get_sfp_info;
|
|
union hifc_outmbox_generic_u *get_sfp_info_sts = NULL;
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, hba, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, sfp_info, return UNF_RETURN_ERROR);
|
|
|
|
memset(&get_sfp_info, 0, sizeof(get_sfp_info));
|
|
|
|
get_sfp_info_sts = kmalloc(sizeof(union hifc_outmbox_generic_u),
|
|
GFP_ATOMIC);
|
|
if (!get_sfp_info_sts) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR, "malloc outmbox memory failed");
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
memset(get_sfp_info_sts, 0, sizeof(union hifc_outmbox_generic_u));
|
|
|
|
get_sfp_info.header.cmnd_type = HIFC_MBOX_GET_SFP_INFO;
|
|
get_sfp_info.header.length =
|
|
HIFC_BYTES_TO_DW_NUM(sizeof(struct hifc_inmbox_get_sfp_info_s));
|
|
get_sfp_info.header.port_id = (hba->port_index);
|
|
|
|
/* send mailbox and handle the return sts */
|
|
if (hifc_mb_send_and_wait_mbox(hba, &get_sfp_info, sizeof(get_sfp_info),
|
|
get_sfp_info_sts) != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_WARN, UNF_LOG_REG_ATT, UNF_WARN,
|
|
"Port(0x%x) HIFC can't send and wait mailbox, command type: 0x%x.",
|
|
hba->port_cfg.port_id,
|
|
get_sfp_info.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
sfp_info->status = get_sfp_info_sts->get_sfp_info_sts.status;
|
|
if (get_sfp_info_sts->get_sfp_info_sts.status != STATUS_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_WARN, UNF_LOG_LOGIN_ATT, UNF_WARN,
|
|
"Port(0x%x) Receive mailbox type(0x%x) status incorrect. Status: 0x%x.",
|
|
hba->port_cfg.port_id,
|
|
get_sfp_info_sts->get_sfp_info_sts.header.cmnd_type,
|
|
get_sfp_info_sts->get_sfp_info_sts.status);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (get_sfp_info_sts->get_sfp_info_sts.header.cmnd_type !=
|
|
HIFC_MBOX_GET_SFP_INFO_STS) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_REG_ATT, UNF_INFO,
|
|
"Port(0x%x) Receive mailbox type incorrect. Type: 0x%x.",
|
|
hba->port_cfg.port_id,
|
|
get_sfp_info_sts->get_sfp_info_sts.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
/* the real sfpinfo is beyond the header of sts */
|
|
memcpy(&sfp_info->sfp_eeprom_info,
|
|
((unsigned char *)get_sfp_info_sts +
|
|
sizeof(get_sfp_info_sts->get_sfp_info_sts)),
|
|
sizeof(union unf_sfp_eeprome_info));
|
|
|
|
ret = RETURN_OK;
|
|
exit:
|
|
kfree(get_sfp_info_sts);
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_get_port_info(void *v_hba)
|
|
{
|
|
unsigned long flags = 0;
|
|
struct hifc_inmbox_get_port_info_s get_port_info;
|
|
union hifc_outmbox_generic_u *port_info_sts = NULL;
|
|
struct hifc_hba_s *hba = (struct hifc_hba_s *)v_hba;
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
|
|
memset(&get_port_info, 0, sizeof(get_port_info));
|
|
port_info_sts = kmalloc(sizeof(union hifc_outmbox_generic_u),
|
|
GFP_ATOMIC);
|
|
if (!port_info_sts) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR, "malloc outmbox memory failed");
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
memset(port_info_sts, 0, sizeof(union hifc_outmbox_generic_u));
|
|
|
|
get_port_info.header.cmnd_type = HIFC_MBOX_GET_PORT_INFO;
|
|
get_port_info.header.length =
|
|
HIFC_BYTES_TO_DW_NUM(sizeof(struct hifc_inmbox_get_port_info_s));
|
|
get_port_info.header.port_id = hba->port_index;
|
|
|
|
if (hifc_mb_send_and_wait_mbox(hba, &get_port_info,
|
|
sizeof(get_port_info), port_info_sts) !=
|
|
RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_WARN, UNF_LOG_REG_ATT, UNF_WARN,
|
|
"Port(0x%x) send and wait mailbox type(0x%x) failed.",
|
|
hba->port_cfg.port_id,
|
|
get_port_info.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if ((port_info_sts->get_port_info_sts.status != STATUS_OK) ||
|
|
(port_info_sts->get_port_info_sts.header.cmnd_type !=
|
|
HIFC_MBOX_GET_PORT_INFO_STS)) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_WARN, UNF_LOG_REG_ATT, UNF_WARN,
|
|
"Port(0x%x) receive mailbox type(0x%x) status(0x%x) error.",
|
|
hba->port_cfg.port_id,
|
|
port_info_sts->get_port_info_sts.header.cmnd_type,
|
|
port_info_sts->get_port_info_sts.status);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
spin_lock_irqsave(&hba->hba_lock, flags);
|
|
hba->active_bb_scn = port_info_sts->get_port_info_sts.bbscn;
|
|
hba->active_rx_bb_credit =
|
|
port_info_sts->get_port_info_sts.non_loop_rx_credit;
|
|
spin_unlock_irqrestore(&hba->hba_lock, flags);
|
|
|
|
ret = RETURN_OK;
|
|
exit:
|
|
kfree(port_info_sts);
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_get_port_current_info(void *v_hba, void *port_info)
|
|
{
|
|
struct hifc_hba_s *hba = NULL;
|
|
struct hifc_inmbox_get_port_info_s get_port_info;
|
|
union hifc_outmbox_generic_u *port_info_sts = NULL;
|
|
struct unf_get_port_info_argout *current_port_info = NULL;
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, port_info, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, v_hba, return UNF_RETURN_ERROR);
|
|
|
|
hba = (struct hifc_hba_s *)v_hba;
|
|
current_port_info = (struct unf_get_port_info_argout *)port_info;
|
|
|
|
memset(&get_port_info, 0, sizeof(get_port_info));
|
|
port_info_sts = kmalloc(sizeof(union hifc_outmbox_generic_u),
|
|
GFP_ATOMIC);
|
|
if (!port_info_sts) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR, "malloc outmbox memory failed");
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
memset(port_info_sts, 0, sizeof(union hifc_outmbox_generic_u));
|
|
|
|
get_port_info.header.cmnd_type = HIFC_MBOX_GET_PORT_INFO;
|
|
get_port_info.header.length =
|
|
HIFC_BYTES_TO_DW_NUM(sizeof(struct hifc_inmbox_get_port_info_s));
|
|
get_port_info.header.port_id = hba->port_index;
|
|
|
|
if (hifc_mb_send_and_wait_mbox(hba, &get_port_info,
|
|
sizeof(get_port_info),
|
|
port_info_sts) != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_WARN, UNF_LOG_REG_ATT, UNF_WARN,
|
|
"[warn]Port(0x%x) send and wait mailbox type(0x%x) failed",
|
|
hba->port_cfg.port_id,
|
|
get_port_info.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if ((port_info_sts->get_port_info_sts.status != STATUS_OK) ||
|
|
(port_info_sts->get_port_info_sts.header.cmnd_type !=
|
|
HIFC_MBOX_GET_PORT_INFO_STS)) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_WARN, UNF_LOG_REG_ATT, UNF_WARN,
|
|
"Port(0x%x) receive mailbox type(0x%x) status(0x%x) error.",
|
|
hba->port_cfg.port_id,
|
|
port_info_sts->get_port_info_sts.header.cmnd_type,
|
|
port_info_sts->get_port_info_sts.status);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
current_port_info->sfp_speed =
|
|
(unsigned char)port_info_sts->get_port_info_sts.sfp_speed;
|
|
current_port_info->present =
|
|
(unsigned char)port_info_sts->get_port_info_sts.present;
|
|
|
|
ret = RETURN_OK;
|
|
exit:
|
|
kfree(port_info_sts);
|
|
return ret;
|
|
}
|
|
|
|
static void hifc_get_fabric_login_params(
|
|
struct hifc_hba_s *hba,
|
|
struct unf_port_login_parms_s *v_param_addr)
|
|
{
|
|
unsigned long flag = 0;
|
|
|
|
spin_lock_irqsave(&hba->hba_lock, flag);
|
|
hba->active_topo = v_param_addr->en_act_topo;
|
|
hba->compared_ratov_val = v_param_addr->compared_ratov_val;
|
|
hba->compared_edtov_val = v_param_addr->compared_edtov_val;
|
|
hba->compared_bbscn = v_param_addr->compared_bbscn;
|
|
hba->remote_edtov_tag = v_param_addr->remote_edtov_tag;
|
|
hba->remote_rttov_tag = v_param_addr->remote_rttov_tag;
|
|
hba->remote_bbcredit = v_param_addr->remote_bbcredit;
|
|
spin_unlock_irqrestore(&hba->hba_lock, flag);
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_LOGIN_ATT, UNF_INFO,
|
|
"[info]Port(0x%x) topo(0x%x) get fabric params: R_A_TOV(0x%x) E_D_TOV(%u) BB_CREDIT(0x%x) BB_SC_N(0x%x)",
|
|
hba->port_cfg.port_id, hba->active_topo,
|
|
hba->compared_ratov_val, hba->compared_edtov_val,
|
|
hba->remote_bbcredit, hba->compared_bbscn);
|
|
}
|
|
|
|
static void hifc_get_port_login_params(
|
|
struct hifc_hba_s *hba,
|
|
struct unf_port_login_parms_s *v_param_addr)
|
|
{
|
|
unsigned long flag = 0;
|
|
|
|
spin_lock_irqsave(&hba->hba_lock, flag);
|
|
hba->compared_ratov_val = v_param_addr->compared_ratov_val;
|
|
hba->compared_edtov_val = v_param_addr->compared_edtov_val;
|
|
hba->compared_bbscn = v_param_addr->compared_bbscn;
|
|
hba->remote_edtov_tag = v_param_addr->remote_edtov_tag;
|
|
hba->remote_rttov_tag = v_param_addr->remote_rttov_tag;
|
|
hba->remote_bbcredit = v_param_addr->remote_bbcredit;
|
|
spin_unlock_irqrestore(&hba->hba_lock, flag);
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_LOGIN_ATT, UNF_MAJOR,
|
|
"Port(0x%x) Topo(0x%x) Get Port Params: R_A_TOV(0x%x), E_D_TOV(0x%x), BB_CREDIT(0x%x), BB_SC_N(0x%x).",
|
|
hba->port_cfg.port_id, hba->active_topo,
|
|
hba->compared_ratov_val, hba->compared_edtov_val,
|
|
hba->remote_bbcredit, hba->compared_bbscn);
|
|
}
|
|
|
|
unsigned int hifc_update_fabric_param(void *v_hba, void *v_para_in)
|
|
{
|
|
unsigned int ret = RETURN_OK;
|
|
struct hifc_hba_s *hba = v_hba;
|
|
struct unf_port_login_parms_s *login_coparms = v_para_in;
|
|
|
|
UNF_CHECK_VALID(0x4923, UNF_B_TRUE, hba, return UNF_RETURN_ERROR);
|
|
UNF_CHECK_VALID(0x4924, UNF_B_TRUE, v_para_in, return UNF_RETURN_ERROR);
|
|
|
|
hifc_get_fabric_login_params(hba, login_coparms);
|
|
|
|
if ((hba->active_topo == UNF_ACT_TOP_P2P_FABRIC) ||
|
|
(hba->active_topo == UNF_ACT_TOP_PUBLIC_LOOP)) {
|
|
if (hba->work_mode == HIFC_SMARTIO_WORK_MODE_FC)
|
|
ret = hifc_config_login_api(hba, login_coparms);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_update_port_param(void *v_hba, void *v_para_in)
|
|
{
|
|
unsigned int ret = RETURN_OK;
|
|
struct hifc_hba_s *hba = v_hba;
|
|
struct unf_port_login_parms_s *login_coparms =
|
|
(struct unf_port_login_parms_s *)v_para_in;
|
|
|
|
UNF_CHECK_VALID(0x4923, UNF_B_TRUE, hba, return UNF_RETURN_ERROR);
|
|
UNF_CHECK_VALID(0x4924, UNF_B_TRUE, v_para_in, return UNF_RETURN_ERROR);
|
|
|
|
if ((hba->active_topo == UNF_ACT_TOP_PRIVATE_LOOP) ||
|
|
(hba->active_topo == UNF_ACT_TOP_P2P_DIRECT)) {
|
|
hifc_get_port_login_params(hba, login_coparms);
|
|
ret = hifc_config_login_api(hba, login_coparms);
|
|
}
|
|
|
|
hifc_save_login_para_in_sq_info(hba, login_coparms);
|
|
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_clear_port_error_code(void *v_hba, void *v_err_code)
|
|
{
|
|
return RETURN_OK;
|
|
}
|
|
|
|
unsigned int hifc_get_and_clear_port_error_code(void *v_hba, void *v_err_code)
|
|
{
|
|
struct hifc_hba_s *hba = (struct hifc_hba_s *)v_hba;
|
|
struct hifc_inmbox_get_err_code_s get_err_code;
|
|
union hifc_outmbox_generic_u *err_code_sts = NULL;
|
|
struct unf_err_code_s *unf_err_code =
|
|
(struct unf_err_code_s *)v_err_code;
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, hba, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, unf_err_code, return UNF_RETURN_ERROR);
|
|
|
|
memset(&get_err_code, 0, sizeof(get_err_code));
|
|
|
|
err_code_sts = kmalloc(sizeof(union hifc_outmbox_generic_u),
|
|
GFP_ATOMIC);
|
|
if (!err_code_sts) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR, "malloc outmbox memory failed");
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
memset(err_code_sts, 0, sizeof(union hifc_outmbox_generic_u));
|
|
|
|
get_err_code.header.cmnd_type = HIFC_MBOX_GET_ERR_CODE;
|
|
get_err_code.header.length =
|
|
HIFC_BYTES_TO_DW_NUM(sizeof(struct hifc_inmbox_get_err_code_s));
|
|
|
|
if (hifc_mb_send_and_wait_mbox(hba, &get_err_code, sizeof(get_err_code),
|
|
err_code_sts) != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_REG_ATT, UNF_INFO,
|
|
"Port(0x%x) HIFC can't send and wait mailbox, command type: 0x%x.",
|
|
hba->port_cfg.port_id,
|
|
get_err_code.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (err_code_sts->get_err_code_sts.status != STATUS_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_REG_ATT, UNF_INFO,
|
|
"Port(0x%x) Receive mailbox type(0x%x) status incorrect, status: 0x%x.",
|
|
hba->port_cfg.port_id,
|
|
err_code_sts->get_err_code_sts.header.cmnd_type,
|
|
err_code_sts->get_err_code_sts.status);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
unf_err_code->link_fail_count =
|
|
err_code_sts->get_err_code_sts.err_code[0];
|
|
unf_err_code->loss_of_sync_count =
|
|
err_code_sts->get_err_code_sts.err_code[1];
|
|
unf_err_code->loss_of_signal_count =
|
|
err_code_sts->get_err_code_sts.err_code[2];
|
|
unf_err_code->proto_error_count =
|
|
err_code_sts->get_err_code_sts.err_code[3];
|
|
unf_err_code->bad_rx_char_count =
|
|
err_code_sts->get_err_code_sts.err_code[4];
|
|
unf_err_code->bad_crc_count =
|
|
err_code_sts->get_err_code_sts.err_code[5];
|
|
unf_err_code->rx_eo_fa_count =
|
|
err_code_sts->get_err_code_sts.err_code[6];
|
|
unf_err_code->dis_frame_count =
|
|
err_code_sts->get_err_code_sts.err_code[7];
|
|
|
|
ret = RETURN_OK;
|
|
exit:
|
|
kfree(err_code_sts);
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_get_work_bale_bbcredit(void *v_hba, void *v_bbcredit)
|
|
{
|
|
unsigned int *bb_credit = (unsigned int *)v_bbcredit;
|
|
struct hifc_hba_s *hba = v_hba;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, hba, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, v_bbcredit, return UNF_RETURN_ERROR);
|
|
|
|
if (hba->active_port_speed == UNF_PORT_SPEED_32_G)
|
|
*bb_credit = HIFC_LOWLEVEL_DEFAULT_32G_BB_CREDIT;
|
|
else if (hba->active_port_speed == UNF_PORT_SPEED_16_G)
|
|
*bb_credit = HIFC_LOWLEVEL_DEFAULT_16G_BB_CREDIT;
|
|
else
|
|
*bb_credit = HIFC_LOWLEVEL_DEFAULT_842G_BB_CREDIT;
|
|
|
|
return RETURN_OK;
|
|
}
|
|
|
|
unsigned int hifc_get_work_bale_bbscn(void *v_hba, void *v_bbscn)
|
|
{
|
|
unsigned int *bbscn = (unsigned int *)v_bbscn;
|
|
struct hifc_hba_s *hba = (struct hifc_hba_s *)v_hba;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, v_hba, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, v_bbscn, return UNF_RETURN_ERROR);
|
|
|
|
*bbscn = hba->port_bbscn_cfg;
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_REG_ATT, UNF_INFO, "Return BBSCN(0x%x) to CM",
|
|
*bbscn);
|
|
|
|
return RETURN_OK;
|
|
}
|
|
|
|
unsigned int hifc_get_software_version(void *v_hba, void *v_version)
|
|
{
|
|
struct hifc_hba_s *hba = (struct hifc_hba_s *)v_hba;
|
|
struct hifc_inmbox_get_fw_version_s fw_ver;
|
|
union hifc_outmbox_generic_u *fw_ver_sts = NULL;
|
|
unsigned char *ver = NULL;
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, v_version, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, hba, return UNF_RETURN_ERROR);
|
|
|
|
memset(&fw_ver, 0, sizeof(fw_ver));
|
|
fw_ver_sts = kmalloc(sizeof(union hifc_outmbox_generic_u), GFP_ATOMIC);
|
|
if (!fw_ver_sts) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR, "malloc outmbox memory failed");
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
memset(fw_ver_sts, 0, sizeof(union hifc_outmbox_generic_u));
|
|
ver = (unsigned char *)&fw_ver_sts->get_fw_ver_sts;
|
|
|
|
fw_ver.header.cmnd_type = HIFC_MBOX_GET_FW_VERSION;
|
|
fw_ver.header.length =
|
|
HIFC_BYTES_TO_DW_NUM(sizeof(struct hifc_inmbox_get_fw_version_s));
|
|
|
|
if (hifc_mb_send_and_wait_mbox(hba, &fw_ver, sizeof(fw_ver),
|
|
fw_ver_sts) != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"Port(0x%x) can't send and wait mailbox, command type: 0x%x.",
|
|
hba->port_cfg.port_id,
|
|
fw_ver.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (fw_ver_sts->get_fw_ver_sts.header.cmnd_type !=
|
|
HIFC_MBOX_GET_FW_VERSION_STS) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
|
|
"Port(0x%x) recv mailbox type(0x%x) incorrect.",
|
|
hba->port_cfg.port_id,
|
|
fw_ver_sts->get_fw_ver_sts.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (fw_ver_sts->get_fw_ver_sts.status != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
|
|
"Port(0x%x) Receive mailbox type(0x%x) status(0x%x) incorrect.",
|
|
hba->port_cfg.port_id,
|
|
fw_ver_sts->get_fw_ver_sts.header.cmnd_type,
|
|
fw_ver_sts->get_fw_ver_sts.status);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
memcpy(v_version, ver + HIFC_VER_ADDR_OFFSET,
|
|
sizeof(struct hifc_outmbox_get_fw_version_sts_s) -
|
|
HIFC_VER_ADDR_OFFSET);
|
|
|
|
ret = RETURN_OK;
|
|
exit:
|
|
kfree(fw_ver_sts);
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_get_firmware_version(void *v_fc_port, void *v_version)
|
|
{
|
|
struct hifc_hba_s *fc_port = (struct hifc_hba_s *)v_fc_port;
|
|
struct unf_version_str_s *version =
|
|
(struct unf_version_str_s *)v_version;
|
|
char *fw_ver = NULL;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, version, return UNF_RETURN_ERROR);
|
|
fw_ver = version->buf;
|
|
HIFC_CHECK(INVALID_VALUE32, fw_ver, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, fc_port, return UNF_RETURN_ERROR);
|
|
|
|
fw_ver[UNF_FW_VERSION_LEN - 1] = 0;
|
|
|
|
return RETURN_OK;
|
|
}
|
|
|
|
unsigned int hifc_get_loop_map(void *v_hba, void *v_buf)
|
|
{
|
|
unsigned long flags = 0;
|
|
struct unf_buf_s *buf = (struct unf_buf_s *)v_buf;
|
|
struct hifc_hba_s *hba = v_hba;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, hba, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, buf, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, buf->cbuf, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, buf->buf_len, return UNF_RETURN_ERROR);
|
|
|
|
if (buf->buf_len > UNF_LOOPMAP_COUNT)
|
|
return UNF_RETURN_ERROR;
|
|
|
|
spin_lock_irqsave(&hba->hba_lock, flags);
|
|
if (hba->loop_map_valid != LOOP_MAP_VALID) {
|
|
spin_unlock_irqrestore(&hba->hba_lock, flags);
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
memcpy(buf->cbuf, hba->loop_map, buf->buf_len); /* do memcpy */
|
|
spin_unlock_irqrestore(&hba->hba_lock, flags);
|
|
|
|
return RETURN_OK;
|
|
}
|
|
|
|
unsigned int hifc_get_speed_cfg(void *v_hba, void *v_speed_cfg)
|
|
{
|
|
struct hifc_hba_s *hba = v_hba;
|
|
unsigned int *speed_cfg = v_speed_cfg;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, hba, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, v_speed_cfg, return UNF_RETURN_ERROR);
|
|
|
|
*speed_cfg = hba->port_speed_cfg;
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_REG_ATT, UNF_INFO,
|
|
"Get config link rate: 0x%x.",
|
|
*speed_cfg);
|
|
|
|
return RETURN_OK;
|
|
}
|
|
|
|
unsigned int hifc_get_speed_act(void *v_hba, void *v_speed_act)
|
|
{
|
|
struct hifc_hba_s *hba = v_hba;
|
|
unsigned int *speed_act = v_speed_act;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, hba, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, v_speed_act, return UNF_RETURN_ERROR);
|
|
|
|
*speed_act = hba->active_port_speed;
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
|
|
"Get config link rate: 0x%x.",
|
|
*speed_act);
|
|
return RETURN_OK;
|
|
}
|
|
|
|
unsigned int hifc_get_port_fec(void *v_hba, void *v_para_out)
|
|
{
|
|
struct hifc_hba_s *hba = v_hba;
|
|
int *fec = v_para_out;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, hba, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, fec, return UNF_RETURN_ERROR);
|
|
|
|
*fec = (hba->fec_status) ? UNF_TRUE : UNF_FALSE;
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
|
|
"Get Port fec: 0x%x.",
|
|
(hba->fec_status));
|
|
return RETURN_OK;
|
|
}
|
|
|
|
unsigned int hifc_save_hba_info(void *v_hba, void *v_para_in)
|
|
{
|
|
struct hifc_inmbox_save_hba_info_s *hba_info = NULL;
|
|
struct hifc_outmbox_save_hba_info_sts_s *hba_info_sts = NULL;
|
|
void *hba_info_addr = v_para_in;
|
|
struct hifc_hba_s *hba = v_hba;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, v_hba, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, v_para_in, return UNF_RETURN_ERROR);
|
|
|
|
hba_info = vmalloc(sizeof(struct hifc_inmbox_save_hba_info_s));
|
|
|
|
if (!hba_info)
|
|
return UNF_RETURN_ERROR;
|
|
|
|
hba_info_sts = vmalloc(sizeof(struct hifc_outmbox_save_hba_info_sts_s));
|
|
|
|
if (!hba_info_sts) {
|
|
vfree(hba_info);
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
|
|
memset(hba_info, 0, sizeof(struct hifc_inmbox_save_hba_info_s));
|
|
memset(hba_info_sts, 0,
|
|
sizeof(struct hifc_outmbox_save_hba_info_sts_s));
|
|
|
|
hba_info->header.cmnd_type = HIFC_MBOX_SAVE_HBA_INFO;
|
|
hba_info->header.length =
|
|
HIFC_BYTES_TO_DW_NUM(sizeof(struct hifc_inmbox_save_hba_info_s));
|
|
|
|
/* fill mailbox payload */
|
|
memcpy(&hba_info->hba_save_info[0], hba_info_addr, SAVE_PORT_INFO_LEN);
|
|
|
|
/* send & wait mailbox */
|
|
if (hifc_mb_send_and_wait_mbox(
|
|
hba, hba_info,
|
|
sizeof(*hba_info),
|
|
(union hifc_outmbox_generic_u *)hba_info_sts)
|
|
!= RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"[warn]Port(0x%x) HIFC can't send and wait mailbox, command type(0x%x)",
|
|
hba->port_cfg.port_id,
|
|
hba_info->header.cmnd_type);
|
|
|
|
vfree(hba_info);
|
|
vfree(hba_info_sts);
|
|
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
|
|
/* check mailbox rsp status */
|
|
if (hba_info_sts->status != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
|
|
"[err]Port(0x%x) receive mailbox type(0x%x) status(0x%x) error",
|
|
hba->port_cfg.port_id,
|
|
hba_info_sts->header.cmnd_type,
|
|
hba_info_sts->status);
|
|
|
|
vfree(hba_info);
|
|
vfree(hba_info_sts);
|
|
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
|
|
/* check mailbox rsp type */
|
|
if (hba_info_sts->header.cmnd_type != HIFC_MBOX_SAVE_HBA_INFO_STS) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
|
|
"[err]Port(0x%x) receive mailbox type(0x%x) error",
|
|
hba->port_cfg.port_id,
|
|
hba_info_sts->header.cmnd_type);
|
|
|
|
vfree(hba_info);
|
|
vfree(hba_info_sts);
|
|
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
|
|
memcpy(hba_info_addr, &hba_info_sts->save_hba_info[0],
|
|
SAVE_PORT_INFO_LEN - 8);
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
|
|
"[event]Port(0x%x) save hba info succeed",
|
|
hba->port_cfg.port_id);
|
|
|
|
vfree(hba_info);
|
|
vfree(hba_info_sts);
|
|
|
|
return RETURN_OK;
|
|
}
|
|
|
|
unsigned int hifc_mbox_reset_chip(struct hifc_hba_s *v_hba,
|
|
unsigned char v_sub_type)
|
|
{
|
|
struct hifc_inmbox_port_reset_s port_reset;
|
|
union hifc_outmbox_generic_u *port_reset_sts = NULL;
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, v_hba, return UNF_RETURN_ERROR);
|
|
|
|
memset(&port_reset, 0, sizeof(port_reset));
|
|
|
|
port_reset_sts = kmalloc(sizeof(union hifc_outmbox_generic_u),
|
|
GFP_ATOMIC);
|
|
if (!port_reset_sts) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR, "malloc outmbox memory failed");
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
memset(port_reset_sts, 0, sizeof(union hifc_outmbox_generic_u));
|
|
port_reset.header.cmnd_type = HIFC_MBOX_PORT_RESET;
|
|
port_reset.header.length =
|
|
HIFC_BYTES_TO_DW_NUM(sizeof(struct hifc_inmbox_port_reset_s));
|
|
port_reset.op_code = v_sub_type;
|
|
|
|
if (hifc_mb_send_and_wait_mbox(v_hba, &port_reset, sizeof(port_reset),
|
|
port_reset_sts) != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"[warn]Port(0x%x) can't send and wait mailbox with command type(0x%x)",
|
|
v_hba->port_cfg.port_id,
|
|
port_reset.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (port_reset_sts->port_reset_sts.status != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
|
|
"[warn]Port(0x%x) receive mailbox type(0x%x) status(0x%x) incorrect",
|
|
v_hba->port_cfg.port_id,
|
|
port_reset_sts->port_reset_sts.header.cmnd_type,
|
|
port_reset_sts->port_reset_sts.status);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (port_reset_sts->port_reset_sts.header.cmnd_type !=
|
|
HIFC_MBOX_PORT_RESET_STS) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
|
|
"[warn]Port(0x%x) recv mailbox type(0x%x) incorrect",
|
|
v_hba->port_cfg.port_id,
|
|
port_reset_sts->port_reset_sts.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
|
|
"[info]Port(0x%x) reset chip mailbox success",
|
|
v_hba->port_cfg.port_id);
|
|
|
|
ret = RETURN_OK;
|
|
exit:
|
|
kfree(port_reset_sts);
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_clear_sq_wqe_done(struct hifc_hba_s *v_hba)
|
|
{
|
|
int async_ret = RETURN_OK;
|
|
struct hifc_inmbx_clear_node_s clear_done;
|
|
|
|
clear_done.header.cmnd_type = HIFC_MBOX_BUFFER_CLEAR_DONE;
|
|
clear_done.header.length =
|
|
HIFC_BYTES_TO_DW_NUM(sizeof(struct hifc_inmbx_clear_node_s));
|
|
clear_done.header.port_id = v_hba->port_index;
|
|
|
|
async_ret = hifc_msg_to_mgmt_async(v_hba->hw_dev_handle,
|
|
HIFC_MOD_FC,
|
|
HIFC_MBOX_BUFFER_CLEAR_DONE,
|
|
&clear_done, sizeof(clear_done));
|
|
|
|
if (async_ret != 0) {
|
|
HIFC_MAILBOX_STAT(v_hba, HIFC_SEND_CLEAR_DONE_FAIL);
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"[err]HIFC Port(0x%x) can't send clear done cmd to up, ret:%d",
|
|
v_hba->port_cfg.port_id, async_ret);
|
|
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
|
|
HIFC_MAILBOX_STAT(v_hba, HIFC_SEND_CLEAR_DONE);
|
|
v_hba->q_set_stage = HIFC_QUEUE_SET_STAGE_FLUSHDONE;
|
|
v_hba->next_clearing_sq = 0;
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_EVENT, UNF_KEVENT,
|
|
"[info]Port(0x%x) clear done msg(0x%x) sent to up succeed with stage(0x%x)",
|
|
v_hba->port_cfg.port_id,
|
|
clear_done.header.cmnd_type, v_hba->q_set_stage);
|
|
|
|
return RETURN_OK;
|
|
}
|
|
|
|
unsigned int hifc_mbx_get_fw_clear_stat(struct hifc_hba_s *v_hba,
|
|
unsigned int *v_clear_state)
|
|
{
|
|
struct hifc_inmbox_get_clear_state_s clr_state;
|
|
union hifc_outmbox_generic_u *port_clr_state_sts = NULL;
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, v_hba, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, v_clear_state, return UNF_RETURN_ERROR);
|
|
|
|
memset(&clr_state, 0, sizeof(clr_state));
|
|
|
|
port_clr_state_sts = kmalloc(sizeof(union hifc_outmbox_generic_u),
|
|
GFP_ATOMIC);
|
|
if (!port_clr_state_sts) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR, "malloc outmbox memory failed");
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
memset(port_clr_state_sts, 0, sizeof(union hifc_outmbox_generic_u));
|
|
|
|
clr_state.header.cmnd_type = HIFC_MBOX_GET_CLEAR_STATE;
|
|
clr_state.header.length =
|
|
HIFC_BYTES_TO_DW_NUM(sizeof(struct hifc_inmbox_get_clear_state_s));
|
|
|
|
if (hifc_mb_send_and_wait_mbox(v_hba, &clr_state, sizeof(clr_state),
|
|
port_clr_state_sts) != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"hifc can't send and wait mailbox, command type: 0x%x",
|
|
clr_state.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (port_clr_state_sts->get_clr_state_sts.status != RETURN_OK) {
|
|
HIFC_TRACE(
|
|
UNF_EVTLOG_LINK_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
|
|
"Port(0x%x) Receive mailbox type(0x%x) status incorrect. Status: 0x%x, state 0x%x.",
|
|
v_hba->port_cfg.port_id,
|
|
port_clr_state_sts->get_clr_state_sts.header.cmnd_type,
|
|
port_clr_state_sts->get_clr_state_sts.status,
|
|
port_clr_state_sts->get_clr_state_sts.state);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (port_clr_state_sts->get_clr_state_sts.header.cmnd_type !=
|
|
HIFC_MBOX_GET_CLEAR_STATE_STS) {
|
|
HIFC_TRACE(
|
|
UNF_EVTLOG_LINK_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
|
|
"Port(0x%x) recv mailbox type(0x%x) incorrect.",
|
|
v_hba->port_cfg.port_id,
|
|
port_clr_state_sts->get_clr_state_sts.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_EVENT, UNF_MAJOR,
|
|
"Port(0x%x) get port clear state 0x%x.",
|
|
v_hba->port_cfg.port_id,
|
|
port_clr_state_sts->get_clr_state_sts.state);
|
|
|
|
*v_clear_state = port_clr_state_sts->get_clr_state_sts.state;
|
|
|
|
ret = RETURN_OK;
|
|
exit:
|
|
kfree(port_clr_state_sts);
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_mbx_set_fec(struct hifc_hba_s *v_hba,
|
|
unsigned int v_fec_opcode)
|
|
{
|
|
struct hifc_inmbox_config_fec_s cfg_fec;
|
|
union hifc_outmbox_generic_u *port_fec_state_sts = NULL;
|
|
unsigned char op_code = 0;
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, v_hba, return UNF_RETURN_ERROR);
|
|
|
|
memset(&cfg_fec, 0, sizeof(cfg_fec));
|
|
|
|
port_fec_state_sts = kmalloc(sizeof(union hifc_outmbox_generic_u),
|
|
GFP_ATOMIC);
|
|
if (!port_fec_state_sts) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR, "malloc outmbox memory failed");
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
memset(port_fec_state_sts, 0, sizeof(union hifc_outmbox_generic_u));
|
|
|
|
op_code = (unsigned char)v_fec_opcode;
|
|
|
|
cfg_fec.header.cmnd_type = HIFC_MBOX_CONFIG_FEC;
|
|
cfg_fec.header.length =
|
|
HIFC_BYTES_TO_DW_NUM(sizeof(HIFC_MBOX_CONFIG_FEC));
|
|
cfg_fec.fec_op_code = op_code;
|
|
|
|
if (hifc_mb_send_and_wait_mbox(v_hba, &cfg_fec, sizeof(cfg_fec),
|
|
port_fec_state_sts) != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"Port(0x%x) hifc can't send and wait mailbox, command type: 0x%x",
|
|
v_hba->port_cfg.port_id, cfg_fec.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (port_fec_state_sts->config_fec_sts.status != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
|
|
"Port(0x%x) Receive mailbox type(0x%x) status incorrect. Status: 0x%x.",
|
|
v_hba->port_cfg.port_id,
|
|
port_fec_state_sts->config_fec_sts.header.cmnd_type,
|
|
port_fec_state_sts->config_fec_sts.status);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (port_fec_state_sts->config_fec_sts.header.cmnd_type !=
|
|
HIFC_MBOX_CONFIG_FEC_STS) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
|
|
"Port(0x%x) recv mailbox type(0x%x) incorrect.",
|
|
v_hba->port_cfg.port_id,
|
|
port_fec_state_sts->config_fec_sts.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
v_hba->fec_status = v_fec_opcode;
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_EVENT, UNF_MAJOR,
|
|
"Port(0x%x) set FEC Status is %u.",
|
|
v_hba->port_cfg.port_id, op_code);
|
|
|
|
ret = RETURN_OK;
|
|
exit:
|
|
kfree(port_fec_state_sts);
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_notify_up_config_timer(struct hifc_hba_s *v_hba, int op_code,
|
|
unsigned int user_data)
|
|
{
|
|
struct hifc_inmbox_config_timer_s time_cfg;
|
|
union hifc_outmbox_generic_u *time_cfg_sts = NULL;
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, v_hba, return UNF_RETURN_ERROR);
|
|
|
|
memset(&time_cfg, 0, sizeof(time_cfg));
|
|
|
|
time_cfg_sts = kmalloc(sizeof(union hifc_outmbox_generic_u),
|
|
GFP_ATOMIC);
|
|
if (!time_cfg_sts) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR, "malloc outmbox memory failed");
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
memset(time_cfg_sts, 0, sizeof(union hifc_outmbox_generic_u));
|
|
time_cfg.header.cmnd_type = HIFC_MBOX_CONFIG_TIMER;
|
|
time_cfg.header.length =
|
|
HIFC_BYTES_TO_DW_NUM(sizeof(struct hifc_inmbox_config_timer_s));
|
|
time_cfg.op_code = (unsigned short)op_code;
|
|
time_cfg.fun_id = hifc_global_func_id(v_hba->hw_dev_handle);
|
|
time_cfg.user_data = user_data;
|
|
|
|
if (hifc_mb_send_and_wait_mbox(v_hba, &time_cfg, sizeof(time_cfg),
|
|
time_cfg_sts) != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"[warn]Port(0x%x) hifc can't send and wait mailbox with command type(0x%x)",
|
|
v_hba->port_cfg.port_id, time_cfg.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (time_cfg_sts->timer_config_sts.header.cmnd_type !=
|
|
HIFC_MBOX_CONFIG_TIMER_STS) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
|
|
"[warn]Port(0x%x) recv mailbox type(0x%x) incorrect",
|
|
v_hba->port_cfg.port_id,
|
|
time_cfg_sts->timer_config_sts.header.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (time_cfg_sts->timer_config_sts.status != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
|
|
"[warn]Port(0x%x) Receive mailbox type(0x%x) status(0x%x) incorrect",
|
|
v_hba->port_cfg.port_id,
|
|
time_cfg_sts->timer_config_sts.header.cmnd_type,
|
|
time_cfg_sts->timer_config_sts.status);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_INFO, UNF_LOG_EVENT, UNF_MAJOR,
|
|
"[info]Port(0x%x) notify uP to %s timer success",
|
|
v_hba->port_cfg.port_id, op_code ? "open" : "close");
|
|
|
|
ret = RETURN_OK;
|
|
exit:
|
|
kfree(time_cfg_sts);
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_get_flash_data(void *v_hba, void *v_flash_data)
|
|
{
|
|
struct hifc_hba_s *hba = NULL;
|
|
struct unf_mbox_flash_data_mgmt_s *flash_data_mgmt = NULL;
|
|
union hifc_outmbox_generic_u *flash_data_sts = NULL;
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, v_hba, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, v_flash_data, return UNF_RETURN_ERROR);
|
|
|
|
hba = (struct hifc_hba_s *)v_hba;
|
|
|
|
flash_data_mgmt = kmalloc(sizeof(struct unf_mbox_flash_data_mgmt_s),
|
|
GFP_ATOMIC);
|
|
|
|
if (!flash_data_mgmt) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_WARN, UNF_LOG_REG_ATT, UNF_KEVENT,
|
|
"can't malloc buff for set flashData.");
|
|
return ret;
|
|
}
|
|
flash_data_sts = kmalloc(sizeof(struct unf_flash_data_mgmt_sts_s),
|
|
GFP_ATOMIC);
|
|
|
|
if (!flash_data_sts) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_WARN, UNF_LOG_REG_ATT, UNF_KEVENT,
|
|
"can't malloc buff for set flashData sts.");
|
|
kfree(flash_data_mgmt);
|
|
return ret;
|
|
}
|
|
memset(flash_data_mgmt, 0, sizeof(struct unf_mbox_flash_data_mgmt_s));
|
|
memset(flash_data_sts, 0, sizeof(struct unf_flash_data_mgmt_sts_s));
|
|
flash_data_mgmt->mbox_head.cmnd_type = HIFC_MBOX_FLASH_DATA_MGMT;
|
|
flash_data_mgmt->mbox_head.length = 1; /* not used */
|
|
flash_data_mgmt->mbox_head.op_code = 0; /* read config */
|
|
|
|
if (hifc_mb_send_and_wait_mbox(
|
|
hba, flash_data_mgmt,
|
|
sizeof(struct unf_mbox_flash_data_mgmt_s),
|
|
flash_data_sts) != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"hifc can't send and wait mailbox, command type: 0x%x.",
|
|
flash_data_mgmt->mbox_head.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (flash_data_sts->flash_data_sts.mbox_head.status != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"Port(0x%x) mailbox status incorrect status(0x%x) .",
|
|
hba->port_cfg.port_id,
|
|
flash_data_sts->flash_data_sts.mbox_head.status);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (flash_data_sts->flash_data_sts.mbox_head.cmnd_type !=
|
|
HIFC_MBOX_FLASH_DATA_MGMT_STS) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"Port(0x%x) receive mailbox type incorrect type: 0x%x.",
|
|
hba->port_cfg.port_id,
|
|
flash_data_sts->flash_data_sts.mbox_head.cmnd_type);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
memcpy((unsigned char *)v_flash_data,
|
|
(unsigned char *)&flash_data_sts->flash_data_sts.flash_data,
|
|
sizeof(struct unf_flash_data_s));
|
|
ret = RETURN_OK;
|
|
exit:
|
|
kfree(flash_data_mgmt);
|
|
kfree(flash_data_sts);
|
|
return ret;
|
|
}
|
|
|
|
unsigned int hifc_set_flash_data(void *v_hba, void *v_flash_data)
|
|
{
|
|
struct hifc_hba_s *hba = NULL;
|
|
struct unf_mbox_flash_data_mgmt_s *flash_data_mgmt = NULL;
|
|
union hifc_outmbox_generic_u *flash_data_sts = NULL;
|
|
unsigned int ret = UNF_RETURN_ERROR;
|
|
|
|
HIFC_CHECK(INVALID_VALUE32, v_hba, return UNF_RETURN_ERROR);
|
|
HIFC_CHECK(INVALID_VALUE32, v_flash_data, return UNF_RETURN_ERROR);
|
|
|
|
hba = (struct hifc_hba_s *)v_hba;
|
|
flash_data_mgmt = kmalloc(sizeof(struct unf_mbox_flash_data_mgmt_s),
|
|
GFP_ATOMIC);
|
|
|
|
if (!flash_data_mgmt) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_KEVENT,
|
|
"can't malloc buff for set flashData.");
|
|
return ret;
|
|
}
|
|
flash_data_sts = kmalloc(sizeof(union hifc_outmbox_generic_u),
|
|
GFP_ATOMIC);
|
|
|
|
if (!flash_data_sts) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_KEVENT,
|
|
"can't malloc buff for set flashData sts.");
|
|
kfree(flash_data_mgmt);
|
|
return ret;
|
|
}
|
|
memset(flash_data_sts, 0, sizeof(union hifc_outmbox_generic_u));
|
|
memset(flash_data_mgmt, 0, sizeof(struct unf_mbox_flash_data_mgmt_s));
|
|
flash_data_mgmt->mbox_head.cmnd_type = HIFC_MBOX_FLASH_DATA_MGMT;
|
|
flash_data_mgmt->mbox_head.length = 1; /* not used */
|
|
flash_data_mgmt->mbox_head.op_code = 2; /* flash config */
|
|
|
|
if (hifc_mb_send_and_wait_mbox(
|
|
hba, flash_data_mgmt,
|
|
sizeof(struct unf_mbox_flash_data_mgmt_s),
|
|
flash_data_sts) != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_KEVENT,
|
|
"hifc can't send and wait mailbox, command type: 0x%x.",
|
|
flash_data_sts->flash_data_sts.mbox_head.cmnd_type);
|
|
|
|
goto END;
|
|
}
|
|
|
|
if (flash_data_sts->flash_data_sts.mbox_head.status != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_KEVENT,
|
|
"Port(0x%x) mailbox status incorrect status(0x%x) .",
|
|
hba->port_cfg.port_id,
|
|
flash_data_sts->flash_data_sts.mbox_head.status);
|
|
|
|
goto END;
|
|
}
|
|
|
|
if (flash_data_sts->flash_data_sts.mbox_head.cmnd_type !=
|
|
HIFC_MBOX_FLASH_DATA_MGMT_STS) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_KEVENT,
|
|
"Port(0x%x) receive mailbox type incorrect type: 0x%x.",
|
|
hba->port_cfg.port_id,
|
|
flash_data_sts->flash_data_sts.mbox_head.cmnd_type);
|
|
|
|
goto END;
|
|
}
|
|
flash_data_mgmt->mbox_head.cmnd_type = HIFC_MBOX_FLASH_DATA_MGMT;
|
|
flash_data_mgmt->mbox_head.length = 1; /* not used */
|
|
flash_data_mgmt->mbox_head.op_code = 1; /* write config */
|
|
memcpy(&flash_data_mgmt->flash_data,
|
|
(unsigned char *)v_flash_data, sizeof(struct unf_flash_data_s));
|
|
|
|
if (hifc_mb_send_and_wait_mbox(
|
|
hba, flash_data_mgmt,
|
|
sizeof(struct unf_mbox_flash_data_mgmt_s),
|
|
flash_data_sts) != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"hifc can't send and wait mailbox, command type: 0x%x.",
|
|
flash_data_sts->flash_data_sts.mbox_head.cmnd_type);
|
|
|
|
goto END;
|
|
}
|
|
|
|
if (flash_data_sts->flash_data_sts.mbox_head.status != RETURN_OK) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_KEVENT,
|
|
"Port(0x%x) mailbox status incorrect status(0x%x) .",
|
|
hba->port_cfg.port_id,
|
|
flash_data_sts->flash_data_sts.mbox_head.status);
|
|
|
|
goto END;
|
|
}
|
|
|
|
if (flash_data_sts->flash_data_sts.mbox_head.cmnd_type !=
|
|
HIFC_MBOX_FLASH_DATA_MGMT_STS) {
|
|
HIFC_TRACE(UNF_EVTLOG_LINK_ERR, UNF_LOG_REG_ATT, UNF_KEVENT,
|
|
"Port(0x%x) receive mailbox type incorrect type: 0x%x.",
|
|
hba->port_cfg.port_id,
|
|
flash_data_sts->flash_data_sts.mbox_head.cmnd_type);
|
|
|
|
goto END;
|
|
}
|
|
ret = RETURN_OK;
|
|
END:
|
|
kfree(flash_data_mgmt);
|
|
kfree(flash_data_sts);
|
|
return ret;
|
|
}
|