// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021 Broadcom. All Rights Reserved. The term
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*/
#include "efc.h"
int
efc_remote_node_cb(void *arg, int event, void *data)
{
struct efc *efc = arg;
struct efc_remote_node *rnode = data;
struct efc_node *node = rnode->node;
unsigned long flags = 0;
spin_lock_irqsave(&efc->lock, flags);
efc_node_post_event(node, event, NULL);
spin_unlock_irqrestore(&efc->lock, flags);
return 0;
}
struct efc_node *
efc_node_find(struct efc_nport *nport, u32 port_id)
{
/* Find an FC node structure given the FC port ID */
return xa_load(&nport->lookup, port_id);
}
static void
_efc_node_free(struct kref *arg)
{
struct efc_node *node = container_of(arg, struct efc_node, ref);
struct efc *efc = node->efc;
struct efc_dma *dma;
dma = &node->sparm_dma_buf;
dma_pool_free(efc->node_dma_pool, dma->virt, dma->phys);
memset(dma, 0, sizeof(struct efc_dma));
mempool_free(node, efc->node_pool);
}
struct efc_node *efc_node_alloc(struct efc_nport *nport,
u32 port_id, bool init, bool targ)
{
int rc;
struct efc_node *node = NULL;
struct efc *efc = nport->efc;
struct efc_dma *dma;
if (nport->shutting_down) {
efc_log_debug(efc, "node allocation when shutting down %06x",
port_id);
return NULL;
}
node = mempool_alloc(efc->node_pool, GFP_ATOMIC);
if (!node) {
efc_log_err(efc, "node allocation failed %06x", port_id);
return NULL;
}
memset(node, 0, sizeof(*node));
dma = &node->sparm_dma_buf;
dma->size = NODE_SPARAMS_SIZE;
dma->virt = dma_pool_zalloc(efc->node_dma_pool, GFP_ATOMIC, &dma->phys);
if (!dma->virt) {
efc_log_err(efc, "node dma alloc failed\n");
goto dma_fail;
}
node->rnode.indicator = U32_MAX;
node->nport = nport;
node->efc = efc;
node->init = init;
node->targ = targ;
spin_lock_init(&node->pend_frames_lock);
INIT_LIST_HEAD(&node->pend_frames);
spin_lock_init(&node->els_ios_lock);
INIT_LIST_HEAD(&node->els_ios_list);
node->els_io_enabled = true;
rc = efc_cmd_node_alloc(efc, &node->rnode, port_id, nport);
if (rc) {
efc_log_err(efc, "efc_hw_node_alloc failed: %d\n", rc);
goto hw_alloc_fail;
}
node->rnode.node = node;
node->sm.app = node;
node->evtdepth = 0;
efc_node_update_display_name(node);
rc = xa_err(xa_store(&nport->lookup, port_id, node, GFP_ATOMIC));
if (rc) {
efc_log_err(efc, "Node lookup store failed: %d\n", rc);
goto xa_fail;
}
/* initialize refcount */
kref_init(&node->ref);
node->release = _efc_node_free;
kref_get(&nport->ref);
return node;
xa_fail:
efc_node_free_resources(efc, &node->rnode);
hw_alloc_fail:
dma_pool_free(efc->node_dma_pool, dma->virt, dma->phys);
dma_fail:
mempool_free(node, efc->node_pool);
return NULL;
}
void
efc_node_free(struct efc_node *node)
{
struct efc_nport *nport;
struct efc *efc;
int rc = 0;
struct efc_node *ns = NULL;
nport = node->nport;
efc = node->efc;
node_printf(node, "Free'd\n");
if (node->refound) {
/*
* Save the name server node. We will send fake RSCN event at
* the end to handle ignored RSCN event during node deletion
*/
ns = efc_node_find(node->nport, FC_FID_DIR_SERV);
}
if (!node->nport) {
efc_log_err(efc, "Node already Freed\n");
return;
}
/* Free HW resources */
rc = efc_node_free_resources(efc, &node->rnode);
if (rc