hifc/hifc/unf_portman.c

5566 lines
165 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Huawei Hifc PCI Express Linux driver
* Copyright(c) 2017 Huawei Technologies Co., Ltd
*
*/
#include "unf_log.h"
#include "unf_common.h"
#include "unf_event.h"
#include "unf_lport.h"
#include "unf_exchg.h"
#include "unf_portman.h"
#include "unf_rport.h"
#include "unf_io.h"
#include "unf_service.h"
#include "unf_rport.h"
#include "unf_npiv.h"
#include "hifc_portmng.h"
#define UNF_LOOP_STOP_NEED_WAIT 0
#define UNF_LOOP_STOP_NO_NEED_WAIT 1
#define UNF_MAX_SAVE_ENTRY_NUM 60
#define UNF_CHECK_CONFIG_SPEED_BY_SFSSPEED(sfs_speed, cfg_speed) \
((sfs_speed) < (cfg_speed) || (sfs_speed) == UNF_PORT_SFP_SPEED_ERR)
#define UNF_LPORT_CHIP_ERROR(lport) \
((lport)->pcie_error_cnt.pcie_error_count[UNF_PCIE_FATALERRORDETECTED])
struct unf_global_lport_s global_lport_mgr;
static unsigned int unf_port_link_up(struct unf_lport_s *v_lport,
void *v_in_put);
static unsigned int unf_port_link_down(struct unf_lport_s *v_lport,
void *v_in_put);
static unsigned int unf_port_abnormal_reset(struct unf_lport_s *v_lport,
void *v_in_put);
static unsigned int unf_port_reset_start(struct unf_lport_s *v_lport,
void *v_in_put);
static unsigned int unf_port_reset_end(struct unf_lport_s *v_lport,
void *v_in_put);
static unsigned int unf_port_nop(struct unf_lport_s *v_lport, void *v_in_put);
static unsigned int unf_port_clean_done(struct unf_lport_s *v_lport,
void *v_in_put);
static unsigned int unf_port_begin_remove(struct unf_lport_s *v_lport,
void *v_in_put);
static unsigned int unf_port_release_rport_index(struct unf_lport_s *v_lport,
void *v_in_put);
static int unf_cm_port_info_get(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_in_put);
static int unf_cm_port_speed_set(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_in_put);
static int unf_cm_topo_set(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_in_put);
static int unf_cm_port_set(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_in_put);
static int unf_get_port_sfp_info(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_in_put);
static int unf_cm_get_all_port_info(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_in_put);
static int unf_cm_clear_error_code_sum(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_in_put);
static int unf_cm_bbscn_set(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_in_put);
static int unf_get_io_dfx_statistics(struct unf_lport_s *v_pstLPort,
struct unf_hinicam_pkg *v_input);
static int unf_cm_set_vport(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_input);
static int unf_cm_link_delay_get(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_in_put);
static int unf_cm_save_data_mode(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_in_put);
static int unf_cm_set_dif(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_in_put);
static int unf_cm_select_dif_mode(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_in_put);
static int unf_cm_adm_show_xchg(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_in_put);
static int unf_cm_adm_link_time_out_opt(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_in_put);
static int unf_cm_adm_log_level_opt(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_in_put);
static struct unf_port_action_s lport_action[] = {
{ UNF_PORT_LINK_UP, unf_port_link_up },
{ UNF_PORT_LINK_DOWN, unf_port_link_down },
{ UNF_PORT_RESET_START, unf_port_reset_start },
{ UNF_PORT_RESET_END, unf_port_reset_end },
{ UNF_PORT_NOP, unf_port_nop },
{ UNF_PORT_CLEAN_DONE, unf_port_clean_done },
{ UNF_PORT_BEGIN_REMOVE, unf_port_begin_remove },
{ UNF_PORT_RELEASE_RPORT_INDEX, unf_port_release_rport_index },
{ UNF_PORT_ABNORMAL_RESET, unf_port_abnormal_reset },
};
static struct unf_hifcadm_action_s unf_hifcadm_action[] = {
{ UNF_PORT_SET_OP, unf_cm_port_set },
{ UNF_TOPO_SET_OP, unf_cm_topo_set },
{ UNF_SPEED_SET_OP, unf_cm_port_speed_set },
{ UNF_INFO_GET_OP, unf_cm_port_info_get },
{ UNF_INFO_CLEAR_OP, unf_cm_clear_error_code_sum },
{ UNF_SFP_INFO_OP, unf_get_port_sfp_info },
{ UNF_ALL_INFO_OP, unf_cm_get_all_port_info },
{ UNF_BBSCN, unf_cm_bbscn_set },
{ UNF_DFX, unf_get_io_dfx_statistics },
{ UNF_VPORT, unf_cm_set_vport },
{ UNF_LINK_DELAY, unf_cm_link_delay_get },
{ UNF_SAVA_DATA, unf_cm_save_data_mode },
{ UNF_DIF, unf_cm_set_dif },
{ UNF_DIF_CONFIG, unf_cm_select_dif_mode },
{ UNF_SHOW_XCHG, unf_cm_adm_show_xchg },
{ FC_LINK_TMO_OPT, unf_cm_adm_link_time_out_opt },
{ FC_DRV_LOG_OPT, unf_cm_adm_log_level_opt },
};
static void unf_destroy_dirty_rport(struct unf_lport_s *v_lport,
int v_show_only)
{
unsigned int dirty_rport = 0;
UNF_REFERNCE_VAR(dirty_rport);
/* for whole L_Port */
if (v_lport->dirty_flag & UNF_LPORT_DIRTY_FLAG_RPORT_POOL_DIRTY) {
dirty_rport = v_lport->rport_pool.rport_pool_count;
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"[info]Port(0x%x) has %u dirty RPort(s)",
v_lport->port_id, dirty_rport);
/* free R_Port pool memory & bitmap */
if (v_show_only == UNF_FALSE) {
vfree(v_lport->rport_pool.rport_pool_add);
v_lport->rport_pool.rport_pool_add = NULL;
vfree(v_lport->rport_pool.pul_rpi_bitmap);
v_lport->rport_pool.pul_rpi_bitmap = NULL;
}
}
UNF_REFERNCE_VAR(dirty_rport);
}
void unf_show_dirty_port(int v_show_only, unsigned int *v_ditry_port_num)
{
struct list_head *node = NULL;
struct list_head *node_next = NULL;
struct unf_lport_s *lport = NULL;
unsigned long flags = 0;
unsigned int port_num = 0;
UNF_CHECK_VALID(0x2200, UNF_TRUE, NULL != v_ditry_port_num, return);
/* for each dirty L_Port from global L_Port list */
spin_lock_irqsave(&global_lport_mgr.global_lport_list_lock, flags);
list_for_each_safe(node, node_next, &global_lport_mgr.list_dirty_head) {
lport = list_entry(node, struct unf_lport_s, entry_lport);
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"[info]Port(0x%x) has dirty data(0x%x)",
lport->port_id, lport->dirty_flag);
/* Destroy dirty L_Port's exchange(s) & R_Port(s) */
unf_destroy_dirty_xchg(lport, v_show_only);
unf_destroy_dirty_rport(lport, v_show_only);
/* Delete (dirty L_Port) list entry if necessary */
if (v_show_only == UNF_FALSE) {
list_del_init(node);
vfree(lport);
}
port_num++;
}
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock,
flags);
*v_ditry_port_num = port_num;
}
int unf_send_event(unsigned int port_id,
unsigned int syn_flag,
void *argc_in,
void *argc_out,
int (*p_func)(void *argc_in, void *argc_out))
{
struct unf_lport_s *lport = NULL;
struct unf_cm_event_report *event = NULL;
int ret = 0;
lport = unf_find_lport_by_port_id(port_id);
if (!lport) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_INFO,
"Cannot find LPort(0x%x).", port_id);
return UNF_RETURN_ERROR;
}
if (unf_lport_refinc(lport) != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_LOGIN_ATT, UNF_MAJOR,
"LPort(0x%x) is removing, no need process.",
lport->port_id);
return UNF_RETURN_ERROR;
}
if (unlikely((!lport->event_mgr.pfn_unf_get_free_event) ||
(!lport->event_mgr.pfn_unf_post_event) ||
(!lport->event_mgr.pfn_unf_release_event))) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Event function is NULL.");
unf_lport_ref_dec_to_destroy(lport);
return UNF_RETURN_ERROR;
}
if (lport->b_port_removing == UNF_TRUE) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_LOGIN_ATT, UNF_MAJOR,
"LPort(0x%x) is removing, no need process.",
lport->port_id);
unf_lport_ref_dec_to_destroy(lport);
return UNF_RETURN_ERROR;
}
event = lport->event_mgr.pfn_unf_get_free_event((void *)lport);
if (!event) {
unf_lport_ref_dec_to_destroy(lport);
return UNF_RETURN_ERROR;
}
init_completion(&event->event_comp);
event->lport = lport;
event->event_asy_flag = syn_flag;
event->pfn_unf_event_task = p_func;
event->para_in = argc_in;
event->para_out = argc_out;
lport->event_mgr.pfn_unf_post_event(lport, event);
if (event->event_asy_flag) {
/* You must wait for the other party to return. Otherwise,
*the linked list may be in disorder.
*/
wait_for_completion(&event->event_comp);
ret = (int)event->result;
lport->event_mgr.pfn_unf_release_event(lport, event);
} else {
ret = RETURN_OK;
}
unf_lport_ref_dec_to_destroy(lport);
return ret;
}
void unf_lport_update_topo(struct unf_lport_s *v_lport,
enum unf_act_topo_e v_enactive_topo)
{
unsigned long flag = 0;
UNF_CHECK_VALID(0x2210, UNF_TRUE, NULL != v_lport, return);
if ((v_enactive_topo > UNF_ACT_TOP_UNKNOWN) ||
(v_enactive_topo < UNF_ACT_TOP_PUBLIC_LOOP)) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_LOGIN_ATT, UNF_ERR,
"[err]Port(0x%x) set invalid topology(0x%x) with current value(0x%x)",
v_lport->nport_id, v_enactive_topo,
v_lport->en_act_topo);
return;
}
spin_lock_irqsave(&v_lport->lport_state_lock, flag);
v_lport->en_act_topo = v_enactive_topo;
spin_unlock_irqrestore(&v_lport->lport_state_lock, flag);
}
void unf_set_lport_removing(struct unf_lport_s *v_lport)
{
UNF_CHECK_VALID(0x2216, UNF_TRUE, (v_lport), return);
v_lport->fc_port = NULL;
v_lport->b_port_removing = UNF_TRUE;
v_lport->destroy_step = UNF_LPORT_DESTROY_STEP_0_SET_REMOVING;
}
unsigned int unf_release_local_port(void *v_lport)
{
struct unf_lport_s *lport = v_lport;
struct completion local_port_free_completion =
COMPLETION_INITIALIZER(local_port_free_completion);
UNF_CHECK_VALID(0x2217, UNF_TRUE, (lport),
return UNF_RETURN_ERROR);
lport->lport_free_completion = &local_port_free_completion;
unf_set_lport_removing(lport);
unf_lport_ref_dec(lport);
wait_for_completion(lport->lport_free_completion);
/* for dirty case */
if (lport->dirty_flag == 0)
vfree(lport);
return RETURN_OK;
}
static void unf_free_all_esgl_pages(struct unf_lport_s *v_lport)
{
struct list_head *node = NULL;
struct list_head *next_node = NULL;
unsigned long flag = 0;
unsigned int alloc_idx;
UNF_CHECK_VALID(0x2218, UNF_TRUE, (v_lport), return);
spin_lock_irqsave(&v_lport->esgl_pool.esgl_pool_lock, flag);
list_for_each_safe(node, next_node,
&v_lport->esgl_pool.list_esgl_pool) {
list_del(node);
}
spin_unlock_irqrestore(&v_lport->esgl_pool.esgl_pool_lock, flag);
if (v_lport->esgl_pool.esgl_buf_list.buflist) {
for (alloc_idx = 0;
alloc_idx < v_lport->esgl_pool.esgl_buf_list.buf_num;
alloc_idx++) {
if (v_lport->esgl_pool.esgl_buf_list.buflist[alloc_idx].vaddr) {
dma_free_coherent(&v_lport->low_level_func.dev->dev,
v_lport->esgl_pool.esgl_buf_list.buf_size,
v_lport->esgl_pool.esgl_buf_list.buflist[alloc_idx].vaddr,
v_lport->esgl_pool.esgl_buf_list.buflist[alloc_idx].paddr);
v_lport->esgl_pool.esgl_buf_list.buflist[alloc_idx].vaddr = NULL;
}
}
kfree(v_lport->esgl_pool.esgl_buf_list.buflist);
v_lport->esgl_pool.esgl_buf_list.buflist = NULL;
}
}
static unsigned int unf_init_esgl_pool(struct unf_lport_s *v_lport)
{
struct unf_esgl_s *esgl = NULL;
unsigned int ret = RETURN_OK;
unsigned int index = 0;
unsigned int buf_total_size;
unsigned int buf_num;
unsigned int alloc_idx;
unsigned int cur_buf_idx = 0;
unsigned int cur_buf_offset = 0;
unsigned int buf_cnt_perhugebuf;
UNF_CHECK_VALID(0x2219, UNF_TRUE, NULL != v_lport,
return UNF_RETURN_ERROR);
v_lport->esgl_pool.esgl_pool_count =
v_lport->low_level_func.lport_cfg_items.max_io;
spin_lock_init(&v_lport->esgl_pool.esgl_pool_lock);
INIT_LIST_HEAD(&v_lport->esgl_pool.list_esgl_pool);
v_lport->esgl_pool.esgl_pool_addr =
vmalloc((size_t)((v_lport->esgl_pool.esgl_pool_count) *
sizeof(struct unf_esgl_s)));
if (!v_lport->esgl_pool.esgl_pool_addr) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_ERR,
"LPort(0x%x) cannot allocate ESGL Pool.",
v_lport->port_id);
return UNF_RETURN_ERROR;
}
esgl = (struct unf_esgl_s *)v_lport->esgl_pool.esgl_pool_addr;
memset(esgl, 0, ((v_lport->esgl_pool.esgl_pool_count) *
sizeof(struct unf_esgl_s)));
buf_total_size =
(unsigned int)(PAGE_SIZE * v_lport->esgl_pool.esgl_pool_count);
v_lport->esgl_pool.esgl_buf_list.buf_size =
buf_total_size > BUF_LIST_PAGE_SIZE ? BUF_LIST_PAGE_SIZE :
buf_total_size;
buf_cnt_perhugebuf =
v_lport->esgl_pool.esgl_buf_list.buf_size / PAGE_SIZE;
buf_num = v_lport->esgl_pool.esgl_pool_count %
buf_cnt_perhugebuf ? v_lport->esgl_pool.esgl_pool_count /
buf_cnt_perhugebuf + 1 : v_lport->esgl_pool.esgl_pool_count /
buf_cnt_perhugebuf;
v_lport->esgl_pool.esgl_buf_list.buflist =
(struct buff_list_s *)
kmalloc(buf_num * sizeof(struct buff_list_s), GFP_KERNEL);
v_lport->esgl_pool.esgl_buf_list.buf_num = buf_num;
if (!v_lport->esgl_pool.esgl_buf_list.buflist) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_REG_ATT, UNF_WARN,
"[err]Allocate Esgl pool buf list failed out of memory");
goto free_buff;
}
memset(v_lport->esgl_pool.esgl_buf_list.buflist, 0,
buf_num * sizeof(struct buff_list_s));
for (alloc_idx = 0; alloc_idx < buf_num; alloc_idx++) {
v_lport->esgl_pool.esgl_buf_list.buflist[alloc_idx].vaddr =
dma_alloc_coherent(
&v_lport->low_level_func.dev->dev,
v_lport->esgl_pool.esgl_buf_list.buf_size,
&v_lport->esgl_pool.esgl_buf_list.buflist[alloc_idx].paddr,
GFP_KERNEL);
if (!v_lport->esgl_pool.esgl_buf_list.buflist[alloc_idx].vaddr)
goto free_buff;
memset(v_lport->esgl_pool.esgl_buf_list.buflist[alloc_idx].vaddr,
0, v_lport->esgl_pool.esgl_buf_list.buf_size);
}
/* allocates the Esgl page, and the DMA uses the */
for (index = 0; index < v_lport->esgl_pool.esgl_pool_count; index++) {
if ((index != 0) && !(index % buf_cnt_perhugebuf))
cur_buf_idx++;
cur_buf_offset =
(unsigned int)
(PAGE_SIZE * (index % buf_cnt_perhugebuf));
esgl->page.page_address =
(unsigned long long)v_lport->esgl_pool.esgl_buf_list.buflist[cur_buf_idx].vaddr +
cur_buf_offset;
esgl->page.page_size = PAGE_SIZE;
esgl->page.esgl_phyaddr =
v_lport->esgl_pool.esgl_buf_list.buflist[cur_buf_idx].paddr +
cur_buf_offset;
list_add_tail(&esgl->entry_esgl,
&v_lport->esgl_pool.list_esgl_pool);
esgl++;
}
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_INFO,
"[EVENT]Allocate bufnum:%u, buf_total_size:%u", buf_num,
buf_total_size);
return ret;
free_buff:
unf_free_all_esgl_pages(v_lport);
vfree(v_lport->esgl_pool.esgl_pool_addr);
return UNF_RETURN_ERROR;
}
static void unf_free_esgl_pool(struct unf_lport_s *v_lport)
{
UNF_CHECK_VALID(0x2220, UNF_TRUE, (v_lport), return);
unf_free_all_esgl_pages(v_lport);
v_lport->esgl_pool.esgl_pool_count = 0;
if (v_lport->esgl_pool.esgl_pool_addr) {
vfree(v_lport->esgl_pool.esgl_pool_addr);
v_lport->esgl_pool.esgl_pool_addr = NULL;
}
v_lport->destroy_step = UNF_LPORT_DESTROY_STEP_5_DESTROY_ESGL_POOL;
}
struct unf_lport_s *unf_find_lport_by_port_id(unsigned int v_port_id)
{
struct unf_lport_s *lport = NULL;
struct list_head *node = NULL;
struct list_head *next_node = NULL;
unsigned long flags = 0;
unsigned int port_id = v_port_id & (~PORTID_VPINDEX_MASK);
unsigned short vport_index = (v_port_id & PORTID_VPINDEX_MASK) >>
PORTID_VPINDEX_SHIT;
spin_lock_irqsave(&global_lport_mgr.global_lport_list_lock, flags);
list_for_each_safe(node, next_node,
&global_lport_mgr.list_lport_list_head) {
lport = list_entry(node, struct unf_lport_s, entry_lport);
if ((port_id == lport->port_id) &&
(lport->b_port_removing != UNF_TRUE)) {
spin_unlock_irqrestore(
&global_lport_mgr.global_lport_list_lock,
flags);
return unf_cm_lookup_vport_by_vp_index(lport,
vport_index);
}
}
list_for_each_safe(node, next_node,
&global_lport_mgr.list_intergrad_head) {
lport = list_entry(node, struct unf_lport_s, entry_lport);
if ((port_id == lport->port_id) &&
(lport->b_port_removing != UNF_TRUE)) {
spin_unlock_irqrestore(
&global_lport_mgr.global_lport_list_lock,
flags);
return unf_cm_lookup_vport_by_vp_index(lport,
vport_index);
}
}
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock, flags);
return NULL;
}
unsigned int unf_is_vport_valid(struct unf_lport_s *v_lport,
struct unf_lport_s *v_vport)
{
struct unf_lport_s *lport = NULL;
struct unf_vport_pool_s *vport_pool = NULL;
struct unf_lport_s *vport = NULL;
struct list_head *node = NULL;
struct list_head *next_node = NULL;
unsigned long flag = 0;
UNF_CHECK_VALID(0x1977, UNF_TRUE, v_lport, return UNF_RETURN_ERROR);
UNF_CHECK_VALID(0x1977, UNF_TRUE, v_vport, return UNF_RETURN_ERROR);
lport = v_lport;
vport_pool = lport->vport_pool;
if (unlikely(!vport_pool)) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_IO_ATT, UNF_ERR,
"[err]Port(0x%x) vport pool is NULL",
lport->port_id);
return UNF_RETURN_ERROR;
}
spin_lock_irqsave(&vport_pool->vport_pool_lock, flag);
list_for_each_safe(node, next_node, &lport->list_vports_head) {
vport = list_entry(node, struct unf_lport_s, entry_vport);
if (vport == v_vport && vport->b_port_removing != UNF_TRUE) {
spin_unlock_irqrestore(&vport_pool->vport_pool_lock,
flag);
return RETURN_OK;
}
}
list_for_each_safe(node, next_node, &lport->list_intergrad_vports) {
vport = list_entry(node, struct unf_lport_s, entry_vport);
if (vport == v_vport && vport->b_port_removing != UNF_TRUE) {
spin_unlock_irqrestore(&vport_pool->vport_pool_lock,
flag);
return RETURN_OK;
}
}
spin_unlock_irqrestore(&vport_pool->vport_pool_lock, flag);
return UNF_RETURN_ERROR;
}
unsigned int unf_is_lport_valid(struct unf_lport_s *v_lport)
{
struct unf_lport_s *lport = NULL;
struct list_head *node = NULL;
struct list_head *next_node = NULL;
unsigned long flags = 0;
spin_lock_irqsave(&global_lport_mgr.global_lport_list_lock, flags);
list_for_each_safe(node, next_node,
&global_lport_mgr.list_lport_list_head) {
lport = list_entry(node, struct unf_lport_s, entry_lport);
if ((v_lport == lport) &&
(lport->b_port_removing != UNF_TRUE)) {
spin_unlock_irqrestore(
&global_lport_mgr.global_lport_list_lock,
flags);
return RETURN_OK;
}
if (unf_is_vport_valid(lport, v_lport) == RETURN_OK) {
spin_unlock_irqrestore(
&global_lport_mgr.global_lport_list_lock,
flags);
return RETURN_OK;
}
}
list_for_each_safe(node, next_node,
&global_lport_mgr.list_intergrad_head) {
lport = list_entry(node, struct unf_lport_s, entry_lport);
if ((v_lport == lport) &&
(lport->b_port_removing != UNF_TRUE)) {
spin_unlock_irqrestore(
&global_lport_mgr.global_lport_list_lock,
flags);
return RETURN_OK;
}
if (unf_is_vport_valid(lport, v_lport) == RETURN_OK) {
spin_unlock_irqrestore(
&global_lport_mgr.global_lport_list_lock,
flags);
return RETURN_OK;
}
}
list_for_each_safe(node, next_node,
&global_lport_mgr.list_destroy_head) {
lport = list_entry(node, struct unf_lport_s, entry_lport);
if ((v_lport == lport) &&
(lport->b_port_removing != UNF_TRUE)) {
spin_unlock_irqrestore(
&global_lport_mgr.global_lport_list_lock,
flags);
return RETURN_OK;
}
if (unf_is_vport_valid(lport, v_lport) == RETURN_OK) {
spin_unlock_irqrestore(
&global_lport_mgr.global_lport_list_lock,
flags);
return RETURN_OK;
}
}
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock,
flags);
return UNF_RETURN_ERROR;
}
static void unf_clean_link_down_io(struct unf_lport_s *v_lport,
int v_clean_flag)
{
/* Clean L_Port/V_Port Link Down I/O: Set Abort Tag */
UNF_CHECK_VALID(0x2225, UNF_TRUE, v_lport, return);
UNF_CHECK_VALID(0x2685, UNF_TRUE,
v_lport->xchg_mgr_temp.pfn_unf_xchg_abort_all_io,
return);
v_lport->xchg_mgr_temp.pfn_unf_xchg_abort_all_io(v_lport,
UNF_XCHG_TYPE_INI, v_clean_flag);
v_lport->xchg_mgr_temp.pfn_unf_xchg_abort_all_io(v_lport,
UNF_XCHG_TYPE_SFS, v_clean_flag);
}
unsigned int unf_fc_port_link_event(void *v_lport, unsigned int v_events,
void *v_input)
{
struct unf_lport_s *lport = NULL;
unsigned int ret = UNF_RETURN_ERROR;
unsigned int index = 0;
if (unlikely(!v_lport))
return UNF_RETURN_ERROR;
lport = (struct unf_lport_s *)v_lport;
ret = unf_lport_refinc(lport);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_LOGIN_ATT, UNF_MAJOR,
"[info]Port(0x%x) is removing and do nothing",
lport->port_id);
return RETURN_OK;
}
/* process port event */
while (index < (sizeof(lport_action) /
sizeof(struct unf_port_action_s))) {
if (v_events == lport_action[index].action) {
ret = lport_action[index].fn_unf_action(lport, v_input);
unf_lport_ref_dec_to_destroy(lport);
return ret;
}
index++;
}
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_LOGIN_ATT, UNF_WARN,
"[warn]Port(0x%x) receive unknown event(0x%x)",
lport->port_id, v_events);
unf_lport_ref_dec_to_destroy(lport);
return ret;
}
void unf_port_mgmt_init(void)
{
memset(&global_lport_mgr, 0, sizeof(struct unf_global_lport_s));
INIT_LIST_HEAD(&global_lport_mgr.list_lport_list_head);
INIT_LIST_HEAD(&global_lport_mgr.list_intergrad_head);
INIT_LIST_HEAD(&global_lport_mgr.list_destroy_head);
INIT_LIST_HEAD(&global_lport_mgr.list_dirty_head);
spin_lock_init(&global_lport_mgr.global_lport_list_lock);
UNF_SET_NOMAL_MODE(global_lport_mgr.dft_mode);
global_lport_mgr.b_start_work = UNF_TRUE;
}
void unf_port_mgmt_deinit(void)
{
if (global_lport_mgr.lport_sum != 0)
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_REG_ATT, UNF_WARN,
"[warn]There are %u port pool memory giveaway",
global_lport_mgr.lport_sum);
memset(&global_lport_mgr, 0, sizeof(struct unf_global_lport_s));
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"[info]Common port manager exit succeed");
}
static void unf_port_register(struct unf_lport_s *v_lport)
{
unsigned long flags = 0;
UNF_CHECK_VALID(0x2230, UNF_TRUE, (v_lport), return);
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_INFO,
"Register LPort(0x%p), port ID(0x%x).",
v_lport, v_lport->port_id);
/* Add to the global management linked list header */
spin_lock_irqsave(&global_lport_mgr.global_lport_list_lock, flags);
list_add_tail(&v_lport->entry_lport,
&global_lport_mgr.list_lport_list_head);
global_lport_mgr.lport_sum++;
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock, flags);
}
static void unf_port_unregister(struct unf_lport_s *v_lport)
{
unsigned long flags = 0;
UNF_CHECK_VALID(0x2703, UNF_TRUE, (v_lport), return);
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_INFO,
"Unregister LPort(0x%p), port ID(0x%x).",
v_lport, v_lport->port_id);
/* Remove from the global management linked list header */
spin_lock_irqsave(&global_lport_mgr.global_lport_list_lock, flags);
list_del(&v_lport->entry_lport);
global_lport_mgr.lport_sum--;
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock, flags);
}
static int unf_port_switch(struct unf_lport_s *v_lport,
unsigned int v_switch_flag)
{
struct unf_lport_s *lport = v_lport;
int ret = UNF_RETURN_ERROR;
int switch_flag = UNF_FALSE;
UNF_CHECK_VALID(0x2261, UNF_TRUE, lport, return UNF_RETURN_ERROR);
if (!lport->low_level_func.port_mgr_op.pfn_ll_port_config_set) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_EQUIP_ATT, UNF_WARN,
"[warn]Port(0x%x)'s config(switch) function is NULL",
lport->port_id);
return UNF_RETURN_ERROR;
}
switch_flag = v_switch_flag ? UNF_TRUE : UNF_FALSE;
ret = (int)lport->low_level_func.port_mgr_op.pfn_ll_port_config_set(
lport->fc_port,
UNF_PORT_CFG_SET_PORT_SWITCH, (void *)&switch_flag);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_WARN,
"[warn]Port(0x%x) switch %s failed",
lport->port_id,
v_switch_flag ? "On" : "Off");
return UNF_RETURN_ERROR;
}
lport->b_switch_state = (enum int_e)switch_flag;
return RETURN_OK;
}
int unf_port_start_work(struct unf_lport_s *v_lport)
{
unsigned long flag = 0;
struct unf_fw_version_s fw_version = { 0 };
unsigned int ret = UNF_RETURN_ERROR;
UNF_CHECK_VALID(0x2231, UNF_TRUE, v_lport, return UNF_RETURN_ERROR);
spin_lock_irqsave(&v_lport->lport_state_lock, flag);
if (v_lport->en_start_work_state != UNF_START_WORK_STOP) {
spin_unlock_irqrestore(&v_lport->lport_state_lock, flag);
return RETURN_OK;
}
v_lport->en_start_work_state = UNF_START_WORK_COMPLETE;
spin_unlock_irqrestore(&v_lport->lport_state_lock, flag);
if (!v_lport->low_level_func.port_mgr_op.pfn_ll_port_diagnose) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Port(0x%x)'s corresponding function is NULL.",
v_lport->port_id);
return UNF_RETURN_ERROR;
}
fw_version.message_type = UNF_DEBUG_TYPE_MESSAGE;
ret = v_lport->low_level_func.port_mgr_op.pfn_ll_port_diagnose(
(void *)v_lport->fc_port,
UNF_PORT_DIAG_PORT_DETAIL, &fw_version);
if (ret != RETURN_OK)
v_lport->fw_version[0] = '\0';
else
memcpy(v_lport->fw_version, fw_version.fw_version,
HIFC_VER_LEN);
unf_cm_get_save_info(v_lport);
/* switch sfp to start work */
(void)unf_port_switch(v_lport, UNF_TRUE);
return RETURN_OK;
}
static unsigned int unf_lport_init_lw_fun_op(
struct unf_lport_s *v_lport,
struct unf_low_level_function_op_s *low_level_op)
{
UNF_CHECK_VALID(0x2235, UNF_TRUE, (v_lport), return UNF_RETURN_ERROR);
UNF_CHECK_VALID(0x2236, UNF_TRUE, (low_level_op),
return UNF_RETURN_ERROR);
v_lport->port_id = low_level_op->lport_cfg_items.port_id;
v_lport->port_name = low_level_op->sys_port_name;
v_lport->node_name = low_level_op->sys_node_name;
v_lport->options = low_level_op->lport_cfg_items.port_mode;
v_lport->en_act_topo = UNF_ACT_TOP_UNKNOWN;
memcpy(&v_lport->low_level_func, low_level_op,
sizeof(struct unf_low_level_function_op_s));
return RETURN_OK;
}
void unf_lport_release_lw_fun_op(struct unf_lport_s *v_lport)
{
UNF_CHECK_VALID(0x2237, UNF_TRUE, v_lport, return);
memset(&v_lport->low_level_func, 0,
sizeof(struct unf_low_level_function_op_s));
v_lport->destroy_step = UNF_LPORT_DESTROY_STEP_13_DESTROY_LW_INTERFACE;
}
struct unf_lport_s *unf_find_lport_by_scsi_host_id(unsigned int scsi_host_id)
{
struct list_head *node = NULL, *next_node = NULL;
struct list_head *vp_node = NULL, *next_vp_node = NULL;
struct unf_lport_s *lport = NULL;
struct unf_lport_s *vport = NULL;
unsigned long flags = 0;
unsigned long vpool_flags = 0;
spin_lock_irqsave(&global_lport_mgr.global_lport_list_lock, flags);
list_for_each_safe(node, next_node,
&global_lport_mgr.list_lport_list_head) {
lport = list_entry(node, struct unf_lport_s, entry_lport);
if (scsi_host_id ==
UNF_GET_SCSI_HOST_ID((lport->host_info.p_scsi_host))) {
spin_unlock_irqrestore(
&global_lport_mgr.global_lport_list_lock,
flags);
return lport;
}
/* support NPIV */
if (lport->vport_pool) {
spin_lock_irqsave(&lport->vport_pool->vport_pool_lock,
vpool_flags);
list_for_each_safe(vp_node, next_vp_node,
&lport->list_vports_head) {
vport = list_entry(vp_node, struct unf_lport_s,
entry_vport);
if (scsi_host_id ==
UNF_GET_SCSI_HOST_ID(vport->host_info.p_scsi_host)) {
spin_unlock_irqrestore(
&lport->vport_pool->vport_pool_lock,
vpool_flags);
spin_unlock_irqrestore(
&global_lport_mgr.global_lport_list_lock,
flags);
return vport;
}
}
spin_unlock_irqrestore(
&lport->vport_pool->vport_pool_lock, vpool_flags);
}
}
list_for_each_safe(node, next_node,
&global_lport_mgr.list_intergrad_head) {
lport = list_entry(node, struct unf_lport_s, entry_lport);
if (scsi_host_id ==
UNF_GET_SCSI_HOST_ID(lport->host_info.p_scsi_host)) {
spin_unlock_irqrestore(
&global_lport_mgr.global_lport_list_lock,
flags);
return lport;
}
/* support NPIV */
if (lport->vport_pool) {
spin_lock_irqsave(&lport->vport_pool->vport_pool_lock,
vpool_flags);
list_for_each_safe(vp_node, next_vp_node,
&lport->list_vports_head) {
vport = list_entry(vp_node, struct unf_lport_s,
entry_vport);
if (scsi_host_id ==
UNF_GET_SCSI_HOST_ID(vport->host_info.p_scsi_host)) {
spin_unlock_irqrestore(
&lport->vport_pool->vport_pool_lock,
vpool_flags);
spin_unlock_irqrestore(
&global_lport_mgr.global_lport_list_lock,
flags);
return vport;
}
}
spin_unlock_irqrestore(
&lport->vport_pool->vport_pool_lock, vpool_flags);
}
}
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock, flags);
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_IO_ATT, UNF_WARN,
"[warn]Can not find port by scsi_host_id(0x%x), may be removing",
scsi_host_id);
return NULL;
}
unsigned int unf_init_scsi_id_table(struct unf_lport_s *v_lport)
{
struct unf_rport_scsi_id_image_s *rport_scsi_id_image = NULL;
struct unf_wwpn_rport_info_s *wwpn_port_info = NULL;
unsigned int idx;
UNF_CHECK_VALID(0x2238, UNF_TRUE, (v_lport),
return UNF_RETURN_ERROR);
rport_scsi_id_image = &v_lport->rport_scsi_table;
rport_scsi_id_image->max_scsi_id = UNF_MAX_SCSI_ID;
/* If the number of remote connections supported by the L_Port is 0,
* an exception occurs
*/
if (rport_scsi_id_image->max_scsi_id == 0) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR,
"[err]Port(0x%x), supported maximum login is zero.",
v_lport->port_id);
return UNF_RETURN_ERROR;
}
rport_scsi_id_image->wwn_rport_info_table =
vmalloc(rport_scsi_id_image->max_scsi_id *
sizeof(struct unf_wwpn_rport_info_s));
if (!rport_scsi_id_image->wwn_rport_info_table) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR,
"[err]Port(0x%x) can't allocate SCSI ID Table(0x%x).",
v_lport->port_id, rport_scsi_id_image->max_scsi_id);
return UNF_RETURN_ERROR;
}
memset(rport_scsi_id_image->wwn_rport_info_table, 0,
rport_scsi_id_image->max_scsi_id *
sizeof(struct unf_wwpn_rport_info_s));
wwpn_port_info = rport_scsi_id_image->wwn_rport_info_table;
for (idx = 0; idx < rport_scsi_id_image->max_scsi_id; idx++) {
INIT_DELAYED_WORK(&wwpn_port_info->loss_tmo_work,
unf_sesion_loss_timeout);
INIT_LIST_HEAD(&wwpn_port_info->fc_lun_list);
wwpn_port_info->lport = v_lport;
wwpn_port_info->target_id = INVALID_VALUE32;
wwpn_port_info++;
}
spin_lock_init(&rport_scsi_id_image->scsi_image_table_lock);
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_INFO,
"[info]Port(0x%x) supported maximum login is %d.",
v_lport->port_id, rport_scsi_id_image->max_scsi_id);
return RETURN_OK;
}
void unf_destroy_scsi_id_table(struct unf_lport_s *v_lport)
{
struct unf_rport_scsi_id_image_s *rport_scsi_id_image = NULL;
struct unf_wwpn_rport_info_s *wwpn_rport_info = NULL;
unsigned int i = 0;
unsigned int ret = UNF_RETURN_ERROR;
UNF_CHECK_VALID(0x2239, UNF_TRUE, (v_lport), return);
rport_scsi_id_image = &v_lport->rport_scsi_table;
if (rport_scsi_id_image->wwn_rport_info_table) {
for (i = 0; i < UNF_MAX_SCSI_ID; i++) {
wwpn_rport_info =
&rport_scsi_id_image->wwn_rport_info_table[i];
UNF_DELAYED_WORK_SYNC(ret, v_lport->port_id,
&wwpn_rport_info->loss_tmo_work,
"loss tmo Timer work");
if (wwpn_rport_info->dfx_counter)
vfree(wwpn_rport_info->dfx_counter);
}
/* just for pc_lint */
if (ret)
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_LOGIN_ATT,
UNF_INFO,
"Port(0x%x) cancel loss tmo work success",
v_lport->port_id);
vfree(rport_scsi_id_image->wwn_rport_info_table);
rport_scsi_id_image->wwn_rport_info_table = NULL;
}
rport_scsi_id_image->max_scsi_id = 0;
v_lport->destroy_step = UNF_LPORT_DESTROY_STEP_10_DESTROY_SCSI_TABLE;
}
static unsigned int unf_lport_init(
struct unf_lport_s *v_lport,
void *private_data,
struct unf_low_level_function_op_s *low_level_op)
{
unsigned int ret = RETURN_OK;
int ret_value = RETURN_ERROR_S32;
char work_queue_name[16];
unf_init_portparms(v_lport);
/* Associating LPort with FCPort */
v_lport->fc_port = private_data;
/* VpIndx=0 is reserved for Lport, and rootLport points to its own */
v_lport->vp_index = 0;
v_lport->root_lport = v_lport;
v_lport->chip_info = NULL;
/* Initialize the units related to L_Port and lw func */
ret = unf_lport_init_lw_fun_op(v_lport, low_level_op);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"LPort(0x%x) initialize lowlevel function unsuccessful.",
v_lport->port_id);
return ret;
}
/* Init Linkevent workqueue */
ret_value = snprintf(work_queue_name, sizeof(work_queue_name),
"%x_lkq", (unsigned int)v_lport->port_id);
UNF_FUNCTION_RETURN_CHECK(ret_value, (int)sizeof(work_queue_name));
v_lport->link_event_wq = create_singlethread_workqueue(work_queue_name);
if (!v_lport->link_event_wq) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_NORMAL, UNF_ERR,
"[err]Port(0x%x) creat link event work queue failed",
v_lport->port_id);
return UNF_RETURN_ERROR;
}
ret_value = snprintf(work_queue_name, sizeof(work_queue_name),
"%x_xchgwq", (unsigned int)v_lport->port_id);
UNF_FUNCTION_RETURN_CHECK(ret_value, (int)sizeof(work_queue_name));
v_lport->xchg_wq = create_workqueue(work_queue_name);
if (!v_lport->xchg_wq) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_NORMAL, UNF_ERR,
"[err]Port(0x%x) creat Exchg work queue failed",
v_lport->port_id);
flush_workqueue(v_lport->link_event_wq);
destroy_workqueue(v_lport->link_event_wq);
v_lport->link_event_wq = NULL;
return UNF_RETURN_ERROR;
}
/* scsi table (R_Port) required for initializing INI
* Initialize the scsi id Table table to manage the
* mapping between SCSI ID, WWN, and Rport.
*/
ret = unf_init_scsi_id_table(v_lport);
if (ret != RETURN_OK) {
flush_workqueue(v_lport->link_event_wq);
destroy_workqueue(v_lport->link_event_wq);
v_lport->link_event_wq = NULL;
flush_workqueue(v_lport->xchg_wq);
destroy_workqueue(v_lport->xchg_wq);
v_lport->xchg_wq = NULL;
return ret;
}
/* Initialize the EXCH resource */
ret = unf_alloc_xchg_resource(v_lport);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"LPort(0x%x) can't allocate exchange resource.",
v_lport->port_id);
flush_workqueue(v_lport->link_event_wq);
destroy_workqueue(v_lport->link_event_wq);
v_lport->link_event_wq = NULL;
flush_workqueue(v_lport->xchg_wq);
destroy_workqueue(v_lport->xchg_wq);
v_lport->xchg_wq = NULL;
unf_destroy_scsi_id_table(v_lport);
return ret;
}
/* Initialize the ESGL resource pool used by Lport */
ret = unf_init_esgl_pool(v_lport);
if (ret != RETURN_OK) {
flush_workqueue(v_lport->link_event_wq);
destroy_workqueue(v_lport->link_event_wq);
v_lport->link_event_wq = NULL;
flush_workqueue(v_lport->xchg_wq);
destroy_workqueue(v_lport->xchg_wq);
v_lport->xchg_wq = NULL;
unf_free_all_xchg_mgr(v_lport);
unf_destroy_scsi_id_table(v_lport);
return ret;
}
/* Initialize the disc manager under Lport */
ret = unf_init_disc_mgr(v_lport);
if (ret != RETURN_OK) {
flush_workqueue(v_lport->link_event_wq);
destroy_workqueue(v_lport->link_event_wq);
v_lport->link_event_wq = NULL;
flush_workqueue(v_lport->xchg_wq);
destroy_workqueue(v_lport->xchg_wq);
v_lport->xchg_wq = NULL;
unf_free_esgl_pool(v_lport);
unf_free_all_xchg_mgr(v_lport);
unf_destroy_scsi_id_table(v_lport);
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"LPort(0x%x) initialize discover manager unsuccessful.",
v_lport->port_id);
return ret;
}
/* Initialize the LPort manager */
ret = unf_init_lport_mgr_temp(v_lport);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"LPort(0x%x) initialize RPort manager unsuccessful.",
v_lport->port_id);
goto RELEASE_LPORT;
}
/* Initialize the EXCH manager */
ret = unf_init_xchg_mgr_temp(v_lport);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"LPort(0x%x) initialize exchange manager unsuccessful.",
v_lport->port_id);
goto RELEASE_LPORT;
}
/* Initialize the resources required by the event processing center */
ret = unf_init_event_center(v_lport);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"LPort(0x%x) initialize event center unsuccessful.",
v_lport->port_id);
goto RELEASE_LPORT;
}
/* Initialize the initialization status of Lport */
unf_set_lport_state(v_lport, UNF_LPORT_ST_INITIAL);
/* Initialize the Lport route test case */
ret = unf_init_lport_route(v_lport);
if (ret != RETURN_OK) {
flush_workqueue(v_lport->link_event_wq);
destroy_workqueue(v_lport->link_event_wq);
v_lport->link_event_wq = NULL;
flush_workqueue(v_lport->xchg_wq);
destroy_workqueue(v_lport->xchg_wq);
v_lport->xchg_wq = NULL;
(void)unf_event_center_destroy(v_lport);
unf_disc_mgr_destroy(v_lport);
unf_free_esgl_pool(v_lport);
unf_free_all_xchg_mgr(v_lport);
unf_destroy_scsi_id_table(v_lport);
return ret;
}
/* Thesupports the initialization stepof the NPIV */
ret = unf_init_vport_pool(v_lport);
if (ret != RETURN_OK) {
flush_workqueue(v_lport->link_event_wq);
destroy_workqueue(v_lport->link_event_wq);
v_lport->link_event_wq = NULL;
flush_workqueue(v_lport->xchg_wq);
destroy_workqueue(v_lport->xchg_wq);
v_lport->xchg_wq = NULL;
unf_destroy_lport_route(v_lport);
(void)unf_event_center_destroy(v_lport);
unf_disc_mgr_destroy(v_lport);
unf_free_esgl_pool(v_lport);
unf_free_all_xchg_mgr(v_lport);
unf_destroy_scsi_id_table(v_lport);
return ret;
}
/* qualifier rport callback */
v_lport->pfn_unf_qualify_rport = unf_rport_set_qualifier_key_reuse;
v_lport->pfn_unf_tmf_abnormal_recovery =
unf_tmf_timeout_recovery_special;
return RETURN_OK;
RELEASE_LPORT:
flush_workqueue(v_lport->link_event_wq);
destroy_workqueue(v_lport->link_event_wq);
v_lport->link_event_wq = NULL;
flush_workqueue(v_lport->xchg_wq);
destroy_workqueue(v_lport->xchg_wq);
v_lport->xchg_wq = NULL;
unf_disc_mgr_destroy(v_lport);
unf_free_esgl_pool(v_lport);
unf_free_all_xchg_mgr(v_lport);
unf_destroy_scsi_id_table(v_lport);
return ret;
}
static void unf_destroy_card_thread(struct unf_lport_s *v_lport)
{
struct unf_event_mgr *event_mgr = NULL;
struct unf_chip_manage_info_s *chip_info = NULL;
struct list_head *list = NULL;
struct list_head *list_tmp = NULL;
struct unf_cm_event_report *event_node = NULL;
unsigned long event_lock_flag = 0;
unsigned long flag = 0;
UNF_CHECK_VALID(0x2249, UNF_TRUE, (v_lport), return);
/* If the thread cannot be found, apply for a new thread. */
chip_info = v_lport->chip_info;
if (!chip_info) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"Port(0x%x) has no event thread.", v_lport->port_id);
return;
}
event_mgr = &v_lport->event_mgr;
spin_lock_irqsave(&chip_info->chip_event_list_lock, flag);
if (!list_empty(&chip_info->list_head)) {
list_for_each_safe(list, list_tmp, &chip_info->list_head) {
event_node = list_entry(list,
struct unf_cm_event_report,
list_entry);
/* The LPort under the global event node is null. */
if (v_lport == event_node->lport) {
list_del_init(&event_node->list_entry);
if (event_node->event_asy_flag ==
UNF_EVENT_SYN) {
event_node->result = UNF_RETURN_ERROR;
complete(&event_node->event_comp);
}
spin_lock_irqsave(&event_mgr->port_event_lock,
event_lock_flag);
event_mgr->free_event_count++;
list_add_tail(&event_node->list_entry,
&event_mgr->list_free_event);
spin_unlock_irqrestore(
&event_mgr->port_event_lock,
event_lock_flag);
}
}
}
spin_unlock_irqrestore(&chip_info->chip_event_list_lock, flag);
/* If the number of events introduced by the event thread is 0,
* it indicates that no interface is used. In this case, thread
* resources need to be consumed
*/
if (atomic_dec_and_test(&chip_info->ref_cnt)) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"Port(0x%x) destroy slot(%u) chip(0x%x) event thread succeed.",
v_lport->port_id, chip_info->slot_id,
chip_info->chip_id);
chip_info->b_thread_exit = UNF_TRUE;
wake_up_process(chip_info->data_thread);
kthread_stop(chip_info->data_thread);
chip_info->data_thread = NULL;
spin_lock_irqsave(&card_thread_mgr.global_card_list_lock, flag);
list_del_init(&chip_info->list_chip_thread_entry);
card_thread_mgr.card_sum--;
spin_unlock_irqrestore(&card_thread_mgr.global_card_list_lock,
flag);
vfree(chip_info);
}
v_lport->chip_info = NULL;
}
unsigned int unf_lport_deinit(struct unf_lport_s *v_lport)
{
UNF_CHECK_VALID(0x2246, UNF_TRUE, (v_lport), return UNF_RETURN_ERROR);
/* If the card is unloaded normally, the thread is stopped once.
* The problem does not occur if you stop the thread again.
*/
unf_destroy_lport_route(v_lport);
/* minus the reference count of the card event;
* the last port deletes the card thread
*/
unf_destroy_card_thread(v_lport);
flush_workqueue(v_lport->link_event_wq);
destroy_workqueue(v_lport->link_event_wq);
v_lport->link_event_wq = NULL;
/* Release Event Processing Center */
(void)unf_event_center_destroy(v_lport);
/* Release the Vport resource pool */
unf_free_vport_pool(v_lport);
/* Destroying the Xchg Manager */
unf_xchg_mgr_destroy(v_lport);
/* Release Esgl pool */
unf_free_esgl_pool(v_lport);
/* reliability review :Disc should release after Xchg.
* Destroy the disc manager
*/
unf_disc_mgr_destroy(v_lport);
/* Release Xchg Mg template */
unf_release_xchg_mgr_temp(v_lport);
/* Release the Lport Mg template */
unf_release_lport_mgr_temp(v_lport);
/* Destroy the ScsiId Table */
unf_destroy_scsi_id_table(v_lport);
flush_workqueue(v_lport->xchg_wq);
destroy_workqueue(v_lport->xchg_wq);
v_lport->xchg_wq = NULL;
/* Deregister SCSI Host */
unf_unregister_scsi_host(v_lport);
/* Releasing the lw Interface Template */
unf_lport_release_lw_fun_op(v_lport);
v_lport->fc_port = NULL;
return RETURN_OK;
}
static int unf_card_event_process(void *v_arg)
{
struct list_head *node = NULL;
struct unf_cm_event_report *event_node = NULL;
unsigned long flags = 0;
struct unf_chip_manage_info_s *chip_info =
(struct unf_chip_manage_info_s *)v_arg;
UNF_REFERNCE_VAR(v_arg);
set_user_nice(current, 4);
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_INFO,
"Slot(%u) chip(0x%x) enter event thread.",
chip_info->slot_id, chip_info->chip_id);
while (!kthread_should_stop()) {
if (chip_info->b_thread_exit == UNF_TRUE)
break;
spin_lock_irqsave(&chip_info->chip_event_list_lock, flags);
if (list_empty(&chip_info->list_head) == UNF_TRUE) {
spin_unlock_irqrestore(&chip_info->chip_event_list_lock,
flags);
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout((long)msecs_to_jiffies(1000));
} else {
node = (&chip_info->list_head)->next;
list_del_init(node);
chip_info->list_num--;
event_node = list_entry(node,
struct unf_cm_event_report,
list_entry);
spin_unlock_irqrestore(&chip_info->chip_event_list_lock,
flags);
unf_handle_event(event_node);
}
}
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EVENT, UNF_MAJOR,
"Slot(%u) chip(0x%x) exit event thread.",
chip_info->slot_id, chip_info->chip_id);
return RETURN_OK;
}
static unsigned int unf_creat_chip_thread(struct unf_lport_s *v_lport)
{
unsigned long flag = 0;
struct unf_chip_manage_info_s *chip_info = NULL;
UNF_CHECK_VALID(0x2250, UNF_TRUE, (v_lport), return UNF_RETURN_ERROR);
/* If the thread cannot be found, apply for a new thread. */
chip_info = (struct unf_chip_manage_info_s *)vmalloc(
sizeof(struct unf_chip_manage_info_s));
if (!chip_info) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR,
"Port(0x%x) cannot allocate thread memory.",
v_lport->port_id);
return UNF_RETURN_ERROR;
}
memset(chip_info, 0, sizeof(struct unf_chip_manage_info_s));
memcpy(&chip_info->chip_info, &v_lport->low_level_func.chip_info,
sizeof(struct unf_chip_info_s));
chip_info->slot_id =
UNF_GET_BOARD_TYPE_AND_SLOT_ID_BY_PORTID(v_lport->port_id);
chip_info->chip_id = v_lport->low_level_func.chip_id;
chip_info->list_num = 0;
chip_info->sfp_9545_fault = UNF_FALSE;
chip_info->sfp_power_fault = UNF_FALSE;
atomic_set(&chip_info->ref_cnt, 1);
atomic_set(&chip_info->card_loop_test_flag, UNF_FALSE);
spin_lock_init(&chip_info->card_loop_back_state_lock);
INIT_LIST_HEAD(&chip_info->list_head);
spin_lock_init(&chip_info->chip_event_list_lock);
chip_info->b_thread_exit = UNF_FALSE;
chip_info->data_thread =
kthread_create(unf_card_event_process, chip_info,
"%x_et", v_lport->port_id);
if (IS_ERR(chip_info->data_thread) ||
(!chip_info->data_thread)) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"Port(0x%x) creat event thread(0x%p) unsuccessful.",
v_lport->port_id, chip_info->data_thread);
vfree(chip_info);
return UNF_RETURN_ERROR;
}
v_lport->chip_info = chip_info;
wake_up_process(chip_info->data_thread);
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_INFO,
"Port(0x%x) creat slot(%u) chip(0x%x) event thread succeed.",
v_lport->port_id, chip_info->slot_id, chip_info->chip_id);
spin_lock_irqsave(&card_thread_mgr.global_card_list_lock, flag);
list_add_tail(&chip_info->list_chip_thread_entry,
&card_thread_mgr.list_card_list_head);
card_thread_mgr.card_sum++;
spin_unlock_irqrestore(&card_thread_mgr.global_card_list_lock, flag);
return RETURN_OK;
}
static unsigned int unf_find_chip_thread(struct unf_lport_s *v_lport)
{
unsigned long flag = 0;
struct list_head *node = NULL;
struct list_head *next_node = NULL;
struct unf_chip_manage_info_s *chip_info = NULL;
unsigned int ret = UNF_RETURN_ERROR;
spin_lock_irqsave(&card_thread_mgr.global_card_list_lock, flag);
list_for_each_safe(node, next_node,
&card_thread_mgr.list_card_list_head) {
chip_info = list_entry(node, struct unf_chip_manage_info_s,
list_chip_thread_entry);
if ((chip_info->chip_id == v_lport->low_level_func.chip_id) &&
(chip_info->slot_id == UNF_GET_BOARD_TYPE_AND_SLOT_ID_BY_PORTID(v_lport->port_id))) {
atomic_inc(&chip_info->ref_cnt);
v_lport->chip_info = chip_info;
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT,
UNF_MAJOR,
"Port(0x%x) find card(%u) chip(0x%x) event thread succeed.",
v_lport->port_id, chip_info->slot_id,
chip_info->chip_id);
spin_unlock_irqrestore(
&card_thread_mgr.global_card_list_lock, flag);
return RETURN_OK;
}
}
spin_unlock_irqrestore(&card_thread_mgr.global_card_list_lock, flag);
ret = unf_creat_chip_thread(v_lport);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"LPort(0x%x) creat event thread unsuccessful. Destroy LPort.",
v_lport->port_id);
return UNF_RETURN_ERROR;
} else {
return RETURN_OK;
}
}
static int unf_cm_get_mac_adr(void *argc_in, void *argc_out)
{
struct unf_lport_s *lport = NULL;
struct unf_get_chip_info_argout *chp_info = NULL;
UNF_CHECK_VALID(0x2398, UNF_TRUE, argc_in, return UNF_RETURN_ERROR);
UNF_CHECK_VALID(0x2398, UNF_TRUE, argc_out, return UNF_RETURN_ERROR);
lport = (struct unf_lport_s *)argc_in;
chp_info = (struct unf_get_chip_info_argout *)argc_out;
if (!lport) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
" LPort is null.");
return UNF_RETURN_ERROR;
}
if (!lport->low_level_func.port_mgr_op.pfn_ll_port_config_get) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"Port(0x%x)'s corresponding function is NULL.",
lport->port_id);
return UNF_RETURN_ERROR;
}
if (lport->low_level_func.port_mgr_op.pfn_ll_port_config_get(
lport->fc_port,
UNF_PORT_CFG_GET_MAC_ADDR, chp_info) != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"Port(0x%x) get .", lport->port_id);
return UNF_RETURN_ERROR;
}
return RETURN_OK;
}
static unsigned int unf_build_lport_wwn(struct unf_lport_s *v_lport)
{
struct unf_get_chip_info_argout v_wwn = { 0 };
unsigned int ret = UNF_RETURN_ERROR;
UNF_CHECK_VALID(0x2403, UNF_TRUE, (v_lport), return UNF_RETURN_ERROR);
ret = (unsigned int)unf_send_event(v_lport->port_id,
UNF_EVENT_SYN,
(void *)v_lport,
(void *)&v_wwn,
unf_cm_get_mac_adr);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"UNF_BuildSysWwn SendEvent(UNF_PortGetMacAdr) fail.");
return UNF_RETURN_ERROR;
}
/* save card mode: UNF_FC_SERVER_BOARD_32_G(6):32G;
* UNF_FC_SERVER_BOARD_16_G(7):16G MODE
*/
v_lport->card_type = v_wwn.board_type;
/* update port max speed */
if (v_wwn.board_type == UNF_FC_SERVER_BOARD_32_G)
v_lport->low_level_func.fc_ser_max_speed = UNF_PORT_SPEED_32_G;
else if (v_wwn.board_type == UNF_FC_SERVER_BOARD_16_G)
v_lport->low_level_func.fc_ser_max_speed = UNF_PORT_SPEED_16_G;
else if (v_wwn.board_type == UNF_FC_SERVER_BOARD_8_G)
v_lport->low_level_func.fc_ser_max_speed = UNF_PORT_SPEED_8_G;
else
v_lport->low_level_func.fc_ser_max_speed = UNF_PORT_SPEED_32_G;
return RETURN_OK;
}
void *unf_lport_create_and_init(
void *private_data,
struct unf_low_level_function_op_s *low_level_op)
{
struct unf_lport_s *lport = NULL;
unsigned int ret = UNF_RETURN_ERROR;
if (!private_data) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"Private Data is NULL");
return NULL;
}
if (!low_level_op) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"LowLevel port(0x%p) function is NULL", private_data);
return NULL;
}
/* 1. vmalloc & Memset L_Port */
lport = vmalloc(sizeof(struct unf_lport_s));
if (!lport) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR,
"Alloc LPort memory failed.");
return NULL;
}
memset(lport, 0, sizeof(struct unf_lport_s));
/* 2. L_Port Init */
if (unf_lport_init(lport, private_data, low_level_op) != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"LPort initialize unsuccessful.");
vfree(lport);
return NULL;
}
/* 4. Get or Create Chip Thread Chip_ID & Slot_ID */
ret = unf_find_chip_thread(lport);
if (ret != RETURN_OK) {
(void)unf_lport_deinit(lport);
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"LPort(0x%x) Find Chip thread unsuccessful. Destroy LPort.",
lport->port_id);
vfree(lport);
return NULL;
}
/* 5. Registers with in the port management global linked list */
unf_port_register(lport);
/* update WWN */
if (unf_build_lport_wwn(lport) != RETURN_OK) {
unf_port_unregister(lport);
(void)unf_lport_deinit(lport);
vfree(lport);
return NULL;
}
unf_init_link_lose_tmo(lport);
/* initialize Scsi Host */
if (unf_register_scsi_host(lport) != RETURN_OK) {
unf_port_unregister(lport);
(void)unf_lport_deinit(lport);
vfree(lport);
return NULL;
}
/* 7. Here, start work now */
if (global_lport_mgr.b_start_work == UNF_TRUE) {
if (unf_port_start_work(lport) != RETURN_OK) {
unf_port_unregister(lport);
(void)unf_lport_deinit(lport);
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_REG_ATT,
UNF_WARN,
"[warn]Port(0x%x) start work failed",
lport->port_id);
vfree(lport);
return NULL;
}
}
UNF_REFERNCE_VAR(lport);
return lport;
}
static int unf_lport_destroy(void *v_lport, void *v_arg_out)
{
struct unf_lport_s *lport = NULL;
unsigned long flags = 0;
if (!v_lport) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"LPort is NULL.");
return UNF_RETURN_ERROR;
}
UNF_REFERNCE_VAR(v_arg_out);
lport = (struct unf_lport_s *)v_lport;
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_NORMAL, UNF_MAJOR,
"Destroy LPort(0x%p), ID(0x%x).",
lport, lport->port_id);
/* NPIV Ensure that all Vport are deleted */
unf_destroy_all_vports(lport);
lport->destroy_step = UNF_LPORT_DESTROY_STEP_1_REPORT_PORT_OUT;
(void)unf_lport_deinit(v_lport);
/* The port is removed from the destroy linked list.
* The next step is to release the memory
*/
spin_lock_irqsave(&global_lport_mgr.global_lport_list_lock, flags);
list_del(&lport->entry_lport);
/* If the port has dirty memory, the port is mounted to the
* linked list of dirty ports
*/
if (lport->dirty_flag)
list_add_tail(&lport->entry_lport,
&global_lport_mgr.list_dirty_head);
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock,
flags);
if (lport->lport_free_completion) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"Complete LPort(0x%p), port ID(0x%x)'s Free Completion.",
lport, lport->port_id);
complete(lport->lport_free_completion);
} else {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"LPort(0x%p), port ID(0x%x)'s Free Completion is NULL.",
lport, lport->port_id);
dump_stack();
}
return RETURN_OK;
}
unsigned int unf_lport_refinc(struct unf_lport_s *v_lport)
{
unsigned long lport_flags = 0;
UNF_CHECK_VALID(0x2208, UNF_TRUE, v_lport, return UNF_RETURN_ERROR);
spin_lock_irqsave(&v_lport->lport_state_lock, lport_flags);
if (atomic_read(&v_lport->lport_ref_cnt) <= 0) {
spin_unlock_irqrestore(&v_lport->lport_state_lock,
lport_flags);
return UNF_RETURN_ERROR;
}
atomic_inc(&v_lport->lport_ref_cnt);
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_LOGIN_ATT, UNF_INFO,
"[info]Port(0x%p) port_id(0x%x) reference count is %d",
v_lport, v_lport->port_id,
atomic_read(&v_lport->lport_ref_cnt));
spin_unlock_irqrestore(&v_lport->lport_state_lock, lport_flags);
return RETURN_OK;
}
void unf_lport_ref_dec(struct unf_lport_s *v_lport)
{
unsigned long flags = 0;
unsigned long lport_flags = 0;
UNF_CHECK_VALID(0x2209, UNF_TRUE, v_lport, return);
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_LOGIN_ATT, UNF_INFO,
"LPort(0x%p), port ID(0x%x), reference count is %d.",
v_lport, v_lport->port_id,
atomic_read(&v_lport->lport_ref_cnt));
spin_lock_irqsave(&global_lport_mgr.global_lport_list_lock, flags);
spin_lock_irqsave(&v_lport->lport_state_lock, lport_flags);
if (atomic_dec_and_test(&v_lport->lport_ref_cnt)) {
spin_unlock_irqrestore(&v_lport->lport_state_lock, lport_flags);
list_del(&v_lport->entry_lport);
global_lport_mgr.lport_sum--;
/* attaches the lport to the destroy linked list for dfx */
list_add_tail(&v_lport->entry_lport,
&global_lport_mgr.list_destroy_head);
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock,
flags);
(void)unf_lport_destroy(v_lport, NULL);
} else {
spin_unlock_irqrestore(&v_lport->lport_state_lock, lport_flags);
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock,
flags);
}
}
static int unf_reset_port(void *v_arg_in, void *v_arg_out)
{
struct unf_reset_port_argin *arg_in =
(struct unf_reset_port_argin *)v_arg_in;
struct unf_lport_s *lport = NULL;
unsigned int ret = UNF_RETURN_ERROR;
enum unf_port_config_state_e port_state = UNF_PORT_CONFIG_STATE_RESET;
UNF_REFERNCE_VAR(v_arg_out);
UNF_CHECK_VALID(0x2262, UNF_TRUE, arg_in, return UNF_RETURN_ERROR);
lport = unf_find_lport_by_port_id(arg_in->port_id);
if (!lport) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Not find LPort(0x%x).", arg_in->port_id);
return UNF_RETURN_ERROR;
}
/* reset port */
if (!lport->low_level_func.port_mgr_op.pfn_ll_port_config_set) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Port(0x%x)'s corresponding function is NULL.",
lport->port_id);
return UNF_RETURN_ERROR;
}
lport->en_act_topo = UNF_ACT_TOP_UNKNOWN;
lport->speed = UNF_PORT_SPEED_UNKNOWN;
lport->fabric_node_name = 0;
ret = lport->low_level_func.port_mgr_op.pfn_ll_port_config_set(
lport->fc_port,
UNF_PORT_CFG_SET_PORT_STATE, (void *)&port_state);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Reset port(0x%x) unsuccessful.", lport->port_id);
return UNF_RETURN_ERROR;
}
return RETURN_OK;
}
static int unf_sfp_switch(unsigned int v_port_id, int v_turn_on)
{
struct unf_lport_s *lport = NULL;
int turn_on = v_turn_on;
int ret = UNF_RETURN_ERROR;
unsigned long flag = 0;
if (global_lport_mgr.b_start_work == UNF_FALSE) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_EQUIP_ATT, UNF_WARN,
"[warn]Port(0x%x) not start work, ignored command:turn %s.",
v_port_id, (v_turn_on == UNF_TRUE) ? "ON" : "OFF");
return RETURN_OK;
}
lport = unf_find_lport_by_port_id(v_port_id);
if (!lport) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_EQUIP_ATT, UNF_WARN,
"[warn]Not find LPort(0x%x).", v_port_id);
return UNF_RETURN_ERROR;
}
spin_lock_irqsave(&lport->lport_state_lock, flag);
if (lport->en_start_work_state != UNF_START_WORK_COMPLETE) {
spin_unlock_irqrestore(&lport->lport_state_lock, flag);
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_EQUIP_ATT, UNF_WARN,
"[warn]LPort(0x%x) not start work, ignored command:turn %s.",
v_port_id, (v_turn_on == UNF_TRUE) ? "ON" : "OFF");
return RETURN_OK;
}
spin_unlock_irqrestore(&lport->lport_state_lock, flag);
if (!lport->low_level_func.port_mgr_op.pfn_ll_port_config_set) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_EQUIP_ATT, UNF_WARN,
"[warn]Port(0x%x)'s corresponding function is NULL.",
v_port_id);
return UNF_RETURN_ERROR;
}
ret = (int)lport->low_level_func.port_mgr_op.pfn_ll_port_config_set(
lport->fc_port,
UNF_PORT_CFG_SET_SFP_SWITCH,
(void *)&turn_on);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_EQUIP_ATT, UNF_WARN,
"[warn]Port(0x%x) switch SFP+ %s unsuccessful.",
v_port_id, v_turn_on ? "On" : "Off");
return UNF_RETURN_ERROR;
}
lport->b_switch_state = (enum int_e)turn_on;
return RETURN_OK;
}
static int unf_sfp_switch_event(void *v_argc_in, void *v_argc_out)
{
struct unf_set_sfp_argin *in = (struct unf_set_sfp_argin *)v_argc_in;
UNF_REFERNCE_VAR(v_argc_out);
UNF_CHECK_VALID(0x2267, UNF_TRUE, v_argc_in, return UNF_RETURN_ERROR);
return unf_sfp_switch(in->port_id, in->turn_on);
}
int unf_cm_sfp_switch(unsigned int v_port_id, int v_bturn_on)
{
struct unf_set_sfp_argin in = { 0 };
in.port_id = v_port_id;
in.turn_on = v_bturn_on;
return unf_send_event(v_port_id, UNF_EVENT_SYN, (void *)&in,
(void *)NULL, unf_sfp_switch_event);
}
static int unf_get_port_speed(void *v_argc_in, void *v_argc_out)
{
unsigned int *speed = (unsigned int *)v_argc_out;
struct unf_low_level_port_mgr_op_s *port_mgr = NULL;
struct unf_lport_s *lport = NULL;
int ret = 0;
unsigned int port_id = *(unsigned int *)v_argc_in;
UNF_CHECK_VALID(0x2268, UNF_TRUE, v_argc_in, return UNF_RETURN_ERROR);
UNF_CHECK_VALID(0x2269, UNF_TRUE, v_argc_out, return UNF_RETURN_ERROR);
lport = unf_find_lport_by_port_id(port_id);
if (!lport) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Cannot Find LPort by (0x%x).", port_id);
return UNF_RETURN_ERROR;
}
port_mgr = &lport->low_level_func.port_mgr_op;
if (!port_mgr->pfn_ll_port_config_get) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Port(0x%x)'s corresponding function is NULL.",
port_id);
return UNF_RETURN_ERROR;
}
if (lport->link_up == UNF_PORT_LINK_UP)
ret = (int)port_mgr->pfn_ll_port_config_get(lport->fc_port,
UNF_PORT_CFG_GET_SPEED_ACT, (void *)speed);
else
*speed = UNF_PORT_SPEED_UNKNOWN;
return ret;
}
static int unf_cm_get_port_speed(unsigned int v_port_id, unsigned int *v_speed)
{
UNF_CHECK_VALID(0x2270, UNF_TRUE, v_speed, return UNF_RETURN_ERROR);
return unf_send_event(v_port_id, UNF_EVENT_SYN, (void *)&v_port_id,
(void *)v_speed, unf_get_port_speed);
}
static int unf_set_port_speed(void *v_argc_in, void *v_argc_out)
{
unsigned int ret = RETURN_OK;
struct unf_set_speed_argin *in =
(struct unf_set_speed_argin *)v_argc_in;
struct unf_lport_s *lport = NULL;
UNF_REFERNCE_VAR(v_argc_out);
UNF_CHECK_VALID(0x2271, UNF_TRUE, v_argc_in, return UNF_RETURN_ERROR);
lport = unf_find_lport_by_port_id(in->port_id);
if (!lport) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Cannot Find LPort by (0x%x).", in->port_id);
return UNF_RETURN_ERROR;
}
if (!lport->low_level_func.port_mgr_op.pfn_ll_port_config_set) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Port(0x%x)'s corresponding function is NULL.",
in->port_id);
return UNF_RETURN_ERROR;
}
ret = lport->low_level_func.port_mgr_op.pfn_ll_port_config_set(
lport->fc_port,
UNF_PORT_CFG_SET_SPEED, (void *)in->speed);
return (int)ret;
}
int unf_cm_set_port_speed(unsigned int v_port_id, unsigned int *v_speed)
{
struct unf_set_speed_argin in = { 0 };
in.port_id = v_port_id;
in.speed = v_speed;
return unf_send_event(v_port_id, UNF_EVENT_SYN, (void *)&in,
(void *)NULL, unf_set_port_speed);
}
static int unf_get_port_topo(void *argc_in, void *argc_out)
{
struct unf_lport_s *lport = NULL;
struct unf_get_topo_argout *out = NULL;
struct unf_low_level_port_mgr_op_s *port_mgr = NULL;
int ret = UNF_TRUE;
unsigned int port_id = 0;
UNF_CHECK_VALID(0x2283, UNF_TRUE, argc_in, return UNF_RETURN_ERROR);
UNF_CHECK_VALID(0x2284, UNF_TRUE, argc_out, return UNF_RETURN_ERROR);
port_id = *(unsigned int *)argc_in;
out = (struct unf_get_topo_argout *)argc_out;
lport = unf_find_lport_by_port_id(port_id);
if (!lport) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Not find LPort(0x%x).", port_id);
return UNF_RETURN_ERROR;
}
port_mgr = &lport->low_level_func.port_mgr_op;
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
port_mgr->pfn_ll_port_config_get,
return UNF_RETURN_ERROR);
if (lport->link_up == UNF_PORT_LINK_UP) {
ret = (int)port_mgr->pfn_ll_port_config_get(lport->fc_port,
UNF_PORT_CFG_GET_TOPO_ACT, (void *)out->en_act_topo);
if (ret != RETURN_OK)
return ret;
} else {
*out->en_act_topo = UNF_ACT_TOP_UNKNOWN;
}
ret = (int)port_mgr->pfn_ll_port_config_get(lport->fc_port,
UNF_PORT_CFG_GET_TOPO_CFG, (void *)out->topo_cfg);
return ret;
}
int unf_cm_get_port_topo(unsigned int v_port_id, unsigned int *v_topo_cfg,
enum unf_act_topo_e *v_en_act_topo)
{
struct unf_get_topo_argout out = { 0 };
UNF_CHECK_VALID(0x2286, UNF_TRUE, v_topo_cfg, return UNF_RETURN_ERROR);
UNF_CHECK_VALID(0x2287, UNF_TRUE, v_en_act_topo,
return UNF_RETURN_ERROR);
out.en_act_topo = v_en_act_topo;
out.topo_cfg = v_topo_cfg;
return unf_send_event(v_port_id, UNF_EVENT_SYN, (void *)&v_port_id,
(void *)&out, unf_get_port_topo);
}
static int unf_set_port_topo(void *argc_in, void *argc_out)
{
struct unf_lport_s *lport = NULL;
struct unf_set_topo_argin *in = NULL;
enum int_e *b_arg_out = (enum int_e *)argc_out;
unsigned int ret = UNF_RETURN_ERROR;
UNF_CHECK_VALID(0x2257, UNF_TRUE, argc_out, return UNF_RETURN_ERROR);
UNF_CHECK_VALID(0x2288, UNF_TRUE, argc_in, return UNF_RETURN_ERROR);
in = (struct unf_set_topo_argin *)argc_in;
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
(in->topo == UNF_TOP_LOOP_MASK) ||
(in->topo == UNF_TOP_P2P_MASK) ||
(in->topo == UNF_TOP_AUTO_MASK),
return UNF_RETURN_ERROR);
lport = unf_find_lport_by_port_id(in->port_id);
if (!lport) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Not find LPort(0x%x).", in->port_id);
return UNF_RETURN_ERROR;
}
UNF_CHECK_VALID(
INVALID_VALUE32, UNF_TRUE,
lport->low_level_func.port_mgr_op.pfn_ll_port_config_set,
return UNF_RETURN_ERROR);
ret = lport->low_level_func.port_mgr_op.pfn_ll_port_config_set(
lport->fc_port,
UNF_PORT_CFG_SET_TOPO, (void *)&in->topo);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Can't set port topology.");
return UNF_RETURN_ERROR;
}
lport->low_level_func.lport_cfg_items.port_topology = in->topo;
*b_arg_out = lport->b_switch_state;
return RETURN_OK;
}
int unf_cm_set_port_topo(unsigned int v_port_id, unsigned int v_topo)
{
struct unf_set_topo_argin in = { 0 };
int ret = UNF_RETURN_ERROR;
enum int_e b_switch_state = UNF_FALSE;
in.port_id = v_port_id;
in.topo = v_topo;
ret = unf_send_event(v_port_id, UNF_EVENT_SYN, (void *)&in,
(void *)&b_switch_state, unf_set_port_topo);
return ret;
}
int unf_set_port_bbscn(void *argc_in, void *argc_out)
{
struct unf_lport_s *lport = NULL;
struct unf_set_bbscn_argin *in = NULL;
unsigned int ret = UNF_RETURN_ERROR;
UNF_REFERNCE_VAR(argc_out);
UNF_CHECK_VALID(0x2300, UNF_TRUE, argc_in, return UNF_RETURN_ERROR);
in = (struct unf_set_bbscn_argin *)argc_in;
lport = unf_find_lport_by_port_id(in->port_id);
if (!lport) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Not find LPort(0x%x).", in->port_id);
return UNF_RETURN_ERROR;
}
UNF_CHECK_VALID(
INVALID_VALUE32, UNF_TRUE,
lport->low_level_func.port_mgr_op.pfn_ll_port_config_set,
return UNF_RETURN_ERROR);
ret = lport->low_level_func.port_mgr_op.pfn_ll_port_config_set(
lport->fc_port,
UNF_PORT_CFG_SET_BBSCN, (void *)&in->bb_scn);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Cannot set port BB_SC_N.");
return UNF_RETURN_ERROR;
}
/* update bbsn cfg to Lport */
lport->low_level_func.lport_cfg_items.bb_scn = in->bb_scn;
return RETURN_OK;
}
int unf_cm_set_port_bbscn(unsigned int v_port_id, unsigned int v_bbscn)
{
struct unf_set_bbscn_argin in = { 0 };
in.port_id = v_port_id;
in.bb_scn = v_bbscn;
return unf_send_event(v_port_id, UNF_EVENT_SYN, (void *)&in,
(void *)NULL, unf_set_port_bbscn);
}
unsigned int unf_get_error_code_sum(struct unf_lport_s *v_lport,
struct unf_err_code_s *v_fc_err_code)
{
struct unf_low_level_port_mgr_op_s *port_mgr = NULL;
struct unf_lport_s *lport = v_lport;
unsigned int ret = UNF_RETURN_ERROR;
struct unf_err_code_s fc_err_code;
UNF_CHECK_VALID(0x2328, UNF_TRUE, v_lport, return UNF_RETURN_ERROR);
UNF_CHECK_VALID(0x2329, UNF_TRUE, v_fc_err_code,
return UNF_RETURN_ERROR);
memset(&fc_err_code, 0, sizeof(struct unf_err_code_s));
port_mgr = &lport->low_level_func.port_mgr_op;
if (!port_mgr->pfn_ll_port_config_get) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Port(0x%x)'s corresponding function is NULL.",
lport->port_id);
return UNF_RETURN_ERROR;
}
ret = port_mgr->pfn_ll_port_config_get((void *)lport->fc_port,
UNF_PORT_CFG_GET_LESB_THEN_CLR, (void *)&fc_err_code);
if (ret != RETURN_OK)
return UNF_RETURN_ERROR;
if (lport->link_up != UNF_PORT_LINK_UP) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_INFO,
"LPort(0x%x) is not link up.", lport->port_id);
memcpy(v_fc_err_code, &lport->err_code_sum,
sizeof(struct unf_err_code_s));
return RETURN_OK;
}
lport->err_code_sum.bad_rx_char_count += fc_err_code.bad_rx_char_count;
lport->err_code_sum.link_fail_count += fc_err_code.link_fail_count;
lport->err_code_sum.loss_of_signal_count +=
fc_err_code.loss_of_signal_count;
lport->err_code_sum.loss_of_sync_count +=
fc_err_code.loss_of_sync_count;
lport->err_code_sum.proto_error_count += fc_err_code.proto_error_count;
lport->err_code_sum.rx_eo_fa_count = fc_err_code.rx_eo_fa_count;
lport->err_code_sum.dis_frame_count = fc_err_code.dis_frame_count;
lport->err_code_sum.bad_crc_count = fc_err_code.bad_crc_count;
memcpy(v_fc_err_code, &lport->err_code_sum,
sizeof(struct unf_err_code_s));
return RETURN_OK;
}
static int unf_clear_port_error_code_sum(void *argc_in, void *argc_out)
{
struct unf_lport_s *lport = NULL;
unsigned int port_id = 0;
unsigned int ret = UNF_RETURN_ERROR;
UNF_CHECK_VALID(0x2331, UNF_TRUE, argc_in, return UNF_RETURN_ERROR);
UNF_REFERNCE_VAR(argc_out);
port_id = *(unsigned int *)argc_in;
lport = unf_find_lport_by_port_id(port_id);
if (!lport) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Cannot find LPort(0x%x).", port_id);
return UNF_RETURN_ERROR;
}
if (!lport->low_level_func.port_mgr_op.pfn_ll_port_config_get) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Port(0x%x)'s corresponding function is NULL.",
port_id);
return UNF_RETURN_ERROR;
}
ret = lport->low_level_func.port_mgr_op.pfn_ll_port_config_get(
(void *)lport->fc_port,
UNF_PORT_CFG_CLR_LESB, NULL);
if (ret != RETURN_OK)
return UNF_RETURN_ERROR;
memset(&lport->err_code_sum, 0, sizeof(struct unf_err_code_s));
return RETURN_OK;
}
int unf_cm_clear_port_error_code_sum(unsigned int v_port_id)
{
return unf_send_event(v_port_id, UNF_EVENT_SYN, (void *)&v_port_id,
(void *)NULL, unf_clear_port_error_code_sum);
}
static int unf_update_lport_sfp_info(struct unf_lport_s *v_lport,
enum unf_port_config_get_op_e v_type)
{
struct unf_lport_s *lport = NULL;
int ret = UNF_RETURN_ERROR;
UNF_CHECK_VALID(0x2332, UNF_TRUE, v_lport, return UNF_RETURN_ERROR);
lport = v_lport;
if (!lport->low_level_func.port_mgr_op.pfn_ll_port_config_get) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Port(0x%x)'s corresponding function is NULL.",
lport->port_id);
return UNF_RETURN_ERROR;
}
ret = (int)(lport->low_level_func.port_mgr_op.pfn_ll_port_config_get(
(void *)lport->fc_port,
v_type, (void *)&lport->sfp_info));
return ret;
}
static int unf_translate_sfp_status(struct unf_lport_s *v_lport,
struct unf_get_sfp_argout *v_out)
{
struct unf_lport_s *lport = v_lport;
int ret = UNF_RETURN_ERROR;
switch (lport->sfp_info.status) {
case UNF_SFP_PRESENT_FAIL:
*v_out->status = DRV_CABLE_CONNECTOR_NONE;
ret = RETURN_OK;
break;
case UNF_SFP_POWER_FAIL:
*v_out->status = DRV_CABLE_CONNECTOR_INVALID;
ret = RETURN_OK;
break;
case UNF_9545_FAIL:
*v_out->status = DRV_CABLE_CONNECTOR_INVALID;
ret = RETURN_OK;
break;
default:
*v_out->status = DRV_CABLE_CONNECTOR_BUTT;
ret = UNF_RETURN_ERROR;
break;
}
return ret;
}
static void unf_record_chip_fault(struct unf_lport_s *v_lport)
{
#define UNF_CHIP_FAULT_MAX_CHECK_TIME 3
if (v_lport->sfp_info.status == UNF_9545_FAIL) {
/* If there are 9545 fault,explain that the sfp is power on,
* and reset sfp_power_fault_count
*/
v_lport->sfp_power_fault_count = 0;
if (v_lport->sfp_9545_fault_count <
UNF_CHIP_FAULT_MAX_CHECK_TIME) {
v_lport->sfp_9545_fault_count++;
} else {
v_lport->chip_info->sfp_9545_fault = UNF_TRUE;
v_lport->sfp_9545_fault_count = 0;
}
} else if (v_lport->sfp_info.status == UNF_SFP_POWER_FAIL) {
if (v_lport->sfp_power_fault_count <
UNF_CHIP_FAULT_MAX_CHECK_TIME) {
v_lport->sfp_power_fault_count++;
} else {
v_lport->chip_info->sfp_power_fault = UNF_TRUE;
v_lport->sfp_power_fault_count = 0;
}
}
}
int unf_check_sfp_tx_fault(struct unf_lport_s *v_lport,
struct unf_sfp_info_s *v_sfp_info)
{
/* 24 hours ms(24*60*60*1000) */
#define UNF_SFP_TXFALT_RECOVER_INTERVEL 86400000
struct unf_sfp_info_s *sfp_info = NULL;
struct unf_lport_s *lport = NULL;
sfp_info = v_sfp_info;
lport = v_lport;
if (sfp_info->sfp_info_a2.diag.status_ctrl.tx_fault_state == 0)
return RETURN_OK;
/* Repair conditions:
* 1 port linkdown;
* 2 from the last repair more than 24 hours;
* 3 sfp is on
*/
if ((lport->link_up == UNF_PORT_LINK_DOWN) &&
(lport->b_switch_state) &&
((lport->last_tx_fault_jif == 0) ||
(jiffies_to_msecs(jiffies - lport->last_tx_fault_jif) >
UNF_SFP_TXFALT_RECOVER_INTERVEL))) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"LPort(0x%x) stat(0x%x) jiff(%ld) lastjiff(%llu) Ctrl(0x%x) TxFault set 1.",
lport->port_id, lport->link_up, jiffies,
lport->last_tx_fault_jif,
*((unsigned char *)
&sfp_info->sfp_info_a2.diag.status_ctrl));
lport->last_tx_fault_jif = jiffies;
(void)unf_sfp_switch(lport->port_id, UNF_FALSE);
msleep(100);
/* Around quickly switch port FW state error problem */
(void)unf_sfp_switch(lport->port_id, UNF_TRUE);
return UNF_RETURN_ERROR;
}
return RETURN_OK;
}
static int unf_get_sfp_info(void *argc_in, void *argc_out)
{
struct unf_lport_s *lport = NULL;
struct unf_get_sfp_argout *out = NULL;
unsigned int port_id = 0;
int ret = RETURN_OK;
UNF_CHECK_VALID(0x2333, UNF_TRUE, argc_in, return UNF_RETURN_ERROR);
UNF_CHECK_VALID(0x2334, UNF_TRUE, argc_out, return UNF_RETURN_ERROR);
port_id = *(unsigned int *)argc_in;
out = (struct unf_get_sfp_argout *)argc_out;
lport = unf_find_lport_by_port_id(port_id);
if (!lport) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Cannot find LPort(0x%x).", port_id);
return UNF_RETURN_ERROR;
}
lport->sfp_info.status = 0;
ret = unf_update_lport_sfp_info(lport, UNF_PORT_CFG_GET_SFP_INFO);
if (ret == RETURN_OK) {
lport->sfp_power_fault_count = 0;
lport->sfp_9545_fault_count = 0;
*out->status = DRV_CABLE_CONNECTOR_OPTICAL;
if (unf_check_sfp_tx_fault(
lport,
&lport->sfp_info.sfp_eeprom_info.sfp_info) ==
UNF_RETURN_ERROR) {
return UNF_RETURN_ERROR;
}
memcpy(out->sfp_info, &lport->sfp_info.sfp_eeprom_info,
sizeof(union unf_sfp_eeprome_info));
ret = RETURN_OK;
} else {
ret = unf_translate_sfp_status(lport, out);
unf_record_chip_fault(lport);
UNF_TRACE(UNF_EVTLOG_IO_INFO, UNF_LOG_IO_ATT, UNF_MAJOR,
"Port(0x%x)'s getsfpinfo fail, sfp status(0x%x).",
lport->port_id, lport->sfp_info.status);
}
return ret;
}
int unf_cm_get_sfp_info(unsigned int v_port_id, unsigned int *v_status,
union unf_sfp_eeprome_info *v_sfp_info,
unsigned int *sfp_type)
{
struct unf_lport_s *lport = NULL;
struct unf_get_sfp_argout out = { 0 };
lport = unf_find_lport_by_port_id(v_port_id);
if (!lport)
return UNF_RETURN_ERROR;
UNF_CHECK_VALID(0x2335, UNF_TRUE, v_status, return UNF_RETURN_ERROR);
UNF_CHECK_VALID(0x2336, UNF_TRUE, v_sfp_info, return UNF_RETURN_ERROR);
out.status = v_status;
out.sfp_info = v_sfp_info;
if (global_lport_mgr.b_start_work == UNF_FALSE) {
UNF_TRACE(UNF_EVTLOG_IO_INFO, UNF_LOG_IO_ATT, UNF_MAJOR,
"Port(0x%x) have not start work, return.", v_port_id);
return UNF_RETURN_ERROR;
}
*sfp_type = lport->low_level_func.sfp_type;
return unf_send_event(v_port_id, UNF_EVENT_SYN, (void *)&v_port_id,
(void *)&out, unf_get_sfp_info);
}
int unf_cm_reset_port(unsigned int v_port_id)
{
int ret = UNF_RETURN_ERROR;
ret = unf_send_event(v_port_id, UNF_EVENT_SYN, (void *)&v_port_id,
(void *)NULL, unf_reset_port);
return ret;
}
int unf_lport_reset_port(struct unf_lport_s *v_lport, unsigned int v_flag)
{
UNF_CHECK_VALID(0x2352, UNF_TRUE, v_lport, return UNF_RETURN_ERROR);
return unf_send_event(v_lport->port_id, v_flag,
(void *)&v_lport->port_id,
(void *)NULL,
unf_reset_port);
}
static inline unsigned int unf_get_loop_alpa(struct unf_lport_s *v_lport,
void *v_loop_alpa)
{
unsigned int ret = UNF_RETURN_ERROR;
UNF_CHECK_VALID(0x2357, UNF_TRUE,
v_lport->low_level_func.port_mgr_op.pfn_ll_port_config_get,
return UNF_RETURN_ERROR);
ret = v_lport->low_level_func.port_mgr_op.pfn_ll_port_config_get(
v_lport->fc_port,
UNF_PORT_CFG_GET_LOOP_ALPA, v_loop_alpa);
return ret;
}
static unsigned int unf_lport_enter_private_loop_login(
struct unf_lport_s *v_lport)
{
struct unf_lport_s *lport = v_lport;
unsigned long flag = 0;
unsigned int ret = UNF_RETURN_ERROR;
UNF_CHECK_VALID(0x2358, UNF_TRUE, v_lport, return UNF_RETURN_ERROR);
spin_lock_irqsave(&lport->lport_state_lock, flag);
unf_lport_stat_ma(lport, UNF_EVENT_LPORT_READY);
/* LPort: LINK_UP --> READY */
spin_unlock_irqrestore(&lport->lport_state_lock, flag);
unf_lport_update_topo(lport, UNF_ACT_TOP_PRIVATE_LOOP);
/* NOP: check L_Port state */
if (atomic_read(&lport->port_no_operater_flag) == UNF_LPORT_NOP) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_LOGIN_ATT, UNF_MAJOR,
"[info]Port(0x%x) is NOP, do nothing",
lport->port_id);
return RETURN_OK;
}
/* INI: check L_Port mode */
if ((lport->options & UNF_PORT_MODE_INI) != UNF_PORT_MODE_INI) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_LOGIN_ATT, UNF_MAJOR,
"[info]Port(0x%x) has no INI feature(0x%x), do nothing",
lport->port_id, lport->options);
return RETURN_OK;
}
if (lport->disc.unf_disc_temp.pfn_unf_disc_start) {
ret = lport->disc.unf_disc_temp.pfn_unf_disc_start(lport);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_LOGIN_ATT,
UNF_WARN,
"[warn]Port(0x%x) with nportid(0x%x) start discovery failed",
lport->port_id, lport->nport_id);
}
}
return ret;
}
unsigned int unf_lport_login(struct unf_lport_s *v_lport,
enum unf_act_topo_e v_en_act_topo)
{
unsigned int loop_alpa = 0;
unsigned int ret = RETURN_OK;
unsigned long flag = 0;
UNF_CHECK_VALID(0x2359, UNF_TRUE, v_lport, return UNF_RETURN_ERROR);
/* 1. Update (set) L_Port topo which get from low level */
unf_lport_update_topo(v_lport, v_en_act_topo);
spin_lock_irqsave(&v_lport->lport_state_lock, flag);
/* 2. Link state check */
if (v_lport->link_up != UNF_PORT_LINK_UP) {
spin_unlock_irqrestore(&v_lport->lport_state_lock, flag);
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_LOGIN_ATT, UNF_WARN,
"[warn]Port(0x%x) with link_state(0x%x) port_state(0x%x) when login",
v_lport->port_id, v_lport->link_up,
v_lport->en_states);
return UNF_RETURN_ERROR;
}
/* 3. Update L_Port state */
unf_lport_stat_ma(v_lport, UNF_EVENT_LPORT_LINK_UP);
/* LPort: INITIAL --> LINK UP */
spin_unlock_irqrestore(&v_lport->lport_state_lock, flag);
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_LOGIN_ATT, UNF_INFO,
"[info]LOGIN: Port(0x%x) start to login with topology(0x%x)",
v_lport->port_id, v_lport->en_act_topo);
/* 4. Start logoin */
if ((v_en_act_topo == UNF_TOP_P2P_MASK) ||
(v_en_act_topo == UNF_ACT_TOP_P2P_FABRIC) ||
(v_en_act_topo == UNF_ACT_TOP_P2P_DIRECT)) {
/* P2P or Fabric mode */
ret = unf_lport_enter_flogi(v_lport);
} else if (v_en_act_topo == UNF_ACT_TOP_PUBLIC_LOOP) {
/* Public loop */
(void)unf_get_loop_alpa(v_lport, &loop_alpa);
/* Before FLOGI ALPA just low 8 bit after FLOGI ACC switch
* will assign complete addresses
*/
spin_lock_irqsave(&v_lport->lport_state_lock, flag);
v_lport->nport_id = loop_alpa;
spin_unlock_irqrestore(&v_lport->lport_state_lock, flag);
ret = unf_lport_enter_flogi(v_lport);
} else if (v_en_act_topo == UNF_ACT_TOP_PRIVATE_LOOP) {
/* Private loop */
(void)unf_get_loop_alpa(v_lport, &loop_alpa);
spin_lock_irqsave(&v_lport->lport_state_lock, flag);
v_lport->nport_id = loop_alpa;
spin_unlock_irqrestore(&v_lport->lport_state_lock, flag);
ret = unf_lport_enter_private_loop_login(v_lport);
} else {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_LOGIN_ATT, UNF_ERR,
"[err]LOGIN: Port(0x%x) login with unknown topology(0x%x)",
v_lport->port_id, v_lport->en_act_topo);
}
return ret;
}
static unsigned int unf_port_link_up(struct unf_lport_s *v_lport,
void *v_in_put)
{
struct unf_lport_s *lport = v_lport;
unsigned int ret = RETURN_OK;
enum unf_act_topo_e en_act_topo = UNF_ACT_TOP_UNKNOWN;
unsigned long flag = 0;
UNF_CHECK_VALID(0x2361, UNF_TRUE, v_lport, return UNF_RETURN_ERROR);
UNF_REFERNCE_VAR(v_in_put);
/* If NOP state, stop */
if (atomic_read(&lport->port_no_operater_flag) == UNF_LPORT_NOP) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_LOGIN_ATT, UNF_ERR,
"[warn]Port(0x%x) is NOP and do nothing",
lport->port_id);
return RETURN_OK;
}
/* Update port state */
spin_lock_irqsave(&lport->lport_state_lock, flag);
lport->link_up = UNF_PORT_LINK_UP;
lport->speed = *((unsigned int *)v_in_put);
unf_set_lport_state(v_lport, UNF_LPORT_ST_INITIAL);
/* INITIAL state */
spin_unlock_irqrestore(&lport->lport_state_lock, flag);
/* set hot pool wait state: so far, do not care */
unf_set_hot_pool_wait_state(lport, UNF_TRUE);
lport->enhanced_features |= UNF_LPORT_ENHANCED_FEATURE_READ_SFP_ONCE;
/* Get port active topopolgy (from low level) */
if (!lport->low_level_func.port_mgr_op.pfn_ll_port_config_get) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_LOGIN_ATT, UNF_ERR,
"[warn]Port(0x%x) get topo function is NULL",
lport->port_id);
return UNF_RETURN_ERROR;
}
ret = lport->low_level_func.port_mgr_op.pfn_ll_port_config_get(
lport->fc_port,
UNF_PORT_CFG_GET_TOPO_ACT, (void *)&en_act_topo);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_LOGIN_ATT, UNF_ERR,
"[warn]Port(0x%x) get topo from low level failed",
lport->port_id);
return UNF_RETURN_ERROR;
}
/* Start Login process */
ret = unf_lport_login(lport, en_act_topo);
unf_report_io_dm_event(lport, UNF_PORT_LINK_UP, 0);
return ret;
}
static unsigned int unf_port_link_down(struct unf_lport_s *v_lport,
void *v_in_put)
{
unsigned long flag = 0;
struct unf_lport_s *lport = NULL;
UNF_CHECK_VALID(0x2363, UNF_FALSE, v_lport, return UNF_RETURN_ERROR);
UNF_REFERNCE_VAR(v_in_put);
lport = v_lport;
unf_report_io_dm_event(lport, UNF_PORT_LINK_DOWN, 0);
/* To prevent repeated reporting linkdown */
spin_lock_irqsave(&lport->lport_state_lock, flag);
lport->speed = UNF_PORT_SPEED_UNKNOWN;
lport->en_act_topo = UNF_ACT_TOP_UNKNOWN;
if (lport->link_up == UNF_PORT_LINK_DOWN) {
spin_unlock_irqrestore(&lport->lport_state_lock, flag);
return RETURN_OK;
}
unf_lport_stat_ma(lport, UNF_EVENT_LPORT_LINK_DOWN);
unf_reset_lport_params(lport);
spin_unlock_irqrestore(&lport->lport_state_lock, flag);
unf_set_hot_pool_wait_state(lport, UNF_FALSE);
/*
* clear I/O:
* 1. INI do ABORT only,
* for INI: busy/delay/delay_transfer/wait
* Clean L_Port/V_Port Link Down I/O: only set ABORT tag
*/
unf_flush_disc_event(&lport->disc, NULL);
unf_clean_link_down_io(lport, UNF_FALSE);
/* for L_Port's R_Ports */
unf_clean_linkdown_rport(lport);
/* for L_Port's all Vports */
unf_linkdown_all_vports(v_lport);
return RETURN_OK;
}
static unsigned int unf_port_abnormal_reset(struct unf_lport_s *v_lport,
void *v_in_put)
{
unsigned int ret = UNF_RETURN_ERROR;
struct unf_lport_s *lport = NULL;
UNF_CHECK_VALID(0x2363, UNF_FALSE, v_lport, return UNF_RETURN_ERROR);
UNF_REFERNCE_VAR(v_in_put);
lport = v_lport;
ret = (unsigned int)unf_lport_reset_port(lport, UNF_EVENT_ASYN);
return ret;
}
static unsigned int unf_port_reset_start(struct unf_lport_s *v_lport,
void *v_in_put)
{
unsigned int ret = RETURN_OK;
unsigned long flag = 0;
UNF_CHECK_VALID(0x2364, UNF_FALSE, v_lport, return UNF_RETURN_ERROR);
UNF_REFERNCE_VAR(v_in_put);
spin_lock_irqsave(&v_lport->lport_state_lock, flag);
unf_set_lport_state(v_lport, UNF_LPORT_ST_RESET);
spin_unlock_irqrestore(&v_lport->lport_state_lock, flag);
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_LOGIN_ATT, UNF_INFO,
"Port(0x%x) begin to reset.", v_lport->port_id);
return ret;
}
static unsigned int unf_port_reset_end(struct unf_lport_s *v_lport,
void *v_in_put)
{
unsigned long flag = 0;
UNF_CHECK_VALID(0x2365, UNF_FALSE, v_lport, return UNF_RETURN_ERROR);
UNF_REFERNCE_VAR(v_in_put);
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_LOGIN_ATT, UNF_INFO,
"Port(0x%x) reset end.", v_lport->port_id);
/* Task management command returns success and avoid
* repair measures case offline device
*/
unf_wakeup_scsi_task_cmnd(v_lport);
spin_lock_irqsave(&v_lport->lport_state_lock, flag);
unf_set_lport_state(v_lport, UNF_LPORT_ST_INITIAL);
spin_unlock_irqrestore(&v_lport->lport_state_lock, flag);
return RETURN_OK;
}
static unsigned int unf_port_nop(struct unf_lport_s *v_lport, void *v_in_put)
{
struct unf_lport_s *lport = NULL;
unsigned long flag = 0;
UNF_CHECK_VALID(0x2366, UNF_FALSE, v_lport, return UNF_RETURN_ERROR);
UNF_REFERNCE_VAR(v_in_put);
lport = v_lport;
atomic_set(&lport->port_no_operater_flag, UNF_LPORT_NOP);
spin_lock_irqsave(&lport->lport_state_lock, flag);
unf_lport_stat_ma(lport, UNF_EVENT_LPORT_LINK_DOWN);
unf_reset_lport_params(lport);
spin_unlock_irqrestore(&lport->lport_state_lock, flag);
/* Set Tag prevent pending I/O to wait_list when close sfp failed */
unf_set_hot_pool_wait_state(lport, UNF_FALSE);
unf_flush_disc_event(&lport->disc, NULL);
/* L_Port/V_Port's I/O(s): Clean Link Down I/O: Set Abort Tag */
unf_clean_link_down_io(lport, UNF_FALSE);
/* L_Port/V_Port's R_Port(s): report link down event to
* scsi & clear resource
*/
unf_clean_linkdown_rport(lport);
unf_linkdown_all_vports(lport);
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_LOGIN_ATT, UNF_MAJOR,
"[info]Port(0x%x) report NOP event done",
lport->nport_id);
return RETURN_OK;
}
static unsigned int unf_port_clean_done(struct unf_lport_s *v_lport,
void *v_in_put)
{
UNF_CHECK_VALID(0x2691, UNF_FALSE, v_lport, return UNF_RETURN_ERROR);
UNF_REFERNCE_VAR(v_in_put);
/* when port reset,delte delete all Rport immediately,
* in order to remove immediately for resources
*/
unf_clean_linkdown_rport(v_lport);
return RETURN_OK;
}
static unsigned int unf_port_begin_remove(struct unf_lport_s *v_lport,
void *v_in_put)
{
UNF_CHECK_VALID(0x2691, UNF_FALSE, v_lport, return UNF_RETURN_ERROR);
UNF_REFERNCE_VAR(v_in_put);
/* Cancel route timer delay work */
unf_destroy_lport_route(v_lport);
return RETURN_OK;
}
static unsigned int unf_get_pcie_link_state(struct unf_lport_s *v_lport)
{
struct unf_lport_s *lport = v_lport;
int link_state = UNF_TRUE;
unsigned int ret = UNF_RETURN_ERROR;
UNF_CHECK_VALID(0x2257, UNF_TRUE, v_lport, return UNF_RETURN_ERROR);
UNF_CHECK_VALID(
INVALID_VALUE32, UNF_TRUE,
lport->low_level_func.port_mgr_op.pfn_ll_port_config_get,
return UNF_RETURN_ERROR);
ret = lport->low_level_func.port_mgr_op.pfn_ll_port_config_get(
lport->fc_port,
UNF_PORT_CFG_GET_PCIE_LINK_STATE, (void *)&link_state);
if (ret != RETURN_OK || link_state != UNF_TRUE) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_KEVENT,
"[err]Can't Get Pcie Link State");
return UNF_RETURN_ERROR;
}
return RETURN_OK;
}
void unf_root_lport_ref_dec(struct unf_lport_s *v_lport)
{
unsigned long flags = 0;
unsigned long lport_flags = 0;
unsigned int ret = UNF_RETURN_ERROR;
UNF_CHECK_VALID(0x2385, UNF_TRUE, v_lport, return);
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_LOGIN_ATT, UNF_INFO,
"[info]Port(0x%p) port_id(0x%x) reference count is %d",
v_lport, v_lport->port_id,
atomic_read(&v_lport->lport_ref_cnt));
spin_lock_irqsave(&global_lport_mgr.global_lport_list_lock, flags);
spin_lock_irqsave(&v_lport->lport_state_lock, lport_flags);
if (atomic_dec_and_test(&v_lport->lport_ref_cnt)) {
spin_unlock_irqrestore(&v_lport->lport_state_lock, lport_flags);
list_del(&v_lport->entry_lport);
global_lport_mgr.lport_sum--;
/* Put L_Port to destroy list for debuging */
list_add_tail(&v_lport->entry_lport,
&global_lport_mgr.list_destroy_head);
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock,
flags);
ret = unf_schedule_global_event((void *)v_lport,
UNF_GLOBAL_EVENT_ASYN,
unf_lport_destroy);
if (ret != RETURN_OK)
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_EVENT,
UNF_CRITICAL,
"[warn]Schedule global event faile. remain nodes(0x%x)",
global_event_queue.list_number);
} else {
spin_unlock_irqrestore(&v_lport->lport_state_lock, lport_flags);
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock,
flags);
}
}
void unf_lport_ref_dec_to_destroy(struct unf_lport_s *v_lport)
{
if (v_lport->root_lport != v_lport)
unf_vport_ref_dec(v_lport);
else
unf_root_lport_ref_dec(v_lport);
}
void unf_lport_route_work(struct work_struct *v_work)
{
#define MAX_INTERVAL_TIMES 60
struct unf_lport_s *lport = NULL;
int ret = 0;
struct unf_err_code_s fc_err_code;
UNF_CHECK_VALID(0x2388, UNF_TRUE, v_work, return);
lport = container_of(v_work, struct unf_lport_s, route_timer_work.work);
if (unlikely(!lport)) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT,
UNF_KEVENT, "[err]LPort is NULL");
return;
}
if (unlikely(lport->b_port_removing == UNF_TRUE)) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_KEVENT,
"[warn]LPort(0x%x) route work is closing.",
lport->port_id);
unf_lport_ref_dec_to_destroy(lport);
return;
}
if (unlikely(unf_get_pcie_link_state(lport)))
lport->pcie_link_down_cnt++;
else
lport->pcie_link_down_cnt = 0;
if (lport->pcie_link_down_cnt >= 3) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_KEVENT,
"[warn]LPort(0x%x) detected pcie linkdown, closing route work",
lport->port_id);
lport->b_pcie_linkdown = UNF_TRUE;
unf_free_lport_all_xchg(lport);
unf_lport_ref_dec_to_destroy(lport);
return;
}
if (unlikely(UNF_LPORT_CHIP_ERROR(lport))) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_KEVENT,
"[warn]LPort(0x%x) reported chip error, closing route work. ",
lport->port_id);
unf_lport_ref_dec_to_destroy(lport);
return;
}
if (lport->enhanced_features &
UNF_LPORT_ENHANCED_FEATURE_CLOSE_FW_ROUTE) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_KEVENT,
"[warn]User close LPort(0x%x) route work. ",
lport->port_id);
unf_lport_ref_dec_to_destroy(lport);
return;
}
if (atomic_read(&lport->err_code_obtain_freq) == 0) {
memset(&fc_err_code, 0, sizeof(struct unf_err_code_s));
unf_get_error_code_sum(lport, &fc_err_code);
atomic_inc(&lport->err_code_obtain_freq);
} else if (atomic_read(&lport->err_code_obtain_freq) ==
MAX_INTERVAL_TIMES) {
atomic_set(&lport->err_code_obtain_freq, 0);
} else {
atomic_inc(&lport->err_code_obtain_freq);
}
/* Scheduling 1 second */
ret = queue_delayed_work(
unf_work_queue, &lport->route_timer_work,
(unsigned long)msecs_to_jiffies(UNF_LPORT_POLL_TIMER));
if (ret == 0) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_KEVENT,
"[warn]LPort(0x%x) schedule work unsuccessful.",
lport->port_id);
unf_lport_ref_dec_to_destroy(lport);
}
}
int unf_cm_get_port_info(void *argc_in, void *argc_out)
{
struct unf_lport_s *lport = NULL;
struct unf_get_port_info_argout *port_info = NULL;
UNF_CHECK_VALID(0x2398, UNF_TRUE, argc_in, return UNF_RETURN_ERROR);
UNF_CHECK_VALID(0x2398, UNF_TRUE, argc_out, return UNF_RETURN_ERROR);
lport = (struct unf_lport_s *)argc_in;
port_info = (struct unf_get_port_info_argout *)argc_out;
if (!lport->low_level_func.port_mgr_op.pfn_ll_port_config_get) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"Port(0x%x)'s corresponding function is NULL.",
lport->port_id);
return UNF_RETURN_ERROR;
}
if (lport->low_level_func.port_mgr_op.pfn_ll_port_config_get(
lport->fc_port,
UNF_PORT_CFG_GET_PORT_INFO, port_info) !=
RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"Port(0x%x) get current info failed.",
lport->port_id);
return UNF_RETURN_ERROR;
}
return RETURN_OK;
}
static unsigned int unf_get_lport_current_info(struct unf_lport_s *v_lport)
{
struct unf_get_port_info_argout port_info = { 0 };
unsigned int ret = UNF_RETURN_ERROR;
struct unf_lport_s *lport = NULL;
UNF_CHECK_VALID(0x2403, UNF_TRUE, v_lport, return UNF_RETURN_ERROR);
lport = unf_find_lport_by_port_id(v_lport->port_id);
if (!lport)
return UNF_RETURN_ERROR;
ret = (unsigned int)unf_send_event(lport->port_id, UNF_EVENT_SYN,
(void *)lport,
(void *)&port_info,
unf_cm_get_port_info);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"UNF_GetPortCurrentInfo SendEvent(unf_cm_get_port_info) fail.");
return UNF_RETURN_ERROR;
}
lport->low_level_func.sfp_speed = port_info.sfp_speed;
return RETURN_OK;
}
int unf_set_link_lose_tmo_to_up(struct unf_lport_s *v_lport,
struct unf_flash_link_tmo_s *v_link_tmo)
{
int ret = UNF_RETURN_ERROR;
struct unf_flash_data_s flash_data;
if ((!v_lport) || (!v_link_tmo) ||
(sizeof(struct unf_flash_data_s) > HIFC_FLASH_DATA_MAX_LEN)) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_NORMAL, UNF_KEVENT,
"[warn]set link tmo param check fail");
return ret;
}
memset(&flash_data, 0, sizeof(struct unf_flash_data_s));
if (!v_lport->low_level_func.port_mgr_op.pfn_ll_port_config_get) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_NORMAL, UNF_KEVENT,
"[warn]link tmo fun null");
return ret;
}
if (v_lport->low_level_func.port_mgr_op.pfn_ll_port_config_get(
v_lport->fc_port,
UNF_PORT_CFG_GET_FLASH_DATA_INFO, &flash_data) !=
RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_NORMAL, UNF_KEVENT,
"[warn]get link tmo to up fail");
return ret;
}
memcpy(&flash_data.link_tmo, v_link_tmo, HIFC_FLASH_LINK_TMO_MAX_LEN);
if (!v_lport->low_level_func.port_mgr_op.pfn_ll_port_config_set) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_NORMAL, UNF_KEVENT,
"[warn]set link tmo fun null");
return ret;
}
if (v_lport->low_level_func.port_mgr_op.pfn_ll_port_config_set(
v_lport->fc_port, UNF_PORT_CFG_SET_FLASH_DATA_INFO,
&flash_data) !=
RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_NORMAL, UNF_KEVENT,
"[warn]set link tmo to up fail");
return ret;
}
ret = RETURN_OK;
return ret;
}
int unf_set_link_lose_tmo(struct unf_lport_s *v_lport, int time_out)
{
struct unf_flash_link_tmo_s flash_link_tmo;
int ret = UNF_RETURN_ERROR;
unsigned int link_tmo = (unsigned int)time_out;
memset(&flash_link_tmo, 0, sizeof(struct unf_flash_link_tmo_s));
if (!v_lport) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_NORMAL,
UNF_KEVENT, "[warn]set link tmo lport null");
return ret;
}
/* 1. update gloabl var */
if ((int)atomic_read(&v_lport->link_lose_tmo) == time_out)
return RETURN_OK;
atomic_set(&v_lport->link_lose_tmo, time_out);
flash_link_tmo.writeflag = HIFC_MGMT_TMO_MAGIC_NUM;
flash_link_tmo.link_tmo0 = (unsigned char)link_tmo;
flash_link_tmo.link_tmo1 = (unsigned char)(link_tmo >> 8);
flash_link_tmo.link_tmo2 = (unsigned char)(link_tmo >> 16);
flash_link_tmo.link_tmo3 = (unsigned char)(link_tmo >> 24);
/* 2. write to up */
ret = unf_set_link_lose_tmo_to_up(v_lport, &flash_link_tmo);
return ret;
}
int unf_set_link_lose_tmo_to_all(int time_out)
{
int ret = RETURN_OK;
struct list_head list_lport_tmp_head;
struct list_head *node = NULL;
struct list_head *next_node = NULL;
struct unf_lport_s *lport = NULL;
unsigned long flags = 0;
INIT_LIST_HEAD(&list_lport_tmp_head);
spin_lock_irqsave(&global_lport_mgr.global_lport_list_lock, flags);
list_for_each_safe(node, next_node,
&global_lport_mgr.list_lport_list_head) {
lport = list_entry(node, struct unf_lport_s, entry_lport);
list_del_init(&lport->entry_lport);
list_add_tail(&lport->entry_lport, &list_lport_tmp_head);
(void)unf_lport_refinc(lport);
}
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock, flags);
while (!list_empty(&list_lport_tmp_head)) {
node = (&list_lport_tmp_head)->next;
lport = list_entry(node, struct unf_lport_s, entry_lport);
if (lport)
unf_set_link_lose_tmo(lport, time_out);
spin_lock_irqsave(&global_lport_mgr.global_lport_list_lock,
flags);
list_del_init(&lport->entry_lport);
list_add_tail(&lport->entry_lport,
&global_lport_mgr.list_lport_list_head);
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock,
flags);
unf_lport_ref_dec_to_destroy(lport);
}
return ret;
}
static int unf_cm_adm_show_xchg(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_input)
{
int ret = UNF_RETURN_ERROR;
struct unf_xchg_mgr_s *xchg_mgr = NULL;
struct unf_xchg_s *xchg = NULL;
struct list_head *xchg_node = NULL;
struct list_head *next_xchg_node = NULL;
unsigned long flags = 0;
unsigned int aborted = 0;
unsigned int ini_busy = 0;
unsigned int tgt_busy = 0;
unsigned int delay = 0;
unsigned int free = 0;
unsigned int wait = 0;
unsigned int sfs_free = 0;
unsigned int sfs_busy = 0;
unsigned int i;
struct unf_adm_xchg *buff_out = NULL;
buff_out = (struct unf_adm_xchg *)v_input->buff_out;
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, *v_input->out_size >=
sizeof(struct unf_adm_xchg), return UNF_RETURN_ERROR);
for (i = 0; i < UNF_EXCHG_MGR_NUM; i++) {
xchg_mgr = unf_get_xchg_mgr_by_lport(v_lport, i);
if (!xchg_mgr)
continue;
if (!xchg_mgr->hot_pool)
continue;
/* hot Xchg */
spin_lock_irqsave(&xchg_mgr->hot_pool->xchg_hot_pool_lock,
flags);
UNF_TRACE(0x2659, UNF_LOG_NORMAL, UNF_INFO, "ini busy :");
list_for_each_safe(xchg_node, next_xchg_node,
&xchg_mgr->hot_pool->ini_busylist) {
ini_busy++;
xchg = list_entry(xchg_node, struct unf_xchg_s,
list_xchg_entry);
UNF_TRACE(0x2660, UNF_LOG_NORMAL, UNF_INFO,
"0x%p--0x%x--0x%x--0x%x--0x%x--0x%x--0x%x--0x%x--0x%x--0x%x--(%llu)",
xchg,
(unsigned int)xchg->hot_pool_tag,
(unsigned int)xchg->xchg_type,
(unsigned int)xchg->ox_id,
(unsigned int)xchg->rx_id,
(unsigned int)xchg->sid,
(unsigned int)xchg->did,
(unsigned int)xchg->seq_id,
(unsigned int)xchg->io_state,
atomic_read(&xchg->ref_cnt),
xchg->alloc_jif);
}
UNF_TRACE(0x2665, UNF_LOG_NORMAL, UNF_INFO, "SFS Busy:");
list_for_each_safe(xchg_node, next_xchg_node,
&xchg_mgr->hot_pool->sfs_busylist) {
sfs_busy++;
xchg = list_entry(xchg_node, struct unf_xchg_s,
list_xchg_entry);
UNF_TRACE(0x2666, UNF_LOG_NORMAL, UNF_INFO,
"0x%p--0x%x--0x%x--0x%x--0x%x--0x%x--0x%x--0x%x--0x%x--0x%x--(%llu)",
xchg,
(unsigned int)xchg->hot_pool_tag,
(unsigned int)xchg->xchg_type,
(unsigned int)xchg->ox_id,
(unsigned int)xchg->rx_id,
(unsigned int)xchg->sid,
(unsigned int)xchg->did,
(unsigned int)xchg->seq_id,
(unsigned int)xchg->io_state,
atomic_read(&xchg->ref_cnt),
xchg->alloc_jif);
}
spin_unlock_irqrestore(&xchg_mgr->hot_pool->xchg_hot_pool_lock,
flags);
/* free Xchg */
spin_lock_irqsave(&xchg_mgr->free_pool.xchg_free_pool_lock,
flags);
list_for_each_safe(xchg_node, next_xchg_node,
&xchg_mgr->free_pool.list_free_xchg_list) {
free++;
}
list_for_each_safe(xchg_node, next_xchg_node,
&xchg_mgr->free_pool.list_sfs_xchg_list) {
sfs_free++;
}
spin_unlock_irqrestore(&xchg_mgr->free_pool.xchg_free_pool_lock,
flags);
ret = RETURN_OK;
}
buff_out->aborted = aborted;
buff_out->ini_busy = ini_busy;
buff_out->tgt_busy = tgt_busy;
buff_out->delay = delay;
buff_out->free = free;
buff_out->wait = wait;
buff_out->sfs_free = sfs_free;
buff_out->sfs_busy = sfs_busy;
UNF_REFERNCE_VAR(xchg);
return ret;
}
static int unf_cm_adm_link_time_out_opt(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_input)
{
int ret = RETURN_OK;
int time_out = 0;
struct unf_link_tmo_opt_s *buff_in = NULL;
struct unf_link_tmo_opt_s *buff_out = NULL;
struct unf_admin_msg_head msg_head = { 0 };
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input,
return RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_lport,
return RETURN_ERROR);
buff_in = (struct unf_link_tmo_opt_s *)(v_input->buff_in);
buff_out = (struct unf_link_tmo_opt_s *)(v_input->buff_out);
msg_head.status = UNF_ADMIN_MSG_DONE;
msg_head.size = sizeof(struct unf_admin_msg_head);
if (buff_in->link_opt) {
/* set link tmo value */
time_out = unf_get_link_lose_tmo(v_lport);
/* compatible for PI2 branch tool (not release)not
* include syncAllPort section
*/
if (v_input->in_size > 16) {
if (buff_in->sync_all_port)
/* sync to all other lport */
unf_set_link_lose_tmo_to_all(buff_in->tmo_value);
else
unf_set_link_lose_tmo(v_lport,
buff_in->tmo_value);
buff_out->sync_all_port = 1;
} else {
unf_set_link_lose_tmo_to_all(buff_in->tmo_value);
}
buff_out->link_opt = 1;
/* return orige value */
buff_out->tmo_value = time_out;
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_NORMAL, UNF_KEVENT,
"[info]set fc port(0x%0x)link tmo value(%d -> %d) success .",
v_lport->nport_id, time_out, buff_out->tmo_value);
} else {
/* get link tmo value */
buff_out->tmo_value = unf_get_link_lose_tmo(v_lport);
buff_out->link_opt = 0;
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_NORMAL, UNF_MAJOR,
"get fc port(0x%0x) link tmo value(%d) success .",
v_lport->nport_id, buff_out->tmo_value);
}
*v_input->out_size = v_input->in_size;
memcpy((void *)buff_out, &msg_head, sizeof(struct unf_admin_msg_head));
return ret;
}
static int unf_cm_adm_log_level_opt(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_input)
{
int ret = RETURN_OK;
unsigned int log_level = 0;
unsigned int log_count = 0;
struct unf_log_level_opt_s *buff_in = NULL;
struct unf_log_level_opt_s *buff_out = NULL;
struct unf_admin_msg_head msg_head = { 0 };
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input,
return RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
v_input->in_size >= sizeof(struct unf_log_level_opt_s),
return RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
*v_input->out_size >=
sizeof(struct unf_log_level_opt_s),
return RETURN_ERROR);
buff_in = (struct unf_log_level_opt_s *)(v_input->buff_in);
buff_out = (struct unf_log_level_opt_s *)(v_input->buff_out);
msg_head.status = UNF_ADMIN_MSG_DONE;
msg_head.size = sizeof(struct unf_admin_msg_head);
if (buff_in->log_opt) {
/* set log level value */
log_level = log_print_level;
log_count = log_limted_times;
log_print_level = buff_in->log_level;
log_limted_times = buff_in->log_fre_qunce;
buff_out->log_opt = 1;
/* return orige value */
buff_out->log_level = log_level;
buff_out->log_fre_qunce = log_count;
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_NORMAL, UNF_MAJOR,
"set fc log level(%u -> %u), frenqunce(%u -> %u)in 2s success .",
log_level, log_print_level, log_count,
log_limted_times);
} else {
/* get link tmo value */
buff_out->log_level = log_print_level;
buff_out->log_fre_qunce = log_limted_times;
buff_out->log_opt = 0;
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_NORMAL, UNF_MAJOR,
"get fc log level(%u),frenqunce(%u) in 2s success .",
buff_out->log_level, buff_out->log_fre_qunce);
}
*v_input->out_size = sizeof(struct unf_log_level_opt_s);
memcpy((void *)buff_out, &msg_head, sizeof(struct unf_admin_msg_head));
return ret;
}
int unf_cm_echo_test(unsigned int v_port_id, unsigned int v_nport_id,
unsigned int *v_link_delay)
{
struct unf_lport_s *lport = NULL;
struct unf_rport_s *rport = NULL;
int ret = RETURN_OK;
unsigned int index = 0;
lport = unf_find_lport_by_port_id(v_port_id);
if (!lport) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_NORMAL, UNF_MAJOR,
"fcping request failed [invalid source lport (0x%x)].\n",
v_port_id);
return UNF_RETURN_ERROR;
}
rport = unf_get_rport_by_nport_id(lport, v_nport_id);
if ((!rport) || (v_nport_id == UNF_FC_FID_FLOGI)) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_NORMAL, UNF_MAJOR,
"fcping request failed [invalid destination rport(0x%x)].\n",
v_nport_id);
return UNF_RETURN_ERROR;
}
for (index = 0; index < UNF_ECHO_SEND_MAX_TIMES; index++) {
ret = (int)unf_send_echo(lport, rport, v_link_delay);
if (ret != RETURN_OK) {
*v_link_delay = 0xffffffff;
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_NORMAL,
UNF_MAJOR,
"fcping request failed [lport(0x%x)-> rport(0x%x)].\n",
v_port_id, v_nport_id);
} else {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_NORMAL,
UNF_MAJOR,
"fcping request succeed within %u us [lport(0x%x)->rport(0x%x)].\n",
*(unsigned int *)v_link_delay, v_port_id,
v_nport_id);
}
msleep(1000);
}
return ret;
}
static int unf_cm_link_delay_get(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_input)
{
int ret = UNF_RETURN_ERROR;
unsigned int link_delay = 0xffffffff;
unsigned int nport_id = 0xffffff;
unsigned int port_id = 0;
struct unf_adm_cmd *buff_in = NULL;
struct unf_adm_cmd *buff_out = NULL;
struct unf_admin_msg_head msg_head = { 0 };
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, *v_input->out_size >=
sizeof(struct unf_adm_cmd), return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input->in_size >=
sizeof(struct unf_adm_cmd), return UNF_RETURN_ERROR);
buff_in = (struct unf_adm_cmd *)(v_input->buff_in);
buff_out = (struct unf_adm_cmd *)(v_input->buff_out);
port_id = v_lport->port_id;
nport_id = buff_in->arg[0];
msg_head.status = UNF_ADMIN_MSG_DONE;
ret = unf_cm_echo_test(port_id, nport_id, &link_delay);
if ((ret == RETURN_OK) && (link_delay != 0xffffffff)) {
buff_out->arg[0] = link_delay;
msg_head.size = sizeof(struct unf_admin_msg_head) +
sizeof(unsigned int) * 1;
} else {
msg_head.status = UNF_ADMIN_MSG_FAILED;
msg_head.size = sizeof(struct unf_admin_msg_head);
}
*v_input->out_size = sizeof(struct unf_adm_cmd);
memcpy((void *)buff_out, &msg_head, sizeof(struct unf_admin_msg_head));
return ret;
}
static unsigned int unf_port_release_rport_index(struct unf_lport_s *v_lport,
void *v_input)
{
unsigned int index = INVALID_VALUE32;
unsigned int *rport_index = NULL;
unsigned long flag = 0;
struct unf_rport_pool_s *rport_pool = NULL;
UNF_CHECK_VALID(0x2370, UNF_FALSE, v_lport, return UNF_RETURN_ERROR);
if (v_input) {
rport_index = (unsigned int *)v_input;
index = *rport_index;
if (index < v_lport->low_level_func.support_max_rport) {
rport_pool = &((struct unf_lport_s *)v_lport->root_lport)->rport_pool;
spin_lock_irqsave(&rport_pool->rport_free_pool_lock,
flag);
if (test_bit((int)index, rport_pool->pul_rpi_bitmap))
clear_bit((int)index,
rport_pool->pul_rpi_bitmap);
else
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN,
UNF_LOG_LOGIN_ATT, UNF_ERR,
"[warn]Port(0x%x) try to release a free rport index(0x%x)",
v_lport->port_id, index);
spin_unlock_irqrestore(
&rport_pool->rport_free_pool_lock,
flag);
} else {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_LOGIN_ATT,
UNF_ERR,
"[warn]Port(0x%x) try to release a not exist rport index(0x%x)",
v_lport->port_id, index);
}
}
return RETURN_OK;
}
void *unf_lookup_lport_by_nport_id(void *v_lport, unsigned int v_nport_id)
{
struct unf_lport_s *lport = NULL;
struct unf_vport_pool_s *vport_pool = NULL;
struct unf_lport_s *vport = NULL;
struct list_head *node = NULL;
struct list_head *next_node = NULL;
unsigned long flag = 0;
UNF_CHECK_VALID(0x1978, UNF_TRUE, v_lport, return NULL);
lport = (struct unf_lport_s *)v_lport;
lport = lport->root_lport;
vport_pool = lport->vport_pool;
if (v_nport_id == lport->nport_id)
return lport;
if (unlikely(!vport_pool)) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_IO_ATT, UNF_WARN,
"[warn]Port(0x%x) vport pool is NULL",
lport->port_id);
return NULL;
}
spin_lock_irqsave(&vport_pool->vport_pool_lock, flag);
list_for_each_safe(node, next_node, &lport->list_vports_head) {
vport = list_entry(node, struct unf_lport_s, entry_vport);
if (vport->nport_id == v_nport_id) {
spin_unlock_irqrestore(&vport_pool->vport_pool_lock,
flag);
return vport;
}
}
list_for_each_safe(node, next_node, &lport->list_intergrad_vports) {
vport = list_entry(node, struct unf_lport_s, entry_vport);
if (vport->nport_id == v_nport_id) {
spin_unlock_irqrestore(&vport_pool->vport_pool_lock,
flag);
return vport;
}
}
spin_unlock_irqrestore(&vport_pool->vport_pool_lock, flag);
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_LOGIN_ATT, UNF_INFO,
"Port(0x%x) has no vport Nport ID(0x%x)",
lport->port_id, v_nport_id);
return NULL;
}
static int unf_get_port_info(struct unf_lport_s *v_lport,
struct unf_lport_info *v_port_info)
{
unsigned int act_speed = INVALID_VALUE32;
unsigned int cfg_speed = INVALID_VALUE32;
unsigned int cfg_topo = INVALID_VALUE32;
enum unf_act_topo_e act_topo = UNF_ACT_TOP_UNKNOWN;
struct unf_err_code_s fc_err_code;
unsigned int cfg_led_mode = INVALID_VALUE32;
struct unf_vport_pool_s *vport_pool = NULL;
struct unf_lport_s *vport = NULL;
struct list_head *node = NULL;
struct list_head *next_node = NULL;
unsigned long flag = 0;
UNF_CHECK_VALID(0x2205, UNF_TRUE, v_lport, return UNF_RETURN_ERROR);
UNF_CHECK_VALID(0x2206, UNF_TRUE, v_port_info, return UNF_RETURN_ERROR);
UNF_CHECK_VALID(0x2207, UNF_TRUE, v_lport->fc_port,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(
0x2208, UNF_TRUE,
v_lport->low_level_func.port_mgr_op.pfn_ll_port_config_get,
return UNF_RETURN_ERROR);
UNF_REFERNCE_VAR(cfg_speed);
UNF_REFERNCE_VAR(act_topo);
memset(&fc_err_code, 0, sizeof(fc_err_code));
/* get port speed */
cfg_speed = v_lport->low_level_func.lport_cfg_items.port_speed;
if (v_lport->link_up == UNF_PORT_LINK_UP)
(void)v_lport->low_level_func.port_mgr_op.pfn_ll_port_config_get(
v_lport->fc_port,
UNF_PORT_CFG_GET_SPEED_ACT, (void *)&act_speed);
else
act_speed = UNF_PORT_SPEED_UNKNOWN;
(void)v_lport->low_level_func.port_mgr_op.pfn_ll_port_config_get(
v_lport->fc_port,
UNF_PORT_CFG_GET_SPEED_CFG, (void *)&cfg_speed);
if (v_lport->link_up == UNF_PORT_LINK_UP)
(void)v_lport->low_level_func.port_mgr_op.pfn_ll_port_config_get(
v_lport->fc_port,
UNF_PORT_CFG_GET_TOPO_ACT, (void *)&act_topo);
else
act_topo = UNF_ACT_TOP_UNKNOWN;
(void)v_lport->low_level_func.port_mgr_op.pfn_ll_port_config_get(
v_lport->fc_port,
UNF_PORT_CFG_GET_TOPO_CFG, (void *)&cfg_topo);
(void)v_lport->low_level_func.port_mgr_op.pfn_ll_port_config_get(
v_lport->fc_port,
UNF_PORT_CFG_GET_LED_STATE, (void *)&cfg_led_mode);
v_port_info->port_id = v_lport->port_id;
v_port_info->options = v_lport->options;
v_port_info->b_start_work = global_lport_mgr.b_start_work;
v_port_info->phy_link = UNF_PORT_LINK_UP;
v_port_info->link_up = v_lport->link_up;
v_port_info->act_speed = act_speed;
v_port_info->cfg_speed = cfg_speed;
v_port_info->port_name = v_lport->port_name;
v_port_info->tape_support =
v_lport->low_level_func.lport_cfg_items.tape_support;
v_port_info->msi = 0;
v_port_info->ini_io_retry_timeout = 0;
v_port_info->support_max_npiv_num =
v_lport->low_level_func.support_max_npiv_num;
v_port_info->act_topo = act_topo;
v_port_info->port_topology =
v_lport->low_level_func.lport_cfg_items.port_topology;
v_port_info->fc_ser_max_speed =
v_lport->low_level_func.fc_ser_max_speed;
if (unf_get_error_code_sum(v_lport, &fc_err_code) != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_LOGIN_ATT, UNF_ERR,
"[err]Port(0x%x) get error code failed",
v_lport->port_id);
return UNF_RETURN_ERROR;
}
v_port_info->loss_of_signal_count = fc_err_code.loss_of_signal_count;
v_port_info->bad_rx_char_count = fc_err_code.bad_rx_char_count;
v_port_info->loss_of_sync_count = fc_err_code.loss_of_sync_count;
v_port_info->link_fail_count = fc_err_code.link_fail_count;
v_port_info->rx_eo_fa_count = fc_err_code.rx_eo_fa_count;
v_port_info->dis_frame_count = fc_err_code.dis_frame_count;
v_port_info->bad_crc_count = fc_err_code.bad_crc_count;
v_port_info->proto_error_count = fc_err_code.proto_error_count;
v_port_info->chip_type = v_lport->low_level_func.chip_info.chip_type;
v_port_info->cfg_led_mode = cfg_led_mode;
v_port_info->vport_num = 0;
vport_pool = v_lport->vport_pool;
if (unlikely(!vport_pool))
return RETURN_OK;
spin_lock_irqsave(&vport_pool->vport_pool_lock, flag);
list_for_each_safe(node, next_node, &v_lport->list_vports_head) {
vport = list_entry(node, struct unf_lport_s, entry_vport);
v_port_info->vport_id[v_port_info->vport_num] = vport->port_id;
v_port_info->vport_num = v_port_info->vport_num + 1;
}
spin_unlock_irqrestore(&vport_pool->vport_pool_lock, flag);
return RETURN_OK;
}
static int unf_get_vport_info(struct unf_lport_s *v_lport,
unsigned int v_vport_id,
struct unf_lport_info *v_port_info)
{
unsigned char vport_index = INVALID_VALUE8;
struct unf_lport_s *vport = NULL;
UNF_CHECK_VALID(0x2203, UNF_TRUE, v_lport, return UNF_RETURN_ERROR);
UNF_CHECK_VALID(0x2203, UNF_TRUE, v_port_info, return UNF_RETURN_ERROR);
vport_index = (v_vport_id & PORTID_VPINDEX_MASK) >> PORTID_VPINDEX_SHIT;
if (unlikely(vport_index == 0)) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_NORMAL, UNF_ERR,
"[err]VPortId(0x%x) is not vport", v_vport_id);
return UNF_RETURN_ERROR;
}
vport = unf_cm_lookup_vport_by_vp_index(v_lport, vport_index);
if (unlikely(!vport)) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_NORMAL, UNF_ERR,
"[err]VPortId(0x%x) can not be found",
v_vport_id);
return UNF_RETURN_ERROR;
}
v_port_info->port_id = vport->port_id;
v_port_info->port_name = vport->port_name;
v_port_info->nport_id = vport->nport_id;
v_port_info->options = 0;
return RETURN_OK;
}
static int unf_get_all_port_info(void *v_arg_in, void *v_arg_out)
{
struct unf_lport_s *lport = NULL;
struct unf_get_allinfo_argout *arg_in = NULL;
unsigned int current_len = 0;
struct unf_lport_info *cur_lport_info = NULL;
struct unf_admin_msg_head msg_head = { 0 };
int ret = UNF_RETURN_ERROR;
unsigned int out_buf_len = 0;
char *out_buf = NULL;
struct hifc_adm_cmd_s *buff_in = NULL;
UNF_CHECK_VALID(0x2203, UNF_TRUE, v_arg_in, return UNF_RETURN_ERROR);
UNF_REFERNCE_VAR(v_arg_out);
arg_in = (struct unf_get_allinfo_argout *)v_arg_in;
out_buf = (char *)arg_in->out_buf;
buff_in = (struct hifc_adm_cmd_s *)arg_in->in_buf;
lport = (struct unf_lport_s *)arg_in->lport;
UNF_CHECK_VALID(0x2203, UNF_TRUE, out_buf, return UNF_RETURN_ERROR);
UNF_CHECK_VALID(0x2203, UNF_TRUE, buff_in, return UNF_RETURN_ERROR);
UNF_CHECK_VALID(0x2203, UNF_TRUE, lport, return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, arg_in->in_size >=
sizeof(struct hifc_adm_cmd_s), return UNF_RETURN_ERROR);
cur_lport_info = vmalloc(sizeof(struct unf_lport_info));
if (!cur_lport_info) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_LOGIN_ATT, UNF_ERR,
"[err]Port(0x%x) malloc memory fail", lport->port_id);
((struct unf_admin_msg_head *)out_buf)->status =
UNF_ADMIN_MSG_FAILED;
return ret;
}
memset(cur_lport_info, 0, sizeof(struct unf_lport_info));
out_buf_len = arg_in->in_size;
msg_head.status = UNF_ADMIN_MSG_DONE;
*arg_in->out_size = out_buf_len;
/* Storage info */
current_len += sizeof(struct unf_admin_msg_head);
if (lport->b_port_removing != UNF_TRUE) {
/* Cmd[3] is Vportid */
if (buff_in->cmd[3] != 0) {
ret = unf_get_vport_info(lport, buff_in->cmd[3],
cur_lport_info);
} else {
ret = unf_get_port_info(lport, cur_lport_info);
}
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_LOGIN_ATT,
UNF_INFO,
"[err]Port(0x%x) get port information error",
lport->port_id);
msg_head.status = UNF_ADMIN_MSG_FAILED;
msg_head.size = current_len;
memcpy(out_buf, &msg_head,
sizeof(struct unf_admin_msg_head));
vfree(cur_lport_info);
return ret;
}
if (out_buf_len < current_len + sizeof(struct unf_lport_info)) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_NORMAL,
UNF_ERR,
"[warn]Allocated buff size (%u < %lu) is not enough",
out_buf_len,
current_len + sizeof(struct unf_lport_info));
/* Compatible for vport: return Lport info
* if tools version is not support npiv
*/
memcpy(out_buf + current_len, cur_lport_info,
out_buf_len - current_len);
current_len = out_buf_len;
} else {
memcpy(out_buf + current_len, cur_lport_info,
sizeof(struct unf_lport_info));
current_len += sizeof(struct unf_lport_info);
}
} else {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_LOGIN_ATT, UNF_INFO,
"[warn]Port(0x%x) is removing. Ref count 0x%x",
lport->port_id, atomic_read(&lport->lport_ref_cnt));
msg_head.status = UNF_ADMIN_MSG_FAILED;
}
msg_head.size = current_len;
memcpy(out_buf, &msg_head, sizeof(struct unf_admin_msg_head));
vfree(cur_lport_info);
return ret;
}
static int unf_cm_get_all_port_info(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_input)
{
struct unf_get_allinfo_argout out = { 0 };
int ret = UNF_RETURN_ERROR;
out.out_buf = v_input->buff_out;
out.in_buf = v_input->buff_in;
out.out_size = v_input->out_size;
out.in_size = v_input->in_size;
out.lport = v_lport;
ret = (int)unf_schedule_global_event((void *)&out,
UNF_GLOBAL_EVENT_SYN,
unf_get_all_port_info);
return ret;
}
static int unf_cm_port_set(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_input)
{
int ret = UNF_RETURN_ERROR;
unsigned int mode = 0; /* 1:portreset 2:sfp on/off */
int turn_on = 0; /* 0:sfp off 1:sfp on */
unsigned int port_id = 0;
void *out_buf = NULL;
struct unf_adm_cmd *buff_in = NULL;
struct unf_admin_msg_head msg_head = { 0 };
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input->in_size >=
sizeof(struct unf_adm_cmd), return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, *v_input->out_size >=
sizeof(struct unf_adm_cmd), return UNF_RETURN_ERROR);
out_buf = v_input->buff_out;
buff_in = v_input->buff_in;
mode = buff_in->arg[0];
port_id = v_lport->port_id;
msg_head.status = UNF_ADMIN_MSG_DONE;
if (mode == 1) {
ret = unf_cm_reset_port(port_id);
if (ret != RETURN_OK)
msg_head.status = UNF_ADMIN_MSG_FAILED;
} else if (mode == 2) {
turn_on = (int)buff_in->arg[1];
if ((turn_on == 0) || (turn_on == 1)) {
ret = unf_cm_sfp_switch(port_id, turn_on);
if (ret != RETURN_OK)
msg_head.status = UNF_ADMIN_MSG_FAILED;
} else {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT,
UNF_ERR,
"[err]Switch sfp failed. Parameter(0x%x) error",
turn_on);
msg_head.status = UNF_ADMIN_MSG_FAILED;
}
}
msg_head.size = sizeof(struct unf_admin_msg_head);
*v_input->out_size = sizeof(struct unf_adm_cmd);
memcpy(out_buf, &msg_head, sizeof(struct unf_admin_msg_head));
return ret;
}
static int unf_cm_topo_set(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_input)
{
int ret = UNF_RETURN_ERROR;
unsigned int topo = 0; /* topology set */
unsigned int port_id = 0;
void *out_buf = NULL;
struct unf_adm_cmd *buff_in = NULL;
struct unf_admin_msg_head msg_head = { 0 };
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input->in_size >=
sizeof(struct unf_adm_cmd), return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, *v_input->out_size >=
sizeof(struct unf_adm_cmd), return UNF_RETURN_ERROR);
out_buf = v_input->buff_out;
buff_in = v_input->buff_in;
topo = buff_in->arg[0];
port_id = v_lport->port_id;
msg_head.status = UNF_ADMIN_MSG_DONE;
if ((topo == UNF_TOP_AUTO_MASK) || (topo == UNF_TOP_LOOP_MASK) ||
(topo == UNF_TOP_P2P_MASK)) {
ret = unf_cm_set_port_topo(port_id, topo);
if (ret != RETURN_OK)
msg_head.status = UNF_ADMIN_MSG_FAILED;
} else {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR,
"[err]Set topo failed. Parameter(0x%x) error", topo);
msg_head.status = UNF_ADMIN_MSG_FAILED;
}
msg_head.size = sizeof(struct unf_admin_msg_head);
*v_input->out_size = sizeof(struct unf_adm_cmd);
memcpy(out_buf, &msg_head, sizeof(struct unf_admin_msg_head));
return ret;
}
static int unf_cm_port_speed_set(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_input)
{
int ret = UNF_RETURN_ERROR;
unsigned int port_speed = 0;
unsigned int port_id = 0;
void *out_buf = NULL;
struct unf_adm_cmd *buff_in = NULL;
struct unf_admin_msg_head msg_head = { 0 };
struct unf_lport_s *lport = NULL;
int check_speed_flag = UNF_TRUE;
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_lport,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
v_input->in_size >= sizeof(struct unf_adm_cmd),
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
*v_input->out_size >= sizeof(struct unf_adm_cmd),
return UNF_RETURN_ERROR);
lport = v_lport;
out_buf = v_input->buff_out;
buff_in = v_input->buff_in;
port_speed = buff_in->arg[0];
port_id = v_lport->port_id;
msg_head.status = UNF_ADMIN_MSG_DONE;
/* get and check sfp speed */
if (unf_get_lport_current_info(lport) != RETURN_OK) {
msg_head.status = UNF_ADMIN_MSG_FAILED;
lport->low_level_func.sfp_speed = UNF_PORT_SFP_SPEED_ERR;
}
if (UNF_CHECK_CONFIG_SPEED_BY_SFSSPEED(lport->low_level_func.sfp_speed,
port_speed)) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR,
"[err]Set port speed failed. Speed (0x%x) is greater than SfpSpeed (0x%x)",
port_speed, lport->low_level_func.sfp_speed);
msg_head.status = UNF_ADMIN_MSG_FAILED;
check_speed_flag = UNF_FALSE;
} else {
if (lport->low_level_func.fc_ser_max_speed ==
UNF_PORT_SPEED_32_G) {
check_speed_flag =
(port_speed == UNF_PORT_SPEED_AUTO) ||
(port_speed == UNF_PORT_SPEED_8_G) ||
(port_speed == UNF_PORT_SPEED_16_G) ||
(port_speed == UNF_PORT_SPEED_32_G);
} else if (lport->low_level_func.fc_ser_max_speed ==
UNF_PORT_SPEED_16_G) {
check_speed_flag =
(port_speed == UNF_PORT_SPEED_AUTO) ||
(port_speed == UNF_PORT_SPEED_4_G) ||
(port_speed == UNF_PORT_SPEED_8_G) ||
(port_speed == UNF_PORT_SPEED_16_G);
} else if (lport->low_level_func.fc_ser_max_speed ==
UNF_PORT_SPEED_8_G) {
check_speed_flag =
(port_speed == UNF_PORT_SPEED_AUTO) ||
(port_speed == UNF_PORT_SPEED_2_G) ||
(port_speed == UNF_PORT_SPEED_4_G) ||
(port_speed == UNF_PORT_SPEED_8_G);
} else {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT,
UNF_ERR,
"[err]Board maxspeed is unknown");
msg_head.status = UNF_ADMIN_MSG_FAILED;
check_speed_flag = UNF_FALSE;
}
}
if (check_speed_flag) {
ret = unf_cm_set_port_speed(port_id, &port_speed);
if (ret != RETURN_OK)
msg_head.status = UNF_ADMIN_MSG_FAILED;
}
msg_head.size = sizeof(struct unf_admin_msg_head);
*v_input->out_size = sizeof(struct unf_adm_cmd);
memcpy(out_buf, &msg_head, sizeof(struct unf_admin_msg_head));
return ret;
}
static int unf_cm_set_vport(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_input)
{
unsigned int ret = UNF_RETURN_ERROR;
struct unf_lport_s *lport = NULL;
unsigned int mode = 0;
unsigned int index = 0;
unsigned int high32 = 0x2000286e;
unsigned int low32 = 0;
unsigned long long port_name = 0;
unsigned int port_id = 0;
void *out_buf = NULL;
struct unf_adm_cmd *buff_in = NULL;
struct unf_admin_msg_head msg_head = { 0 };
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
v_input->in_size >= sizeof(struct unf_adm_cmd),
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
*v_input->out_size >= sizeof(struct unf_adm_cmd),
return UNF_RETURN_ERROR);
out_buf = v_input->buff_out;
buff_in = v_input->buff_in;
port_id = v_lport->port_id;
msg_head.status = UNF_ADMIN_MSG_DONE;
mode = buff_in->arg[0];
switch (mode) {
case 1:
/* create vport with wwpn */
low32 = buff_in->arg[1];
port_name = ((unsigned long)high32 << 32) | low32;
//lint -fallthrough
case 3:
/* create vport and autogeneration wwpn */
ret = unf_npiv_conf(port_id, port_name);
if (ret != RETURN_OK)
msg_head.status = UNF_ADMIN_MSG_FAILED;
msleep(2000);
break;
case 2:
/* delete vport by vport index */
index = buff_in->arg[2];
ret = unf_delete_vport(port_id, index);
if (ret != RETURN_OK)
msg_head.status = UNF_ADMIN_MSG_FAILED;
break;
case 4:
/* delete all vport on Lport */
lport = unf_find_lport_by_port_id(port_id);
if (!lport) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_NORMAL,
UNF_ERR,
"[err]Port(0x%x) can't find", port_id);
msg_head.status = UNF_ADMIN_MSG_FAILED;
} else {
unf_destroy_all_vports(lport);
ret = RETURN_OK;
}
break;
default:
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_NORMAL, UNF_ERR,
"[err]Mode is unknown");
msg_head.status = UNF_ADMIN_MSG_FAILED;
break;
}
msg_head.size = sizeof(struct unf_admin_msg_head);
*v_input->out_size = sizeof(struct unf_adm_cmd);
memcpy(out_buf, &msg_head, sizeof(struct unf_admin_msg_head));
return (int)ret;
}
static int unf_cm_port_info_get(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_input)
{
int ret = UNF_RETURN_ERROR;
unsigned int topo_cfg = 0;
enum unf_act_topo_e topo = UNF_ACT_TOP_UNKNOWN;
unsigned int port_speed = 0;
unsigned int port_id = 0;
struct unf_adm_cmd *buff_out = NULL;
struct unf_admin_msg_head msg_head = { 0 };
struct unf_lport_s *lport = NULL;
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
*v_input->out_size >= sizeof(struct unf_adm_cmd),
return UNF_RETURN_ERROR);
lport = v_lport;
port_id = v_lport->port_id;
buff_out = (struct unf_adm_cmd *)v_input->buff_out;
msg_head.status = UNF_ADMIN_MSG_DONE;
ret = unf_cm_get_port_topo(port_id, &topo_cfg, &topo);
if (ret == RETURN_OK) {
ret = unf_cm_get_port_speed(port_id, &port_speed);
if (ret == RETURN_OK) {
buff_out->arg[0] = lport->port_id;
buff_out->arg[1] = topo_cfg;
buff_out->arg[2] = topo;
buff_out->arg[3] = port_speed;
buff_out->arg[4] = lport->link_up;
msg_head.size = sizeof(struct unf_admin_msg_head) +
sizeof(unsigned int) * 5;
} else {
msg_head.status = UNF_ADMIN_MSG_FAILED;
msg_head.size = sizeof(struct unf_admin_msg_head);
}
} else {
msg_head.status = UNF_ADMIN_MSG_FAILED;
msg_head.size = sizeof(struct unf_admin_msg_head);
}
*v_input->out_size = sizeof(struct unf_adm_cmd);
memcpy(buff_out, &msg_head, sizeof(struct unf_admin_msg_head));
return ret;
}
static int unf_get_port_sfp_info(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_input)
{
#define MIN_SFPINFO_LEN 512
union unf_sfp_eeprome_info *sfp_info = NULL;
int ret = UNF_RETURN_ERROR;
unsigned int status = 0;
unsigned int sfp_type = 0;
unsigned int port_id = 0;
char *buff_out = NULL;
struct unf_admin_msg_head msg_head = { 0 };
UNF_CHECK_VALID(0x2203, UNF_TRUE, v_input, return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
*v_input->out_size >= MIN_SFPINFO_LEN,
return UNF_RETURN_ERROR);
buff_out = v_input->buff_out;
port_id = v_lport->port_id;
*v_input->out_size = MIN_SFPINFO_LEN;
msg_head.status = UNF_ADMIN_MSG_DONE;
sfp_info = vmalloc(sizeof(union unf_sfp_eeprome_info));
if (!sfp_info)
return UNF_RETURN_ERROR;
memset(sfp_info, 0, sizeof(union unf_sfp_eeprome_info));
ret = unf_cm_get_sfp_info(port_id, &status, sfp_info, &sfp_type);
if (ret == UNF_RETURN_ERROR || (status != DRV_CABLE_CONNECTOR_OPTICAL))
msg_head.status = UNF_ADMIN_MSG_FAILED;
msg_head.size = sizeof(struct unf_admin_msg_head);
memcpy(buff_out, &msg_head, sizeof(struct unf_admin_msg_head));
memcpy((buff_out + msg_head.size),
&sfp_info->sfp_info, sizeof(struct unf_sfp_info_s));
vfree(sfp_info);
return ret;
}
static int unf_cm_clear_error_code_sum(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_input)
{
int ret = RETURN_OK;
void *out_buf = NULL;
unsigned int port_id = 0;
struct unf_admin_msg_head msg_head = { 0 };
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
*v_input->out_size >= sizeof(struct unf_adm_cmd),
return UNF_RETURN_ERROR);
out_buf = v_input->buff_out;
port_id = v_lport->port_id;
msg_head.status = UNF_ADMIN_MSG_DONE;
ret = unf_cm_clear_port_error_code_sum(port_id);
if (ret != RETURN_OK)
msg_head.status = UNF_ADMIN_MSG_FAILED;
msg_head.size = sizeof(struct unf_admin_msg_head);
*v_input->out_size = sizeof(struct unf_adm_cmd);
memcpy(out_buf, &msg_head, sizeof(struct unf_admin_msg_head));
return ret;
}
static int unf_cm_bbscn_set(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_input)
{
int ret = UNF_RETURN_ERROR;
unsigned int bbscn_val = 0;
unsigned int port_id = 0;
void *out_buf = NULL;
struct unf_adm_cmd *buff_in = NULL;
struct unf_admin_msg_head msg_head = { 0 };
UNF_CHECK_VALID(INVALID_VALUE32,
UNF_TRUE, v_input, return UNF_RETURN_ERROR);
out_buf = v_input->buff_out;
buff_in = v_input->buff_in;
port_id = v_lport->port_id;
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
out_buf, return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
buff_in, return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
v_input->in_size >= sizeof(struct unf_adm_cmd),
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
*v_input->out_size >= sizeof(struct unf_adm_cmd),
return UNF_RETURN_ERROR);
bbscn_val = buff_in->arg[1];
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"[info]BBSCN value (0x%x)", bbscn_val);
msg_head.status = UNF_ADMIN_MSG_DONE;
if (bbscn_val <= UNF_MAX_BBSCN_VALUE) {
ret = unf_cm_set_port_bbscn(port_id, bbscn_val);
if (ret != RETURN_OK)
msg_head.status = UNF_ADMIN_MSG_FAILED;
} else {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR,
"[err]BBSCN value is invalid(0x%x)", bbscn_val);
msg_head.status = UNF_ADMIN_MSG_FAILED;
}
msg_head.size = sizeof(struct unf_admin_msg_head);
*v_input->out_size = sizeof(struct unf_adm_cmd);
memcpy(out_buf, &msg_head, sizeof(struct unf_admin_msg_head));
return ret;
}
static void unf_fc_host_counter(struct unf_lport_s *v_lport,
struct hifc_adm_dfx_cmd_s *v_buff_out)
{
unsigned int scsi_id = 0;
unsigned int index = 0;
struct unf_rport_scsi_id_image_s *scsi_image_table = NULL;
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_lport, return);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_buff_out, return);
scsi_image_table = &v_lport->rport_scsi_table;
v_buff_out->unresult.host_cnt.host_num =
v_lport->host_info.p_scsi_host->host_no;
v_buff_out->unresult.host_cnt.port_id = v_lport->port_id;
v_buff_out->unresult.host_cnt.scsi_session_add_success =
atomic_read(&v_lport->scsi_session_add_success);
v_buff_out->unresult.host_cnt.scsi_session_add_failed =
atomic_read(&v_lport->scsi_session_add_failed);
v_buff_out->unresult.host_cnt.scsi_session_del_success =
atomic_read(&v_lport->scsi_session_del_success);
v_buff_out->unresult.host_cnt.scsi_session_del_failed =
atomic_read(&v_lport->scsi_session_del_failed);
v_buff_out->unresult.host_cnt.device_alloc =
atomic_read(&v_lport->device_alloc);
v_buff_out->unresult.host_cnt.device_destroy =
atomic_read(&v_lport->device_destroy);
v_buff_out->unresult.host_cnt.session_loss_tmo =
atomic_read(&v_lport->session_loss_tmo);
v_buff_out->unresult.host_cnt.alloc_scsi_id =
atomic_read(&v_lport->alloc_scsi_id);
v_buff_out->unresult.host_cnt.reuse_scsi_id =
atomic_read(&v_lport->reuse_scsi_id);
v_buff_out->unresult.host_cnt.resume_scsi_id =
atomic_read(&v_lport->resume_scsi_id);
v_buff_out->unresult.host_cnt.add_start_work_failed =
atomic_read(&v_lport->add_start_work_failed);
v_buff_out->unresult.host_cnt.add_closing_work_failed =
atomic_read(&v_lport->add_closing_work_failed);
for (scsi_id = 0; scsi_id < UNF_MAX_SCSI_ID / 2; scsi_id++) {
index = scsi_id * 2;
v_buff_out->unresult.host_cnt.session_state[scsi_id].session1 =
(unsigned char)atomic_read(&scsi_image_table->wwn_rport_info_table[index].en_scsi_state);
index = scsi_id * 2 + 1;
v_buff_out->unresult.host_cnt.session_state[scsi_id].session2 =
(unsigned char)atomic_read(&scsi_image_table->wwn_rport_info_table[index].en_scsi_state);
}
for (scsi_id = 0; scsi_id < UNF_MAX_SCSI_ID; scsi_id++) {
if (!scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter)
continue;
v_buff_out->unresult.host_cnt.abort_io +=
atomic_read(&scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter->error_handle[UNF_SCSI_ABORT_IO_TYPE]);
v_buff_out->unresult.host_cnt.device_reset +=
atomic_read(&scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter->error_handle[UNF_SCSI_DEVICE_RESET_TYPE]);
v_buff_out->unresult.host_cnt.target_reset +=
atomic_read(&scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter->error_handle[UNF_SCSI_TARGET_RESET_TYPE]);
v_buff_out->unresult.host_cnt.bus_reset +=
atomic_read(&scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter->error_handle[UNF_SCSI_BUS_RESET_TYPE]);
v_buff_out->unresult.host_cnt.virtual_reset +=
atomic_read(&scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter->error_handle[UNF_SCSI_VIRTUAL_RESET_TYPE]);
v_buff_out->unresult.host_cnt.abort_io_result +=
atomic_read(&scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter->error_handle_result[UNF_SCSI_ABORT_IO_TYPE]);
v_buff_out->unresult.host_cnt.device_reset_result +=
atomic_read(&scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter->error_handle_result[UNF_SCSI_DEVICE_RESET_TYPE]);
v_buff_out->unresult.host_cnt.target_reset_result +=
atomic_read(&scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter->error_handle_result[UNF_SCSI_TARGET_RESET_TYPE]);
v_buff_out->unresult.host_cnt.bus_reset_result +=
atomic_read(&scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter->error_handle_result[UNF_SCSI_BUS_RESET_TYPE]);
v_buff_out->unresult.host_cnt.virtual_reset_result +=
atomic_read(&scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter->error_handle_result[UNF_SCSI_VIRTUAL_RESET_TYPE]);
}
}
static void unf_fc_session_counter(struct unf_lport_s *v_lport,
unsigned int scsi_id,
struct hifc_adm_dfx_cmd_s *v_buff_out)
{
struct unf_wwpn_rport_info_s *rport_info = NULL;
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_lport, return);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_buff_out, return);
rport_info = &v_lport->rport_scsi_table.wwn_rport_info_table[scsi_id];
v_buff_out->unresult.session_cnt.port_id = v_lport->port_id;
v_buff_out->unresult.session_cnt.host_id =
v_lport->host_info.p_scsi_host->host_no;
if (rport_info->dfx_counter) {
v_buff_out->unresult.session_cnt.target_busy =
atomic64_read(&rport_info->dfx_counter->target_busy);
v_buff_out->unresult.session_cnt.host_busy =
atomic64_read(&rport_info->dfx_counter->host_busy);
v_buff_out->unresult.session_cnt.abort_io =
atomic_read(&rport_info->dfx_counter->error_handle[UNF_SCSI_ABORT_IO_TYPE]);
v_buff_out->unresult.session_cnt.device_reset =
atomic_read(&rport_info->dfx_counter->error_handle[UNF_SCSI_DEVICE_RESET_TYPE]);
v_buff_out->unresult.session_cnt.target_reset =
atomic_read(&rport_info->dfx_counter->error_handle[UNF_SCSI_TARGET_RESET_TYPE]);
v_buff_out->unresult.session_cnt.bus_reset =
atomic_read(&rport_info->dfx_counter->error_handle[UNF_SCSI_BUS_RESET_TYPE]);
v_buff_out->unresult.session_cnt.virtual_reset =
atomic_read(&rport_info->dfx_counter->error_handle[UNF_SCSI_VIRTUAL_RESET_TYPE]);
v_buff_out->unresult.session_cnt.abort_io_result =
atomic_read(&rport_info->dfx_counter->error_handle_result[UNF_SCSI_ABORT_IO_TYPE]);
v_buff_out->unresult.session_cnt.device_reset_result =
atomic_read(&rport_info->dfx_counter->error_handle_result[UNF_SCSI_DEVICE_RESET_TYPE]);
v_buff_out->unresult.session_cnt.target_reset_result =
atomic_read(&rport_info->dfx_counter->error_handle_result[UNF_SCSI_TARGET_RESET_TYPE]);
v_buff_out->unresult.session_cnt.bus_reset_result =
atomic_read(&rport_info->dfx_counter->error_handle_result[UNF_SCSI_BUS_RESET_TYPE]);
v_buff_out->unresult.session_cnt.virtual_reset_result =
atomic_read(&rport_info->dfx_counter->error_handle_result[UNF_SCSI_VIRTUAL_RESET_TYPE]);
v_buff_out->unresult.session_cnt.device_alloc =
atomic_read(&rport_info->dfx_counter->device_alloc);
v_buff_out->unresult.session_cnt.device_destroy =
atomic_read(&rport_info->dfx_counter->device_destroy);
}
v_buff_out->unresult.session_cnt.target_id = rport_info->target_id;
if ((rport_info->wwpn != INVALID_WWPN) && (rport_info->rport)) {
v_buff_out->unresult.session_cnt.remote_port_wwpn =
rport_info->wwpn;
v_buff_out->unresult.session_cnt.remote_port_nportid =
rport_info->rport->nport_id;
v_buff_out->unresult.session_cnt.scsi_state =
atomic_read(&rport_info->en_scsi_state);
v_buff_out->unresult.session_cnt.remote_port_state =
rport_info->rport->rp_state;
v_buff_out->unresult.session_cnt.remote_port_scsiid =
rport_info->rport->scsi_id;
v_buff_out->unresult.session_cnt.remote_port_index =
rport_info->rport->rport_index;
if (rport_info->rport->lport) {
v_buff_out->unresult.session_cnt.local_port_wwpn =
rport_info->rport->lport->port_name;
v_buff_out->unresult.session_cnt.local_port_nportid =
rport_info->rport->local_nport_id;
v_buff_out->unresult.session_cnt.local_port_ini_state =
rport_info->rport->lport_ini_state;
v_buff_out->unresult.session_cnt.local_port_state =
rport_info->rport->lport->en_states;
}
}
}
static int unf_fc_session_scsi_cmd_in(
struct unf_hinicam_pkg *v_input,
struct unf_rport_scsi_id_image_s *scsi_image_table)
{
unsigned int scsi_id = 0;
unsigned int scsi_cmd_type = 0;
int ret = RETURN_OK;
struct hifc_adm_dfx_cmd_s *buff_out = NULL;
struct unf_adm_cmd *buff_in = NULL;
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, scsi_image_table,
return UNF_RETURN_ERROR);
buff_in = (struct unf_adm_cmd *)v_input->buff_in;
buff_out = (struct hifc_adm_dfx_cmd_s *)v_input->buff_out;
scsi_id = buff_in->arg[2];
scsi_cmd_type = buff_in->arg[3];
if (scsi_id >= UNF_MAX_SCSI_ID || scsi_cmd_type >= UNF_MAX_SCSI_CMD)
return UNF_RETURN_ERROR;
if (scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter)
buff_out->unresult.scsi_cmd_in =
atomic64_read(&scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter->scsi_cmd_cnt[scsi_cmd_type]);
return ret;
}
static int unf_fc_host_scsi_cmd_in_total(
struct unf_hinicam_pkg *v_input,
struct unf_rport_scsi_id_image_s *scsi_image_table)
{
unsigned int scsi_id = 0;
unsigned int scsi_cmd_type = 0;
struct hifc_adm_dfx_cmd_s *buff_out = NULL;
struct unf_adm_cmd *buff_in = NULL;
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, scsi_image_table,
return UNF_RETURN_ERROR);
buff_in = (struct unf_adm_cmd *)v_input->buff_in;
buff_out = (struct hifc_adm_dfx_cmd_s *)v_input->buff_out;
scsi_cmd_type = buff_in->arg[3];
if (scsi_cmd_type >= UNF_MAX_SCSI_CMD)
return UNF_RETURN_ERROR;
for (scsi_id = 0; scsi_id < UNF_MAX_SCSI_ID; scsi_id++) {
if (!scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter)
continue;
buff_out->unresult.scsi_cmd_in +=
atomic64_read(&scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter->scsi_cmd_cnt[scsi_cmd_type]);
}
return RETURN_OK;
}
static int unf_fc_host_scsi_cmd_done_total(
struct unf_hinicam_pkg *v_input,
struct unf_rport_scsi_id_image_s *scsi_image_table)
{
unsigned int scsi_id = 0;
unsigned int io_return_value = 0;
int ret = RETURN_OK;
struct hifc_adm_dfx_cmd_s *buff_out = NULL;
struct unf_adm_cmd *buff_in = NULL;
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, scsi_image_table,
return UNF_RETURN_ERROR);
buff_in = (struct unf_adm_cmd *)v_input->buff_in;
buff_out = (struct hifc_adm_dfx_cmd_s *)v_input->buff_out;
io_return_value = buff_in->arg[3];
if (io_return_value >= UNF_MAX_IO_RETURN_VALUE)
return UNF_RETURN_ERROR;
for (scsi_id = 0; scsi_id < UNF_MAX_SCSI_ID; scsi_id++) {
if (!scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter)
continue;
buff_out->unresult.scsi_cmd_done +=
atomic64_read(&scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter->io_done_cnt[io_return_value]);
}
return ret;
}
static int unf_fc_session_scsi_cmd_done(
struct unf_hinicam_pkg *v_input,
struct unf_rport_scsi_id_image_s *scsi_image_table)
{
unsigned int scsi_id = 0;
unsigned int io_return_value = 0;
int ret = RETURN_OK;
struct hifc_adm_dfx_cmd_s *buff_out = NULL;
struct unf_adm_cmd *buff_in = NULL;
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, scsi_image_table,
return UNF_RETURN_ERROR);
buff_in = (struct unf_adm_cmd *)v_input->buff_in;
buff_out = (struct hifc_adm_dfx_cmd_s *)v_input->buff_out;
scsi_id = buff_in->arg[2];
io_return_value = buff_in->arg[3];
if (scsi_id >= UNF_MAX_SCSI_ID ||
io_return_value >= UNF_MAX_IO_RETURN_VALUE)
return UNF_RETURN_ERROR;
if (scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter)
buff_out->unresult.scsi_cmd_done =
atomic64_read(&scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter->io_done_cnt[io_return_value]);
return ret;
}
static int unf_get_io_dfx_statistics(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_input)
{
int ret = RETURN_OK;
unsigned int counter_mode = 0;
struct hifc_adm_dfx_cmd_s *buff_out = NULL;
struct unf_adm_cmd *buff_in = NULL;
struct unf_admin_msg_head msg_head = { 0 };
struct unf_rport_scsi_id_image_s *scsi_image_table = NULL;
unsigned int scsi_id = 0;
struct unf_lport_s *vport = NULL;
unsigned int buff_flag = 0;
buff_flag = (!v_input) || (!v_input->buff_out) ||
(!v_input->buff_in) || (!v_lport);
if (buff_flag)
return UNF_RETURN_ERROR;
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
v_input->in_size >= sizeof(struct unf_adm_cmd),
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
*v_input->out_size >= sizeof(struct hifc_adm_dfx_cmd_s),
return UNF_RETURN_ERROR);
buff_in = (struct unf_adm_cmd *)v_input->buff_in;
buff_out = (struct hifc_adm_dfx_cmd_s *)v_input->buff_out;
msg_head.status = UNF_ADMIN_MSG_DONE;
vport = unf_cm_lookup_vport_by_vp_index(
v_lport, (unsigned short)(buff_in->arg[4]));
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, vport,
return UNF_RETURN_ERROR);
scsi_image_table = &vport->rport_scsi_table;
FC_DRIVE_ACTION_CHECK((!scsi_image_table->wwn_rport_info_table),
(msg_head.status = UNF_ADMIN_MSG_FAILED),
(ret = UNF_RETURN_ERROR),
goto err);
counter_mode = buff_in->arg[1];
switch (counter_mode) {
case FC_HOST_COUNTER:
unf_fc_host_counter(vport, buff_out);
break;
case FC_SESSION_SCSI_CMD_IN:
ret = unf_fc_session_scsi_cmd_in(v_input, scsi_image_table);
break;
case FC_HOST_SCSI_CMD_IN_TOTAL:
ret = unf_fc_host_scsi_cmd_in_total(v_input, scsi_image_table);
break;
case FC_HOST_SCSI_CMD_DONE_TOTAL:
ret = unf_fc_host_scsi_cmd_done_total(v_input,
scsi_image_table);
break;
case FC_SESSION_SCSI_CMD_DONE:
ret = unf_fc_session_scsi_cmd_done(v_input, scsi_image_table);
break;
case FC_SESSION_COUNTER:
scsi_id = buff_in->arg[2];
FC_DRIVE_ACTION_CHECK((scsi_id >= UNF_MAX_SCSI_ID),
(msg_head.status = UNF_ADMIN_MSG_FAILED),
(ret = UNF_RETURN_ERROR),
goto err);
unf_fc_session_counter(vport, scsi_id, buff_out);
break;
default:
msg_head.status = UNF_ADMIN_MSG_FAILED;
ret = UNF_RETURN_ERROR;
break;
}
if (ret != RETURN_OK)
return ret;
err:
msg_head.size = sizeof(struct unf_admin_msg_head);
*v_input->out_size = sizeof(struct hifc_adm_dfx_cmd_s);
memcpy(buff_out, &msg_head, sizeof(struct unf_admin_msg_head));
return ret;
}
static int unf_cm_switch_dif(unsigned int v_option,
unsigned int v_dix_ip_checksum)
{
#define UNF_WAIT_IO_COMPLETE_TIME_MS 5000
#define UNF_WAIT_ONE_TIME_MS 100
#define UNF_LOOP_TIMES (UNF_WAIT_IO_COMPLETE_TIME_MS / UNF_WAIT_ONE_TIME_MS)
int ret = UNF_RETURN_ERROR;
struct unf_lport_s *lport = NULL;
unsigned long flags = 0;
int enable_dif;
unsigned int index;
dix_flag = v_dix_ip_checksum ? UNF_TRUE : UNF_FALSE;
enable_dif = (v_option >= UNF_ENABLE_DIF_DIX_PROT &&
v_option <= UNF_ENABLE_DIX_PROT);
if (enable_dif) {
dif_sgl_mode = UNF_TRUE;
hifc_dif_enable = UNF_TRUE;
}
switch (v_option) {
case UNF_DIF_ACTION_NONE:
dif_sgl_mode = UNF_FALSE;
hifc_dif_enable = UNF_FALSE;
hifc_dif_type = 0;
hifc_guard = 0;
break;
case UNF_ENABLE_DIF_DIX_PROT:
hifc_dif_type = SHOST_DIF_TYPE1_PROTECTION |
SHOST_DIX_TYPE1_PROTECTION;
break;
case UNF_ENABLE_DIF_PROT:
hifc_dif_type = SHOST_DIF_TYPE1_PROTECTION;
dif_sgl_mode = UNF_FALSE;
break;
case UNF_ENABLE_DIX_PROT:
hifc_dif_type = SHOST_DIX_TYPE0_PROTECTION;
break;
default:
return UNF_ADMIN_MSG_FAILED;
}
/* 1. Close Lport's SFP */
spin_lock_irqsave(&global_lport_mgr.global_lport_list_lock, flags);
list_for_each_entry(lport, &global_lport_mgr.list_lport_list_head,
entry_lport) {
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock,
flags);
ret = unf_cm_sfp_switch(lport->port_id, UNF_FALSE);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT,
UNF_ERR,
"[err]Port(0x%x) close SFP failed in DIF switch",
lport->port_id);
return UNF_ADMIN_MSG_FAILED;
}
for (index = 0; index < UNF_LOOP_TIMES; index++) {
if (unf_busy_io_completed(lport) == UNF_TRUE)
break;
msleep(UNF_WAIT_ONE_TIME_MS);
}
spin_lock_irqsave(&global_lport_mgr.global_lport_list_lock,
flags);
}
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock,
flags);
/* 2. UnRegister the SCSI host of LPort, including its Vports */
spin_lock_irqsave(&global_lport_mgr.global_lport_list_lock, flags);
list_for_each_entry(lport, &global_lport_mgr.list_lport_list_head,
entry_lport) {
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock,
flags);
unf_unregister_scsi_host(lport);
spin_lock_irqsave(&global_lport_mgr.global_lport_list_lock,
flags);
}
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock, flags);
/* 3. Register the SCSI host of LPort, including its Vports */
spin_lock_irqsave(&global_lport_mgr.global_lport_list_lock, flags);
list_for_each_entry(lport, &global_lport_mgr.list_lport_list_head,
entry_lport) {
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock,
flags);
if (unf_register_scsi_host(lport) != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_REG_ATT,
UNF_WARN, "[warn]Port(0x%x) register scsi host failed in DIF switch",
lport->port_id);
return UNF_ADMIN_MSG_FAILED;
}
spin_lock_irqsave(&global_lport_mgr.global_lport_list_lock,
flags);
}
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock, flags);
/* 4. Open Lport's SFP */
spin_lock_irqsave(&global_lport_mgr.global_lport_list_lock, flags);
list_for_each_entry(lport, &global_lport_mgr.list_lport_list_head,
entry_lport) {
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock,
flags);
ret = unf_cm_sfp_switch(lport->port_id, UNF_TRUE);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT,
UNF_ERR,
"[err]Port(0x%x) reopen SFP failed in DIF switch",
lport->port_id);
return UNF_ADMIN_MSG_FAILED;
}
spin_lock_irqsave(&global_lport_mgr.global_lport_list_lock,
flags);
}
spin_unlock_irqrestore(&global_lport_mgr.global_lport_list_lock, flags);
return UNF_ADMIN_MSG_DONE;
}
static int unf_cm_switch_app_ref_escape(unsigned int v_option)
{
switch (v_option) {
case UNF_APP_REF_ESC_BOTH_NOT_CHECK:
dif_app_esc_check = HIFC_DIF_APP_REF_ESC_NOT_CHECK;
dif_ref_esc_check = HIFC_DIF_APP_REF_ESC_NOT_CHECK;
break;
case UNF_APP_ESC_CHECK:
dif_app_esc_check = HIFC_DIF_APP_REF_ESC_CHECK;
dif_ref_esc_check = HIFC_DIF_APP_REF_ESC_NOT_CHECK;
break;
case UNF_REF_ESC_CHECK:
dif_app_esc_check = HIFC_DIF_APP_REF_ESC_NOT_CHECK;
dif_ref_esc_check = HIFC_DIF_APP_REF_ESC_CHECK;
break;
case UNF_APP_REF_ESC_BOTH_CHECK:
dif_app_esc_check = HIFC_DIF_APP_REF_ESC_CHECK;
dif_ref_esc_check = HIFC_DIF_APP_REF_ESC_CHECK;
break;
default:
dif_app_esc_check = HIFC_DIF_APP_REF_ESC_CHECK;
dif_ref_esc_check = HIFC_DIF_APP_REF_ESC_CHECK;
break;
}
return UNF_ADMIN_MSG_DONE;
}
static int unf_cm_select_dif_mode(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_input)
{
unsigned int dif_mode = 0;
unsigned int option = 0;
unsigned int dix_ip_checksum = 0;
struct unf_adm_cmd *buff_in = NULL;
struct unf_adm_cmd *buff_out = NULL;
struct unf_admin_msg_head msg_head = { 0 };
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input->buff_out,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input->buff_in,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
v_input->in_size >= sizeof(struct unf_adm_cmd),
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
*v_input->out_size >= sizeof(struct unf_adm_cmd),
return UNF_RETURN_ERROR);
buff_in = (struct unf_adm_cmd *)v_input->buff_in;
buff_out = (struct unf_adm_cmd *)v_input->buff_out;
msg_head.status = UNF_ADMIN_MSG_DONE;
dif_mode = buff_in->arg[0];
option = buff_in->arg[1];
dix_ip_checksum = buff_in->arg[2];
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"[info]DIF mode(0x%x) sub option(0x%x 0x%x)",
dif_mode, option, dix_ip_checksum);
switch (dif_mode) {
case UNF_SWITCH_DIF_DIX:
msg_head.status =
(unsigned short)unf_cm_switch_dif(option,
dix_ip_checksum);
break;
case UNF_APP_REF_ESCAPE:
msg_head.status =
(unsigned short)unf_cm_switch_app_ref_escape(option);
break;
default:
msg_head.status = UNF_ADMIN_MSG_FAILED;
goto end;
}
end:
msg_head.size = sizeof(struct unf_admin_msg_head);
*v_input->out_size = sizeof(struct unf_adm_cmd);
memcpy(buff_out, &msg_head, sizeof(struct unf_admin_msg_head));
return RETURN_OK;
}
static int unf_cm_set_dif(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_input)
{
unsigned int dif_switch = 0;
struct unf_adm_cmd *buff_in = NULL;
struct unf_adm_cmd *buff_out = NULL;
struct unf_admin_msg_head msg_head = { 0 };
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input->buff_out,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input->buff_in,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
v_input->in_size >= sizeof(struct unf_adm_cmd),
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
*v_input->out_size >= sizeof(struct unf_adm_cmd),
return UNF_RETURN_ERROR);
buff_in = (struct unf_adm_cmd *)v_input->buff_in;
buff_out = (struct unf_adm_cmd *)v_input->buff_out;
msg_head.status = UNF_ADMIN_MSG_DONE;
dif_switch = (buff_in->arg[0]) ?
UNF_ENABLE_DIF_DIX_PROT : UNF_DIF_ACTION_NONE;
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"[info]DIF switch is 0x%x", dif_switch);
if (dif_switch == UNF_ENABLE_DIF_DIX_PROT)
msg_head.status = (unsigned short)unf_cm_switch_dif(dif_switch,
UNF_ENABLE_IP_CHECKSUM);
else
msg_head.status = (unsigned short)unf_cm_switch_dif(dif_switch,
UNF_DISABLE_IP_CHECKSUM);
msg_head.size = sizeof(struct unf_admin_msg_head);
*v_input->out_size = sizeof(struct unf_adm_cmd);
memcpy(buff_out, &msg_head, sizeof(struct unf_admin_msg_head));
return RETURN_OK;
}
static unsigned int unf_save_port_info(struct unf_lport_s *lport,
void *save_info_addr)
{
unsigned int ret = UNF_RETURN_ERROR;
UNF_CHECK_VALID(0x2271, UNF_TRUE, save_info_addr,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(0x2271, UNF_TRUE, lport, return UNF_RETURN_ERROR);
if (!lport->low_level_func.port_mgr_op.pfn_ll_port_config_set) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Port(0x%x)'s corresponding function is NULL.",
lport->port_id);
return ret;
}
ret = lport->low_level_func.port_mgr_op.pfn_ll_port_config_set(
lport->fc_port,
UNF_PORT_CFG_SAVE_HBA_INFO, (void *)save_info_addr);
return ret;
}
static unsigned int unf_save_port_base_info(struct unf_lport_s *lport,
void *v_save_info)
{
struct unf_save_info_head_s *save_info_head = v_save_info;
struct unf_port_info_entry_s *sava_port_entry = NULL;
struct unf_low_level_port_mgr_op_s *port_mgr = NULL;
unsigned int cfg_speed = 0;
unsigned int topo_cfg = 0;
int fec = UNF_FALSE;
int ret = UNF_RETURN_ERROR;
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, lport,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, save_info_head,
return UNF_RETURN_ERROR);
save_info_head->opcode = 0;
/* write information to up */
save_info_head->type = UNF_PORT_BASE_INFO; /* port base info */
save_info_head->entry_num = 1;
save_info_head->next = 0xffff;
sava_port_entry = (struct unf_port_info_entry_s *)
((void *)(save_info_head + 1));
port_mgr = &lport->low_level_func.port_mgr_op;
if (!port_mgr->pfn_ll_port_config_get) {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"Port(0x%x)'s corresponding function is NULL.",
lport->nport_id);
return UNF_RETURN_ERROR;
}
/* get Bbscn */
sava_port_entry->bb_scn = unf_low_level_bbscn(lport);
/* get speed */
port_mgr->pfn_ll_port_config_get(lport->fc_port,
UNF_PORT_CFG_GET_SPEED_CFG,
(void *)&cfg_speed);
sava_port_entry->speed = cfg_speed;
/* get topo */
port_mgr->pfn_ll_port_config_get(lport->fc_port,
UNF_PORT_CFG_GET_TOPO_CFG,
(void *)&topo_cfg);
sava_port_entry->topo = topo_cfg;
/* get fec */
port_mgr->pfn_ll_port_config_get(lport->fc_port,
UNF_PORT_CFG_GET_FEC,
(void *)&fec);
sava_port_entry->fec = fec;
ret = (int)unf_save_port_info(lport, v_save_info);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_EQUIP_ATT, UNF_WARN,
"[warn]Port(0x%x) send mailbox fail",
lport->port_id);
return UNF_RETURN_ERROR;
}
return RETURN_OK;
}
unsigned int unf_cm_save_port_info(unsigned int v_port_id)
{
unsigned int port_id = v_port_id;
struct unf_lport_s *lport = NULL;
struct unf_save_info_head_s *save_info = NULL;
unsigned int ret = UNF_RETURN_ERROR;
lport = unf_find_lport_by_port_id(port_id);
if (!lport) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
"[err]Port(0x%x) can not be found", port_id);
return ret;
}
save_info = vmalloc(SAVE_PORT_INFO_LEN);
if (!save_info) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_NORMAL, UNF_ERR,
"[err]Can't alloc buffer for saving port info");
return ret;
}
/* 1 clean flush */
memset(save_info, 0, SAVE_PORT_INFO_LEN);
save_info->opcode = 2; /* notify up to clean flush */
save_info->type = 0xf;
save_info->entry_num = 0;
save_info->next = 0xffff;
ret = unf_save_port_info(lport, save_info);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"[warn]Port(0x%x) send mailbox fail", lport->port_id);
vfree(save_info);
return ret;
}
/* 2 save port base information */
memset(save_info, 0, SAVE_PORT_INFO_LEN);
ret = unf_save_port_base_info(lport, save_info);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
"[err]Port(0x%x) save port base information failed",
lport->port_id);
vfree(save_info);
return ret;
}
vfree(save_info);
return ret;
}
static void unf_handle_port_base_info(struct unf_lport_s *lport,
struct unf_port_info_entry_s *v_save_info)
{
struct unf_port_info_entry_s *sava_port_entry = NULL;
unsigned int ret = UNF_RETURN_ERROR;
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, lport, return);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_save_info, return);
sava_port_entry = v_save_info;
UNF_CHECK_VALID(INVALID_VALUE32,
UNF_TRUE,
(sava_port_entry->topo == UNF_TOP_LOOP_MASK) ||
(sava_port_entry->topo == UNF_TOP_P2P_MASK) ||
(sava_port_entry->topo == UNF_TOP_AUTO_MASK),
return);
if (!lport->low_level_func.port_mgr_op.pfn_ll_port_config_set) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
"Port(0x%x)'s corresponding function is NULL.",
lport->port_id);
return;
}
ret = lport->low_level_func.port_mgr_op.pfn_ll_port_config_set(
lport->fc_port,
UNF_PORT_CFG_SET_HBA_BASE_INFO, (void *)sava_port_entry);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
"Cannot set port base info");
return;
}
/* update bbsn cfg to Lport */
lport->low_level_func.lport_cfg_items.bb_scn = sava_port_entry->bb_scn;
lport->low_level_func.lport_cfg_items.port_topology =
sava_port_entry->topo;
}
static unsigned int unf_recovery_save_info(struct unf_lport_s *lport,
void *v_save_info,
unsigned char v_type)
{
struct unf_save_info_head_s *save_info_head = v_save_info;
void *info_entry = NULL;
int ret = 0;
unsigned short next_flag = 0;
unsigned char entry_num = 0;
unsigned char index = 0;
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, lport,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, save_info_head,
return UNF_RETURN_ERROR);
do {
memset(save_info_head, 0, SAVE_PORT_INFO_LEN);
save_info_head->opcode = 1;
/* read information from up */
save_info_head->type = v_type;
/* vport[qos] info */
save_info_head->entry_num = 0xff;
save_info_head->next = next_flag;
ret = (int)unf_save_port_info(lport, save_info_head);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_EQUIP_ATT,
UNF_WARN,
"[warn]Port(0x%x) send mailbox fail",
lport->port_id);
return UNF_RETURN_ERROR;
}
next_flag = (unsigned short)save_info_head->next;
entry_num = (unsigned char)save_info_head->entry_num;
info_entry = save_info_head + 1;
for (index = 0; index < entry_num; index++) {
switch (v_type) {
case UNF_PORT_BASE_INFO:
unf_handle_port_base_info(lport, info_entry);
info_entry = ((struct unf_port_info_entry_s *)
info_entry) + 1;
break;
default:
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR,
UNF_LOG_EQUIP_ATT,
UNF_ERR,
"[err]Port(0x%x) handle message failed",
lport->port_id);
return UNF_RETURN_ERROR;
}
}
} while (next_flag != 0xffff);
return RETURN_OK;
}
unsigned int unf_cm_get_save_info(struct unf_lport_s *v_lport)
{
struct unf_lport_s *lport = NULL;
void *save_info = NULL;
unsigned int ret = UNF_RETURN_ERROR;
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_lport,
return UNF_RETURN_ERROR);
lport = v_lport;
save_info = vmalloc(SAVE_PORT_INFO_LEN);
if (!save_info) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_NORMAL, UNF_ERR,
"[err]Can't alloc buffer for saving port info");
return ret;
}
/* 1 get port base information */
ret = unf_recovery_save_info(lport, save_info, UNF_PORT_BASE_INFO);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"[warn]Port(0x%x) send mailbox fail", lport->port_id);
vfree(save_info);
return ret;
}
vfree(save_info);
return ret;
}
int unf_get_link_lose_tmo(struct unf_lport_s *v_lport)
{
unsigned int tmo_value = 0;
if (!v_lport)
return UNF_LOSE_TMO;
tmo_value = atomic_read(&v_lport->link_lose_tmo);
if (!tmo_value)
tmo_value = UNF_LOSE_TMO;
return (int)tmo_value;
}
int unf_get_link_lose_tmo_from_up(struct unf_lport_s *v_lport,
struct unf_flash_link_tmo_s *v_link_tmo)
{
int ret = UNF_RETURN_ERROR;
struct unf_flash_data_s flash_data;
if (!v_lport || !v_link_tmo || (sizeof(struct unf_flash_data_s)
> HIFC_FLASH_DATA_MAX_LEN)) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_NORMAL, UNF_KEVENT,
"[warn]get flas link tmo param check fail");
return ret;
}
memset(&flash_data, 0, sizeof(struct unf_flash_data_s));
if (!v_lport->low_level_func.port_mgr_op.pfn_ll_port_config_get) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_NORMAL, UNF_KEVENT,
"[warn]link tmo fun null");
return ret;
}
if (v_lport->low_level_func.port_mgr_op.pfn_ll_port_config_get(
v_lport->fc_port,
UNF_PORT_CFG_GET_FLASH_DATA_INFO, &flash_data) !=
RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_NORMAL, UNF_KEVENT,
"[warn]get link tmo from up fail");
return ret;
}
ret = RETURN_OK;
memcpy(v_link_tmo, &flash_data.link_tmo, HIFC_FLASH_LINK_TMO_MAX_LEN);
return ret;
}
void unf_init_link_lose_tmo(struct unf_lport_s *v_lport)
{
struct unf_flash_link_tmo_s flash_link_tmo;
unsigned int tmo;
memset(&flash_link_tmo, 0, sizeof(struct unf_flash_link_tmo_s));
if (!v_lport) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"[warn]int link tmo param check fail");
return;
}
if ((unf_get_link_lose_tmo_from_up(v_lport, &flash_link_tmo) ==
RETURN_OK) &&
(flash_link_tmo.writeflag == HIFC_MGMT_TMO_MAGIC_NUM)) {
tmo = (((unsigned int)flash_link_tmo.link_tmo3 << 24) |
((unsigned int)flash_link_tmo.link_tmo2 << 16) |
((unsigned int)flash_link_tmo.link_tmo1 << 8) |
flash_link_tmo.link_tmo0);
if (tmo > 600)
unf_set_link_lose_tmo(v_lport, UNF_LOSE_TMO);
else
atomic_set(&v_lport->link_lose_tmo, (int)tmo);
} else {
unf_set_link_lose_tmo(v_lport, UNF_LOSE_TMO);
}
}
unsigned int unf_register_scsi_host(struct unf_lport_s *v_lport)
{
struct unf_host_param_s host_param = { 0 };
unf_scsi_host_s **p_scsi_host = NULL;
struct unf_lport_cfg_item_s *lport_cfg_items = NULL;
UNF_CHECK_VALID(0x1359, TRUE, v_lport, return UNF_RETURN_ERROR);
/* Point to -->> L_port->Scsi_host */
p_scsi_host = &v_lport->host_info.p_scsi_host;
lport_cfg_items = &v_lport->low_level_func.lport_cfg_items;
host_param.can_queue = (int)lport_cfg_items->max_queue_depth;
/* Performance optimization */
host_param.cmnd_per_lun = UNF_MAX_CMND_PER_LUN;
host_param.sg_table_size = UNF_MAX_DMA_SEGS;
host_param.max_id = UNF_MAX_TARGET_NUMBER;
host_param.max_lun = UNF_DEFAULT_MAX_LUN;
host_param.max_channel = UNF_MAX_BUS_CHANNEL;
host_param.max_cmnd_len = UNF_MAX_SCSI_CMND_LEN; /* CDB-16 */
host_param.dma_boundary = UNF_DMA_BOUNDARY;
host_param.max_sectors = UNF_MAX_SECTORS;
host_param.port_id = v_lport->port_id;
host_param.lport = v_lport;
host_param.pdev = &v_lport->low_level_func.dev->dev;
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_INFO,
"[info]Port(0x%x) allocate scsi host: can queue(%u), command performance LUN(%u), max lun(%u)",
v_lport->port_id, host_param.can_queue,
host_param.cmnd_per_lun, host_param.max_lun);
if (unf_alloc_scsi_host(p_scsi_host, &host_param) != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR,
"[err]Port(0x%x) allocate scsi host failed",
v_lport->port_id);
return UNF_RETURN_ERROR;
}
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_KEVENT,
"[event]Port(0x%x) allocate scsi host(0x%x) succeed",
v_lport->port_id, UNF_GET_SCSI_HOST_ID(*p_scsi_host));
return RETURN_OK;
}
void unf_unregister_scsi_host(struct unf_lport_s *v_lport)
{
unf_scsi_host_s *p_scsi_host = NULL;
unsigned int host_no = 0;
UNF_REFERNCE_VAR(p_scsi_host);
UNF_CHECK_VALID(0x1360, TRUE, v_lport, return);
p_scsi_host = v_lport->host_info.p_scsi_host;
if (p_scsi_host) {
host_no = UNF_GET_SCSI_HOST_ID(p_scsi_host);
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"[event]Port(0x%x) starting unregister scsi host(0x%x)",
v_lport->port_id, host_no);
unf_free_scsi_host(p_scsi_host);
/* can`t set p_scsi_host for NULL,
* since it does`t alloc by itself
*/
} else {
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_KEVENT,
"[warn]Port(0x%x) unregister scsi host, invalid ScsiHost ",
v_lport->port_id);
}
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
"[event]Port(0x%x) unregister scsi host(0x%x) succeed",
v_lport->port_id, host_no);
v_lport->destroy_step = UNF_LPORT_DESTROY_STEP_12_UNREG_SCSI_HOST;
UNF_REFERNCE_VAR(p_scsi_host);
UNF_REFERNCE_VAR(host_no);
}
unsigned int unf_cm_clear_flush(unsigned int v_port_id)
{
unsigned int port_id = v_port_id;
struct unf_lport_s *lport = NULL;
struct unf_save_info_head_s *save_info = NULL;
unsigned int ret = UNF_RETURN_ERROR;
lport = unf_find_lport_by_port_id(port_id);
if (!lport) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_EQUIP_ATT, UNF_ERR,
"[err]Port(0x%x) can not be found", port_id);
return ret;
}
save_info = vmalloc(SAVE_PORT_INFO_LEN);
if (!save_info) {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_NORMAL, UNF_ERR,
"[err]Can't alloc buffer for saving port info");
return ret;
}
/* 1 clean flush */
memset(save_info, 0, SAVE_PORT_INFO_LEN);
save_info->opcode = 2; /* notify up to clean flush */
save_info->type = 0xf;
save_info->entry_num = 0;
save_info->next = 0xffff;
ret = unf_save_port_info(lport, save_info);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_EQUIP_ATT, UNF_MAJOR,
"[warn]Port(0x%x) send mailbox fail", lport->port_id);
vfree(save_info);
return ret;
}
vfree(save_info);
return ret;
}
static int unf_cm_save_data_mode(struct unf_lport_s *v_lport,
struct unf_hinicam_pkg *v_input)
{
int ret = UNF_RETURN_ERROR;
unsigned int save_data_mode = 0;
unsigned int port_id = 0;
void *out_buf = NULL;
struct unf_adm_cmd *buff_in = NULL;
struct unf_admin_msg_head msg_head = { 0 };
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input,
return UNF_RETURN_ERROR);
out_buf = v_input->buff_out;
buff_in = v_input->buff_in;
port_id = v_lport->port_id;
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, out_buf,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, buff_in,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
v_input->in_size >= sizeof(struct unf_adm_cmd),
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE,
*v_input->out_size >= sizeof(struct unf_adm_cmd),
return UNF_RETURN_ERROR);
save_data_mode = buff_in->arg[0];
msg_head.status = UNF_ADMIN_MSG_DONE;
if (save_data_mode == UNF_SAVA_INFO_MODE) {
ret = (int)unf_cm_save_port_info(port_id);
if (ret != RETURN_OK)
msg_head.status = UNF_ADMIN_MSG_FAILED;
} else if (save_data_mode == UNF_CLEAN_INFO_MODE) {
ret = (int)unf_cm_clear_flush(port_id);
if (ret != RETURN_OK)
msg_head.status = UNF_ADMIN_MSG_FAILED;
} else {
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_MAJOR,
"[err]This mode(0x%x) is unknown", save_data_mode);
msg_head.status = UNF_ADMIN_MSG_FAILED;
}
msg_head.size = sizeof(struct unf_admin_msg_head);
*v_input->out_size = sizeof(struct unf_adm_cmd);
memcpy(out_buf, &msg_head, sizeof(struct unf_admin_msg_head));
return ret;
}
int unf_cmd_adm_handler(void *v_lport, struct unf_hinicam_pkg *v_input)
{
struct unf_lport_s *lport = NULL;
int ret = UNF_RETURN_ERROR;
enum unf_msg_format_e msg_formate;
unsigned int index = 0;
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_lport,
return UNF_RETURN_ERROR);
UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, v_input,
return UNF_RETURN_ERROR);
lport = (struct unf_lport_s *)v_lport;
msg_formate = v_input->msg_format;
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_INFO,
"[info]Enter HIFC_Adm, msg_formate=0x%x, 0x%x",
msg_formate, *v_input->out_size);
/* hifcadm event */
while (index < (sizeof(unf_hifcadm_action) /
sizeof(struct unf_hifcadm_action_s))) {
if ((msg_formate == unf_hifcadm_action[index].hifc_action) &&
unf_hifcadm_action[index].fn_unf_hifc_action) {
ret = unf_hifcadm_action[index].fn_unf_hifc_action(lport, v_input);
if (ret != RETURN_OK) {
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_EVENT,
UNF_WARN,
"[warn]Port(0x%x) process up msg(0x%x) failed",
lport->port_id, msg_formate);
}
return ret;
}
index++;
}
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_EVENT, UNF_KEVENT,
"[event]Port(0x%x) not support adm cmd, msg type(0x%x) ",
lport->port_id, msg_formate);
return ret;
}