565 lines
15 KiB
C
565 lines
15 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Huawei Fabric Channel Linux driver
|
|
* Copyright(c) 2018 Huawei Technologies Co., Ltd
|
|
*
|
|
*/
|
|
|
|
#include "unf_log.h"
|
|
#include "unf_event.h"
|
|
#include "unf_exchg.h"
|
|
#include "unf_portman.h"
|
|
#include "unf_rport.h"
|
|
#include "unf_service.h"
|
|
#include "unf_io.h"
|
|
|
|
#define RPORT_FEATURE_POOL_SIZE 4096
|
|
|
|
static struct unf_esgl_page_s *unf_cm_get_one_free_esgl_page(
|
|
void *v_lport,
|
|
struct unf_frame_pkg_s *v_fra_pkg);
|
|
static unsigned int unf_recv_tmf_marker_status(
|
|
void *v_lport,
|
|
struct unf_frame_pkg_s *v_fra_pkg);
|
|
static unsigned int unf_recv_abts_mrker_status(
|
|
void *v_lport,
|
|
struct unf_frame_pkg_s *v_fra_pkg);
|
|
static int unf_get_cfg_parms(char *v_section_name,
|
|
struct unf_cfg_item_s *v_cfg_parm,
|
|
unsigned int *v_cfg_value,
|
|
unsigned int v_item_num);
|
|
|
|
|
|
/* global variables */
|
|
unsigned int event_thread_exit;
|
|
struct task_struct *event_thread;
|
|
|
|
struct completion *fc_event_handle_thd_comp;
|
|
struct workqueue_struct *unf_work_queue;
|
|
|
|
struct unf_global_card_thread_s card_thread_mgr;
|
|
unsigned int unf_dbg_level = UNF_MAJOR;
|
|
unsigned int log_print_level = UNF_INFO;
|
|
unsigned int log_limted_times = UNF_LOGIN_ATT_PRINT_TIMES;
|
|
|
|
struct unf_cm_handle_op_s cm_low_levle_handle = {
|
|
.pfn_unf_alloc_local_port = unf_lport_create_and_init,
|
|
.pfn_unf_release_local_port = unf_release_local_port,
|
|
.pfn_unf_receive_els_pkg = unf_receive_els_pkg,
|
|
.pfn_unf_receive_gs_pkg = unf_receive_gs_pkg,
|
|
.pfn_unf_receive_bls_pkg = unf_receive_bls_pkg,
|
|
.pfn_unf_send_els_done = unf_send_els_done,
|
|
.pfn_unf_receive_ini_rsponse = unf_ini_scsi_completed,
|
|
.pfn_unf_get_cfg_parms = unf_get_cfg_parms,
|
|
.pfn_unf_receive_marker_status = unf_recv_tmf_marker_status,
|
|
.pfn_unf_receive_abts_marker_status = unf_recv_abts_mrker_status,
|
|
|
|
.pfn_unf_cm_get_sgl_entry = unf_ini_get_sgl_entry,
|
|
.pfn_unf_cm_get_dif_sgl_entry = unf_ini_get_dif_sgl_entry,
|
|
.pfn_unf_get_one_free_esgl_page = unf_cm_get_one_free_esgl_page,
|
|
.pfn_unf_fc_port_link_event = unf_fc_port_link_event,
|
|
.pfn_unf_ioctl_to_com_handler = unf_cmd_adm_handler,
|
|
};
|
|
|
|
static struct unf_esgl_page_s *unf_cm_get_one_free_esgl_page(
|
|
void *v_lport,
|
|
struct unf_frame_pkg_s *v_fra_pkg)
|
|
{
|
|
struct unf_lport_s *lport = NULL;
|
|
struct unf_xchg_s *xchg = NULL;
|
|
|
|
UNF_CHECK_VALID(0x1700, 1, v_lport, return NULL);
|
|
UNF_CHECK_VALID(0x1701, 1, v_fra_pkg, return NULL);
|
|
|
|
lport = (struct unf_lport_s *)v_lport;
|
|
xchg = (struct unf_xchg_s *)v_fra_pkg->xchg_contex;
|
|
|
|
return unf_get_one_free_esgl_page(lport, xchg); /* from esgl pool */
|
|
}
|
|
|
|
static int unf_get_cfg_parms(char *v_section_name,
|
|
struct unf_cfg_item_s *v_cfg_parm,
|
|
unsigned int *v_cfg_value,
|
|
unsigned int v_item_num)
|
|
{
|
|
/* Maximum length of a configuration item value,
|
|
* including the end character
|
|
*/
|
|
#define UNF_MAX_ITEM_VALUE_LEN (256)
|
|
|
|
unsigned int *value = NULL;
|
|
struct unf_cfg_item_s *cfg_parm = NULL;
|
|
unsigned int i = 0;
|
|
|
|
cfg_parm = v_cfg_parm;
|
|
value = v_cfg_value;
|
|
|
|
for (i = 0; i < v_item_num; i++) {
|
|
if (!cfg_parm || !value) {
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR,
|
|
UNF_LOG_REG_ATT, UNF_ERR,
|
|
"[err]Config name or value is NULL");
|
|
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
|
|
if (strcmp("End", cfg_parm->name) == 0)
|
|
break;
|
|
|
|
if (strcmp("fw_path", cfg_parm->name) == 0) {
|
|
cfg_parm++;
|
|
value += UNF_MAX_ITEM_VALUE_LEN / sizeof(unsigned int);
|
|
|
|
continue;
|
|
}
|
|
|
|
*value = cfg_parm->default_value;
|
|
cfg_parm++;
|
|
value++;
|
|
}
|
|
|
|
return RETURN_OK;
|
|
}
|
|
|
|
static unsigned int unf_recv_tmf_marker_status(
|
|
void *v_lport,
|
|
struct unf_frame_pkg_s *v_fra_pkg)
|
|
{
|
|
struct unf_lport_s *lport = NULL;
|
|
struct unf_xchg_s *xchg = NULL;
|
|
unsigned short hot_pool_tag = 0;
|
|
|
|
UNF_CHECK_VALID(0x3543, UNF_TRUE, v_lport, return UNF_RETURN_ERROR);
|
|
UNF_CHECK_VALID(0x3544, UNF_TRUE, v_fra_pkg, return UNF_RETURN_ERROR);
|
|
lport = (struct unf_lport_s *)v_lport;
|
|
|
|
/* Find exchange which point to marker sts */
|
|
if (!lport->xchg_mgr_temp.pfn_unf_look_up_xchg_by_tag) {
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_LOGIN_ATT, UNF_ERR,
|
|
"[err]Port(0x%x) tag function is NULL",
|
|
lport->port_id);
|
|
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
|
|
hot_pool_tag = (unsigned short)
|
|
(v_fra_pkg->private[PKG_PRIVATE_XCHG_HOT_POOL_INDEX]);
|
|
|
|
xchg = (struct unf_xchg_s *)
|
|
(lport->xchg_mgr_temp.pfn_unf_look_up_xchg_by_tag((void *)lport,
|
|
hot_pool_tag));
|
|
if (!xchg) {
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_LOGIN_ATT, UNF_WARN,
|
|
"[warn]Port(0x%x_0x%x) find exchange by tag(0x%x) failed",
|
|
lport->port_id, lport->nport_id, hot_pool_tag);
|
|
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
|
|
/*
|
|
* NOTE: set exchange TMF state with MARKER_STS_RECEIVED
|
|
*
|
|
* About TMF state
|
|
* 1. STS received
|
|
* 2. Response received
|
|
* 3. Do check if necessary
|
|
*/
|
|
xchg->tmf_state |= MARKER_STS_RECEIVED;
|
|
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_IO_ATT, UNF_MAJOR,
|
|
"[info]Marker STS: D_ID(0x%x) S_ID(0x%x) OX_ID(0x%x) RX_ID(0x%x), EXCH: D_ID(0x%x) S_ID(0x%x) OX_ID(0x%x) RX_ID(0x%x)",
|
|
v_fra_pkg->frame_head.rctl_did & UNF_NPORTID_MASK,
|
|
v_fra_pkg->frame_head.csctl_sid & UNF_NPORTID_MASK,
|
|
(unsigned short)(v_fra_pkg->frame_head.oxid_rxid >> 16),
|
|
(unsigned short)(v_fra_pkg->frame_head.oxid_rxid),
|
|
xchg->did,
|
|
xchg->sid,
|
|
xchg->ox_id,
|
|
xchg->rx_id);
|
|
|
|
return RETURN_OK;
|
|
}
|
|
|
|
static unsigned int unf_recv_abts_mrker_status(
|
|
void *v_lport,
|
|
struct unf_frame_pkg_s *v_fra_pkg)
|
|
{
|
|
struct unf_lport_s *lport = NULL;
|
|
struct unf_xchg_s *xchg = NULL;
|
|
unsigned short hot_pool_tag = 0;
|
|
unsigned long flags = 0;
|
|
|
|
UNF_CHECK_VALID(0x3543, UNF_TRUE, v_lport, return UNF_RETURN_ERROR);
|
|
UNF_CHECK_VALID(0x3544, UNF_TRUE, v_fra_pkg, return UNF_RETURN_ERROR);
|
|
lport = (struct unf_lport_s *)v_lport;
|
|
|
|
/* Find exchange by tag */
|
|
if (!lport->xchg_mgr_temp.pfn_unf_look_up_xchg_by_tag) {
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_LOGIN_ATT, UNF_ERR,
|
|
"[err]Port(0x%x) tag function is NULL",
|
|
lport->port_id);
|
|
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
|
|
hot_pool_tag = (unsigned short)
|
|
(v_fra_pkg->private[PKG_PRIVATE_XCHG_HOT_POOL_INDEX]);
|
|
|
|
xchg = (struct unf_xchg_s *)
|
|
(lport->xchg_mgr_temp.pfn_unf_look_up_xchg_by_tag((void *)lport,
|
|
hot_pool_tag));
|
|
if (!xchg) {
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_LOGIN_ATT, UNF_WARN,
|
|
"[warn]Port(0x%x_0x%x) find exchange by tag(0x%x) failed",
|
|
lport->port_id, lport->nport_id, hot_pool_tag);
|
|
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
|
|
/*
|
|
* NOTE: set exchange ABTS state with MARKER_STS_RECEIVED
|
|
*
|
|
* About exchange ABTS state
|
|
* 1. STS received
|
|
* 2. Response received
|
|
* 3. Do check if necessary
|
|
*
|
|
* About Exchange status get from low level
|
|
* 1. Set: when RCVD ABTS Marker
|
|
* 2. Set: when RCVD ABTS Req Done
|
|
* 3. value: set value with pkg->status
|
|
*/
|
|
spin_lock_irqsave(&xchg->xchg_state_lock, flags);
|
|
xchg->ucode_abts_state = v_fra_pkg->status;
|
|
xchg->abts_state |= MARKER_STS_RECEIVED;
|
|
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_LOGIN_ATT, UNF_KEVENT,
|
|
"[info]Port(0x%x) wake up SEMA for Abts marker exchange(0x%p) oxid(0x%x 0x%x) status(0x%x)",
|
|
lport->port_id, xchg, xchg->ox_id, xchg->hot_pool_tag,
|
|
v_fra_pkg->abts_maker_status);
|
|
|
|
/*
|
|
* NOTE: Second time for ABTS marker received, or
|
|
* ABTS response have been received, no need to wake up sema
|
|
*/
|
|
if ((xchg->io_state & INI_IO_STATE_ABORT_TIMEOUT) ||
|
|
(xchg->abts_state & ABTS_RESPONSE_RECEIVED)) {
|
|
spin_unlock_irqrestore(&xchg->xchg_state_lock, flags);
|
|
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_LOGIN_ATT,
|
|
UNF_KEVENT,
|
|
"[info]Port(0x%x) no need to wake up SEMA for Abts marker ABTS_STATE(0x%x) IO_STATE(0x%x)",
|
|
lport->port_id, xchg->abts_state,
|
|
xchg->io_state);
|
|
|
|
return RETURN_OK;
|
|
}
|
|
if (xchg->io_state & INI_IO_STATE_TMF_ABORT) {
|
|
spin_unlock_irqrestore(&xchg->xchg_state_lock, flags);
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_LOGIN_ATT,
|
|
UNF_KEVENT,
|
|
"[info]Port(0x%x) receive Abts marker, exchange(%p) state(0x%x) free it",
|
|
lport->port_id, xchg, xchg->io_state);
|
|
|
|
unf_cm_free_xchg(lport, xchg);
|
|
} else {
|
|
spin_unlock_irqrestore(&xchg->xchg_state_lock, flags);
|
|
up(&xchg->task_sema);
|
|
}
|
|
|
|
return RETURN_OK;
|
|
}
|
|
|
|
unsigned int unf_get_cm_handle_op(struct unf_cm_handle_op_s *v_cm_handle)
|
|
{
|
|
UNF_CHECK_VALID(0x1708, UNF_TRUE, v_cm_handle,
|
|
return UNF_RETURN_ERROR);
|
|
|
|
memcpy(v_cm_handle, &cm_low_levle_handle,
|
|
sizeof(struct unf_cm_handle_op_s));
|
|
|
|
return RETURN_OK;
|
|
}
|
|
|
|
static void unf_uninit_cm_low_level_handle(void)
|
|
{
|
|
memset(&cm_low_levle_handle, 0, sizeof(struct unf_cm_handle_op_s));
|
|
}
|
|
|
|
int unf_event_process(void *v_arg)
|
|
{
|
|
struct list_head *node = NULL;
|
|
struct unf_cm_event_report *event_node = NULL;
|
|
unsigned long flags = 0;
|
|
|
|
UNF_REFERNCE_VAR(v_arg);
|
|
|
|
set_user_nice(current, 4);
|
|
recalc_sigpending();
|
|
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_INFO,
|
|
"[event]Enter event thread");
|
|
|
|
complete(fc_event_handle_thd_comp);
|
|
|
|
do {
|
|
spin_lock_irqsave(&fc_event_list.fc_eventlist_lock, flags);
|
|
if (list_empty(&fc_event_list.list_head) == UNF_TRUE) {
|
|
spin_unlock_irqrestore(&fc_event_list.fc_eventlist_lock,
|
|
flags);
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
|
schedule_timeout((long)msecs_to_jiffies(1000));
|
|
} else {
|
|
node = (&fc_event_list.list_head)->next;
|
|
list_del_init(node);
|
|
fc_event_list.list_num--;
|
|
event_node = list_entry(node,
|
|
struct unf_cm_event_report,
|
|
list_entry);
|
|
spin_unlock_irqrestore(&fc_event_list.fc_eventlist_lock,
|
|
flags);
|
|
|
|
/* Process event node */
|
|
unf_handle_event(event_node);
|
|
}
|
|
} while (!event_thread_exit);
|
|
|
|
complete_and_exit(fc_event_handle_thd_comp, 0);
|
|
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EVENT, UNF_MAJOR,
|
|
"[event]Event thread exit");
|
|
|
|
return RETURN_OK;
|
|
}
|
|
|
|
static unsigned int unf_creat_event_center(void)
|
|
{
|
|
struct completion fc_event_completion =
|
|
COMPLETION_INITIALIZER(fc_event_completion);
|
|
|
|
struct completion *p_fc_event_completion = &fc_event_completion;
|
|
|
|
INIT_LIST_HEAD(&fc_event_list.list_head);
|
|
fc_event_list.list_num = 0;
|
|
spin_lock_init(&fc_event_list.fc_eventlist_lock);
|
|
fc_event_handle_thd_comp = p_fc_event_completion;
|
|
|
|
event_thread = kthread_run(unf_event_process, NULL, "hifc_event");
|
|
if (IS_ERR(event_thread)) {
|
|
complete_and_exit(fc_event_handle_thd_comp, 0);
|
|
fc_event_handle_thd_comp = NULL;
|
|
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"[err]Create event thread failed(0x%p)",
|
|
event_thread);
|
|
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
wait_for_completion(fc_event_handle_thd_comp);
|
|
return RETURN_OK;
|
|
}
|
|
|
|
static void unf_cm_event_thread_exit(void)
|
|
{
|
|
struct completion fc_event_completion =
|
|
COMPLETION_INITIALIZER(fc_event_completion);
|
|
|
|
struct completion *p_fc_event_completion = &fc_event_completion;
|
|
|
|
fc_event_handle_thd_comp = p_fc_event_completion;
|
|
event_thread_exit = 1;
|
|
wake_up_process(event_thread);
|
|
wait_for_completion(fc_event_handle_thd_comp);
|
|
|
|
fc_event_handle_thd_comp = NULL;
|
|
}
|
|
|
|
static void unf_cm_cread_card_mgr_list(void)
|
|
{
|
|
/* So far, do not care */
|
|
INIT_LIST_HEAD(&card_thread_mgr.list_card_list_head);
|
|
|
|
spin_lock_init(&card_thread_mgr.global_card_list_lock);
|
|
|
|
card_thread_mgr.card_sum = 0;
|
|
}
|
|
|
|
static int unf_port_feature_pool_init(void)
|
|
{
|
|
unsigned int i = 0;
|
|
unsigned int rport_fea_pool_size = 0;
|
|
struct unf_rport_feature_recard_s *rport_fea_recard = NULL;
|
|
unsigned long flags = 0;
|
|
|
|
rport_fea_pool_size = sizeof(struct unf_rport_feature_pool_s);
|
|
port_fea_pool = vmalloc(rport_fea_pool_size);
|
|
if (!port_fea_pool) {
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"[err]cannot allocate rport feature pool");
|
|
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
memset(port_fea_pool, 0, rport_fea_pool_size);
|
|
spin_lock_init(&port_fea_pool->port_fea_pool_lock);
|
|
INIT_LIST_HEAD(&port_fea_pool->list_busy_head);
|
|
INIT_LIST_HEAD(&port_fea_pool->list_free_head);
|
|
|
|
port_fea_pool->p_port_feature_pool_addr =
|
|
vmalloc((size_t)(RPORT_FEATURE_POOL_SIZE *
|
|
sizeof(struct unf_rport_feature_recard_s)));
|
|
if (!port_fea_pool->p_port_feature_pool_addr) {
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"[err]cannot allocate rport feature pool address");
|
|
|
|
vfree(port_fea_pool);
|
|
port_fea_pool = NULL;
|
|
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
|
|
memset(port_fea_pool->p_port_feature_pool_addr, 0,
|
|
sizeof(struct unf_rport_feature_recard_s) *
|
|
RPORT_FEATURE_POOL_SIZE);
|
|
rport_fea_recard =
|
|
(struct unf_rport_feature_recard_s *)
|
|
port_fea_pool->p_port_feature_pool_addr;
|
|
|
|
spin_lock_irqsave(&port_fea_pool->port_fea_pool_lock, flags);
|
|
for (i = 0; i < RPORT_FEATURE_POOL_SIZE; i++) {
|
|
list_add_tail(&rport_fea_recard->entry_feature,
|
|
&port_fea_pool->list_free_head);
|
|
rport_fea_recard++;
|
|
}
|
|
spin_unlock_irqrestore(&port_fea_pool->port_fea_pool_lock, flags);
|
|
|
|
return RETURN_OK;
|
|
}
|
|
|
|
void unf_free_port_feature_pool(void)
|
|
{
|
|
if (port_fea_pool->p_port_feature_pool_addr) {
|
|
vfree(port_fea_pool->p_port_feature_pool_addr);
|
|
port_fea_pool->p_port_feature_pool_addr = NULL;
|
|
}
|
|
vfree(port_fea_pool);
|
|
port_fea_pool = NULL;
|
|
}
|
|
|
|
int unf_common_init(void)
|
|
{
|
|
int ret = RETURN_OK;
|
|
|
|
unf_dbg_level = UNF_MAJOR;
|
|
log_print_level = UNF_KEVENT;
|
|
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_KEVENT,
|
|
"UNF Driver Version:%s.", UNF_FC_VERSION);
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_KEVENT,
|
|
"UNF Compile Time: %s", __TIME_STR__);
|
|
|
|
ret = unf_port_feature_pool_init();
|
|
if (ret != RETURN_OK) {
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"[err]Port Feature Pool init failed");
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* 1. Init Transport */
|
|
ret = (int)unf_register_ini_transport();
|
|
if (ret != RETURN_OK) {
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"[err]INI interface init failed");
|
|
unf_free_port_feature_pool();
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* 2. Init L_Port MG: Y */
|
|
unf_port_mgmt_init();
|
|
|
|
/* 3. Init card MG list: N */
|
|
unf_cm_cread_card_mgr_list();
|
|
|
|
/* 4. Init global event resource: N */
|
|
ret = (int)unf_init_global_event_msg();
|
|
if (ret != RETURN_OK) {
|
|
unf_unregister_ini_transport();
|
|
unf_free_port_feature_pool();
|
|
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"[err]Create global event center failed");
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* 5. Create event center(one thread per pf): Y */
|
|
ret = (int)unf_creat_event_center();
|
|
if (ret != RETURN_OK) {
|
|
unf_destroy_global_event_msg();
|
|
unf_unregister_ini_transport();
|
|
unf_free_port_feature_pool();
|
|
|
|
fc_event_handle_thd_comp = NULL;
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"[err]Create event center (thread) failed");
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* 6. Create work queue: Y */
|
|
unf_work_queue = create_workqueue("unf_wq");
|
|
if (!unf_work_queue) {
|
|
/* event thread exist */
|
|
unf_cm_event_thread_exit();
|
|
unf_destroy_global_event_msg();
|
|
|
|
fc_event_handle_thd_comp = NULL;
|
|
unf_unregister_ini_transport();
|
|
unf_free_port_feature_pool();
|
|
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR,
|
|
"[err]Create work queue failed");
|
|
|
|
return UNF_RETURN_ERROR;
|
|
}
|
|
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
|
|
"[info]Init common layer succeed");
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void unf_destroy_dirty_port(void)
|
|
{
|
|
unsigned int v_ditry_port_num = 0;
|
|
|
|
unf_show_dirty_port(UNF_FALSE, &v_ditry_port_num);
|
|
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR,
|
|
"[info]Sys has %d dirty L_Port(s)", v_ditry_port_num);
|
|
}
|
|
|
|
void unf_common_exit(void)
|
|
{
|
|
unf_free_port_feature_pool();
|
|
|
|
unf_destroy_dirty_port();
|
|
|
|
flush_workqueue(unf_work_queue);
|
|
destroy_workqueue(unf_work_queue);
|
|
unf_work_queue = NULL;
|
|
|
|
unf_cm_event_thread_exit();
|
|
|
|
unf_destroy_global_event_msg();
|
|
|
|
unf_uninit_cm_low_level_handle();
|
|
|
|
unf_port_mgmt_deinit();
|
|
|
|
unf_unregister_ini_transport();
|
|
|
|
UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_KEVENT,
|
|
"[info]HIFC module remove succeed");
|
|
}
|