Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
+52
View File
@@ -0,0 +1,52 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2021 Broadcom. All Rights Reserved. The term
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*/
#ifndef __EFC_H__
#define __EFC_H__
#include "../include/efc_common.h"
#include "efclib.h"
#include "efc_sm.h"
#include "efc_cmds.h"
#include "efc_domain.h"
#include "efc_nport.h"
#include "efc_node.h"
#include "efc_fabric.h"
#include "efc_device.h"
#include "efc_els.h"
#define EFC_MAX_REMOTE_NODES 2048
#define NODE_SPARAMS_SIZE 256
enum efc_scsi_del_initiator_reason {
EFC_SCSI_INITIATOR_DELETED,
EFC_SCSI_INITIATOR_MISSING,
};
enum efc_scsi_del_target_reason {
EFC_SCSI_TARGET_DELETED,
EFC_SCSI_TARGET_MISSING,
};
#define EFC_FC_ELS_DEFAULT_RETRIES 3
#define domain_sm_trace(domain) \
efc_log_debug(domain->efc, "[domain:%s] %-20s %-20s\n", \
domain->display_name, __func__, efc_sm_event_name(evt)) \
#define domain_trace(domain, fmt, ...) \
efc_log_debug(domain->efc, \
"[%s]" fmt, domain->display_name, ##__VA_ARGS__) \
#define node_sm_trace() \
efc_log_debug(node->efc, "[%s] %-20s %-20s\n", \
node->display_name, __func__, efc_sm_event_name(evt)) \
#define nport_sm_trace(nport) \
efc_log_debug(nport->efc, \
"[%s] %-20s %-20s\n", nport->display_name, __func__, efc_sm_event_name(evt)) \
#endif /* __EFC_H__ */
@@ -0,0 +1,782 @@
// 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 "efclib.h"
#include "../libefc_sli/sli4.h"
#include "efc_cmds.h"
#include "efc_sm.h"
static void
efc_nport_free_resources(struct efc_nport *nport, int evt, void *data)
{
struct efc *efc = nport->efc;
/* Clear the nport attached flag */
nport->attached = false;
/* Free the service parameters buffer */
if (nport->dma.virt) {
dma_free_coherent(&efc->pci->dev, nport->dma.size,
nport->dma.virt, nport->dma.phys);
memset(&nport->dma, 0, sizeof(struct efc_dma));
}
/* Free the SLI resources */
sli_resource_free(efc->sli, SLI4_RSRC_VPI, nport->indicator);
efc_nport_cb(efc, evt, nport);
}
static int
efc_nport_get_mbox_status(struct efc_nport *nport, u8 *mqe, int status)
{
struct efc *efc = nport->efc;
struct sli4_mbox_command_header *hdr =
(struct sli4_mbox_command_header *)mqe;
if (status || le16_to_cpu(hdr->status)) {
efc_log_debug(efc, "bad status vpi=%#x st=%x hdr=%x\n",
nport->indicator, status, le16_to_cpu(hdr->status));
return -EIO;
}
return 0;
}
static int
efc_nport_free_unreg_vpi_cb(struct efc *efc, int status, u8 *mqe, void *arg)
{
struct efc_nport *nport = arg;
int evt = EFC_EVT_NPORT_FREE_OK;
int rc;
rc = efc_nport_get_mbox_status(nport, mqe, status);
if (rc)
evt = EFC_EVT_NPORT_FREE_FAIL;
efc_nport_free_resources(nport, evt, mqe);
return rc;
}
static void
efc_nport_free_unreg_vpi(struct efc_nport *nport)
{
struct efc *efc = nport->efc;
int rc;
u8 data[SLI4_BMBX_SIZE];
rc = sli_cmd_unreg_vpi(efc->sli, data, nport->indicator,
SLI4_UNREG_TYPE_PORT);
if (rc) {
efc_log_err(efc, "UNREG_VPI format failure\n");
efc_nport_free_resources(nport, EFC_EVT_NPORT_FREE_FAIL, data);
return;
}
rc = efc->tt.issue_mbox_rqst(efc->base, data,
efc_nport_free_unreg_vpi_cb, nport);
if (rc) {
efc_log_err(efc, "UNREG_VPI command failure\n");
efc_nport_free_resources(nport, EFC_EVT_NPORT_FREE_FAIL, data);
}
}
static void
efc_nport_send_evt(struct efc_nport *nport, int evt, void *data)
{
struct efc *efc = nport->efc;
/* Now inform the registered callbacks */
efc_nport_cb(efc, evt, nport);
/* Set the nport attached flag */
if (evt == EFC_EVT_NPORT_ATTACH_OK)
nport->attached = true;
/* If there is a pending free request, then handle it now */
if (nport->free_req_pending)
efc_nport_free_unreg_vpi(nport);
}
static int
efc_nport_alloc_init_vpi_cb(struct efc *efc, int status, u8 *mqe, void *arg)
{
struct efc_nport *nport = arg;
if (efc_nport_get_mbox_status(nport, mqe, status)) {
efc_nport_free_resources(nport, EFC_EVT_NPORT_ALLOC_FAIL, mqe);
return -EIO;
}
efc_nport_send_evt(nport, EFC_EVT_NPORT_ALLOC_OK, mqe);
return 0;
}
static void
efc_nport_alloc_init_vpi(struct efc_nport *nport)
{
struct efc *efc = nport->efc;
u8 data[SLI4_BMBX_SIZE];
int rc;
/* If there is a pending free request, then handle it now */
if (nport->free_req_pending) {
efc_nport_free_resources(nport, EFC_EVT_NPORT_FREE_OK, data);
return;
}
rc = sli_cmd_init_vpi(efc->sli, data,
nport->indicator, nport->domain->indicator);
if (rc) {
efc_log_err(efc, "INIT_VPI format failure\n");
efc_nport_free_resources(nport, EFC_EVT_NPORT_ALLOC_FAIL, data);
return;
}
rc = efc->tt.issue_mbox_rqst(efc->base, data,
efc_nport_alloc_init_vpi_cb, nport);
if (rc) {
efc_log_err(efc, "INIT_VPI command failure\n");
efc_nport_free_resources(nport, EFC_EVT_NPORT_ALLOC_FAIL, data);
}
}
static int
efc_nport_alloc_read_sparm64_cb(struct efc *efc, int status, u8 *mqe, void *arg)
{
struct efc_nport *nport = arg;
u8 *payload = NULL;
if (efc_nport_get_mbox_status(nport, mqe, status)) {
efc_nport_free_resources(nport, EFC_EVT_NPORT_ALLOC_FAIL, mqe);
return -EIO;
}
payload = nport->dma.virt;
memcpy(&nport->sli_wwpn, payload + SLI4_READ_SPARM64_WWPN_OFFSET,
sizeof(nport->sli_wwpn));
memcpy(&nport->sli_wwnn, payload + SLI4_READ_SPARM64_WWNN_OFFSET,
sizeof(nport->sli_wwnn));
dma_free_coherent(&efc->pci->dev, nport->dma.size, nport->dma.virt,
nport->dma.phys);
memset(&nport->dma, 0, sizeof(struct efc_dma));
efc_nport_alloc_init_vpi(nport);
return 0;
}
static void
efc_nport_alloc_read_sparm64(struct efc *efc, struct efc_nport *nport)
{
u8 data[SLI4_BMBX_SIZE];
int rc;
/* Allocate memory for the service parameters */
nport->dma.size = EFC_SPARAM_DMA_SZ;
nport->dma.virt = dma_alloc_coherent(&efc->pci->dev,
nport->dma.size, &nport->dma.phys,
GFP_KERNEL);
if (!nport->dma.virt) {
efc_log_err(efc, "Failed to allocate DMA memory\n");
efc_nport_free_resources(nport, EFC_EVT_NPORT_ALLOC_FAIL, data);
return;
}
rc = sli_cmd_read_sparm64(efc->sli, data,
&nport->dma, nport->indicator);
if (rc) {
efc_log_err(efc, "READ_SPARM64 format failure\n");
efc_nport_free_resources(nport, EFC_EVT_NPORT_ALLOC_FAIL, data);
return;
}
rc = efc->tt.issue_mbox_rqst(efc->base, data,
efc_nport_alloc_read_sparm64_cb, nport);
if (rc) {
efc_log_err(efc, "READ_SPARM64 command failure\n");
efc_nport_free_resources(nport, EFC_EVT_NPORT_ALLOC_FAIL, data);
}
}
int
efc_cmd_nport_alloc(struct efc *efc, struct efc_nport *nport,
struct efc_domain *domain, u8 *wwpn)
{
u32 index;
nport->indicator = U32_MAX;
nport->free_req_pending = false;
if (wwpn)
memcpy(&nport->sli_wwpn, wwpn, sizeof(nport->sli_wwpn));
/*
* allocate a VPI object for the port and stores it in the
* indicator field of the port object.
*/
if (sli_resource_alloc(efc->sli, SLI4_RSRC_VPI,
&nport->indicator, &index)) {
efc_log_err(efc, "VPI allocation failure\n");
return -EIO;
}
if (domain) {
/*
* If the WWPN is NULL, fetch the default
* WWPN and WWNN before initializing the VPI
*/
if (!wwpn)
efc_nport_alloc_read_sparm64(efc, nport);
else
efc_nport_alloc_init_vpi(nport);
} else if (!wwpn) {
/* domain NULL and wwpn non-NULL */
efc_log_err(efc, "need WWN for physical port\n");
sli_resource_free(efc->sli, SLI4_RSRC_VPI, nport->indicator);
return -EIO;
}
return 0;
}
static int
efc_nport_attach_reg_vpi_cb(struct efc *efc, int status, u8 *mqe,
void *arg)
{
struct efc_nport *nport = arg;
nport->attaching = false;
if (efc_nport_get_mbox_status(nport, mqe, status)) {
efc_nport_free_resources(nport, EFC_EVT_NPORT_ATTACH_FAIL, mqe);
return -EIO;
}
efc_nport_send_evt(nport, EFC_EVT_NPORT_ATTACH_OK, mqe);
return 0;
}
int
efc_cmd_nport_attach(struct efc *efc, struct efc_nport *nport, u32 fc_id)
{
u8 buf[SLI4_BMBX_SIZE];
int rc = 0;
if (!nport) {
efc_log_err(efc, "bad param(s) nport=%p\n", nport);
return -EIO;
}
nport->fc_id = fc_id;
/* register previously-allocated VPI with the device */
rc = sli_cmd_reg_vpi(efc->sli, buf, nport->fc_id,
nport->sli_wwpn, nport->indicator,
nport->domain->indicator, false);
if (rc) {
efc_log_err(efc, "REG_VPI format failure\n");
efc_nport_free_resources(nport, EFC_EVT_NPORT_ATTACH_FAIL, buf);
return rc;
}
rc = efc->tt.issue_mbox_rqst(efc->base, buf,
efc_nport_attach_reg_vpi_cb, nport);
if (rc) {
efc_log_err(efc, "REG_VPI command failure\n");
efc_nport_free_resources(nport, EFC_EVT_NPORT_ATTACH_FAIL, buf);
} else {
nport->attaching = true;
}
return rc;
}
int
efc_cmd_nport_free(struct efc *efc, struct efc_nport *nport)
{
if (!nport) {
efc_log_err(efc, "bad parameter(s) nport=%p\n", nport);
return -EIO;
}
/* Issue the UNREG_VPI command to free the assigned VPI context */
if (nport->attached)
efc_nport_free_unreg_vpi(nport);
else if (nport->attaching)
nport->free_req_pending = true;
else
efc_sm_post_event(&nport->sm, EFC_EVT_NPORT_FREE_OK, NULL);
return 0;
}
static int
efc_domain_get_mbox_status(struct efc_domain *domain, u8 *mqe, int status)
{
struct efc *efc = domain->efc;
struct sli4_mbox_command_header *hdr =
(struct sli4_mbox_command_header *)mqe;
if (status || le16_to_cpu(hdr->status)) {
efc_log_debug(efc, "bad status vfi=%#x st=%x hdr=%x\n",
domain->indicator, status,
le16_to_cpu(hdr->status));
return -EIO;
}
return 0;
}
static void
efc_domain_free_resources(struct efc_domain *domain, int evt, void *data)
{
struct efc *efc = domain->efc;
/* Free the service parameters buffer */
if (domain->dma.virt) {
dma_free_coherent(&efc->pci->dev,
domain->dma.size, domain->dma.virt,
domain->dma.phys);
memset(&domain->dma, 0, sizeof(struct efc_dma));
}
/* Free the SLI resources */
sli_resource_free(efc->sli, SLI4_RSRC_VFI, domain->indicator);
efc_domain_cb(efc, evt, domain);
}
static void
efc_domain_send_nport_evt(struct efc_domain *domain,
int port_evt, int domain_evt, void *data)
{
struct efc *efc = domain->efc;
/* Send alloc/attach ok to the physical nport */
efc_nport_send_evt(domain->nport, port_evt, NULL);
/* Now inform the registered callbacks */
efc_domain_cb(efc, domain_evt, domain);
}
static int
efc_domain_alloc_read_sparm64_cb(struct efc *efc, int status, u8 *mqe,
void *arg)
{
struct efc_domain *domain = arg;
if (efc_domain_get_mbox_status(domain, mqe, status)) {
efc_domain_free_resources(domain,
EFC_HW_DOMAIN_ALLOC_FAIL, mqe);
return -EIO;
}
efc_domain_send_nport_evt(domain, EFC_EVT_NPORT_ALLOC_OK,
EFC_HW_DOMAIN_ALLOC_OK, mqe);
return 0;
}
static void
efc_domain_alloc_read_sparm64(struct efc_domain *domain)
{
struct efc *efc = domain->efc;
u8 data[SLI4_BMBX_SIZE];
int rc;
rc = sli_cmd_read_sparm64(efc->sli, data, &domain->dma, 0);
if (rc) {
efc_log_err(efc, "READ_SPARM64 format failure\n");
efc_domain_free_resources(domain,
EFC_HW_DOMAIN_ALLOC_FAIL, data);
return;
}
rc = efc->tt.issue_mbox_rqst(efc->base, data,
efc_domain_alloc_read_sparm64_cb, domain);
if (rc) {
efc_log_err(efc, "READ_SPARM64 command failure\n");
efc_domain_free_resources(domain,
EFC_HW_DOMAIN_ALLOC_FAIL, data);
}
}
static int
efc_domain_alloc_init_vfi_cb(struct efc *efc, int status, u8 *mqe,
void *arg)
{
struct efc_domain *domain = arg;
if (efc_domain_get_mbox_status(domain, mqe, status)) {
efc_domain_free_resources(domain,
EFC_HW_DOMAIN_ALLOC_FAIL, mqe);
return -EIO;
}
efc_domain_alloc_read_sparm64(domain);
return 0;
}
static void
efc_domain_alloc_init_vfi(struct efc_domain *domain)
{
struct efc *efc = domain->efc;
struct efc_nport *nport = domain->nport;
u8 data[SLI4_BMBX_SIZE];
int rc;
/*
* For FC, the HW alread registered an FCFI.
* Copy FCF information into the domain and jump to INIT_VFI.
*/
domain->fcf_indicator = efc->fcfi;
rc = sli_cmd_init_vfi(efc->sli, data, domain->indicator,
domain->fcf_indicator, nport->indicator);
if (rc) {
efc_log_err(efc, "INIT_VFI format failure\n");
efc_domain_free_resources(domain,
EFC_HW_DOMAIN_ALLOC_FAIL, data);
return;
}
efc_log_err(efc, "%s issue mbox\n", __func__);
rc = efc->tt.issue_mbox_rqst(efc->base, data,
efc_domain_alloc_init_vfi_cb, domain);
if (rc) {
efc_log_err(efc, "INIT_VFI command failure\n");
efc_domain_free_resources(domain,
EFC_HW_DOMAIN_ALLOC_FAIL, data);
}
}
int
efc_cmd_domain_alloc(struct efc *efc, struct efc_domain *domain, u32 fcf)
{
u32 index;
if (!domain || !domain->nport) {
efc_log_err(efc, "bad parameter(s) domain=%p nport=%p\n",
domain, domain ? domain->nport : NULL);
return -EIO;
}
/* allocate memory for the service parameters */
domain->dma.size = EFC_SPARAM_DMA_SZ;
domain->dma.virt = dma_alloc_coherent(&efc->pci->dev,
domain->dma.size,
&domain->dma.phys, GFP_KERNEL);
if (!domain->dma.virt) {
efc_log_err(efc, "Failed to allocate DMA memory\n");
return -EIO;
}
domain->fcf = fcf;
domain->fcf_indicator = U32_MAX;
domain->indicator = U32_MAX;
if (sli_resource_alloc(efc->sli, SLI4_RSRC_VFI, &domain->indicator,
&index)) {
efc_log_err(efc, "VFI allocation failure\n");
dma_free_coherent(&efc->pci->dev,
domain->dma.size, domain->dma.virt,
domain->dma.phys);
memset(&domain->dma, 0, sizeof(struct efc_dma));
return -EIO;
}
efc_domain_alloc_init_vfi(domain);
return 0;
}
static int
efc_domain_attach_reg_vfi_cb(struct efc *efc, int status, u8 *mqe,
void *arg)
{
struct efc_domain *domain = arg;
if (efc_domain_get_mbox_status(domain, mqe, status)) {
efc_domain_free_resources(domain,
EFC_HW_DOMAIN_ATTACH_FAIL, mqe);
return -EIO;
}
efc_domain_send_nport_evt(domain, EFC_EVT_NPORT_ATTACH_OK,
EFC_HW_DOMAIN_ATTACH_OK, mqe);
return 0;
}
int
efc_cmd_domain_attach(struct efc *efc, struct efc_domain *domain, u32 fc_id)
{
u8 buf[SLI4_BMBX_SIZE];
int rc = 0;
if (!domain) {
efc_log_err(efc, "bad param(s) domain=%p\n", domain);
return -EIO;
}
domain->nport->fc_id = fc_id;
rc = sli_cmd_reg_vfi(efc->sli, buf, SLI4_BMBX_SIZE, domain->indicator,
domain->fcf_indicator, domain->dma,
domain->nport->indicator, domain->nport->sli_wwpn,
domain->nport->fc_id);
if (rc) {
efc_log_err(efc, "REG_VFI format failure\n");
goto cleanup;
}
rc = efc->tt.issue_mbox_rqst(efc->base, buf,
efc_domain_attach_reg_vfi_cb, domain);
if (rc) {
efc_log_err(efc, "REG_VFI command failure\n");
goto cleanup;
}
return rc;
cleanup:
efc_domain_free_resources(domain, EFC_HW_DOMAIN_ATTACH_FAIL, buf);
return rc;
}
static int
efc_domain_free_unreg_vfi_cb(struct efc *efc, int status, u8 *mqe, void *arg)
{
struct efc_domain *domain = arg;
int evt = EFC_HW_DOMAIN_FREE_OK;
int rc;
rc = efc_domain_get_mbox_status(domain, mqe, status);
if (rc) {
evt = EFC_HW_DOMAIN_FREE_FAIL;
rc = -EIO;
}
efc_domain_free_resources(domain, evt, mqe);
return rc;
}
static void
efc_domain_free_unreg_vfi(struct efc_domain *domain)
{
struct efc *efc = domain->efc;
int rc;
u8 data[SLI4_BMBX_SIZE];
rc = sli_cmd_unreg_vfi(efc->sli, data, domain->indicator,
SLI4_UNREG_TYPE_DOMAIN);
if (rc) {
efc_log_err(efc, "UNREG_VFI format failure\n");
goto cleanup;
}
rc = efc->tt.issue_mbox_rqst(efc->base, data,
efc_domain_free_unreg_vfi_cb, domain);
if (rc) {
efc_log_err(efc, "UNREG_VFI command failure\n");
goto cleanup;
}
return;
cleanup:
efc_domain_free_resources(domain, EFC_HW_DOMAIN_FREE_FAIL, data);
}
int
efc_cmd_domain_free(struct efc *efc, struct efc_domain *domain)
{
if (!domain) {
efc_log_err(efc, "bad parameter(s) domain=%p\n", domain);
return -EIO;
}
efc_domain_free_unreg_vfi(domain);
return 0;
}
int
efc_cmd_node_alloc(struct efc *efc, struct efc_remote_node *rnode, u32 fc_addr,
struct efc_nport *nport)
{
/* Check for invalid indicator */
if (rnode->indicator != U32_MAX) {
efc_log_err(efc,
"RPI allocation failure addr=%#x rpi=%#x\n",
fc_addr, rnode->indicator);
return -EIO;
}
/* NULL SLI port indicates an unallocated remote node */
rnode->nport = NULL;
if (sli_resource_alloc(efc->sli, SLI4_RSRC_RPI,
&rnode->indicator, &rnode->index)) {
efc_log_err(efc, "RPI allocation failure addr=%#x\n",
fc_addr);
return -EIO;
}
rnode->fc_id = fc_addr;
rnode->nport = nport;
return 0;
}
static int
efc_cmd_node_attach_cb(struct efc *efc, int status, u8 *mqe, void *arg)
{
struct efc_remote_node *rnode = arg;
struct sli4_mbox_command_header *hdr =
(struct sli4_mbox_command_header *)mqe;
int evt = 0;
if (status || le16_to_cpu(hdr->status)) {
efc_log_debug(efc, "bad status cqe=%#x mqe=%#x\n", status,
le16_to_cpu(hdr->status));
rnode->attached = false;
evt = EFC_EVT_NODE_ATTACH_FAIL;
} else {
rnode->attached = true;
evt = EFC_EVT_NODE_ATTACH_OK;
}
efc_remote_node_cb(efc, evt, rnode);
return 0;
}
int
efc_cmd_node_attach(struct efc *efc, struct efc_remote_node *rnode,
struct efc_dma *sparms)
{
int rc = -EIO;
u8 buf[SLI4_BMBX_SIZE];
if (!rnode || !sparms) {
efc_log_err(efc, "bad parameter(s) rnode=%p sparms=%p\n",
rnode, sparms);
return -EIO;
}
/*
* If the attach count is non-zero, this RPI has already been reg'd.
* Otherwise, register the RPI
*/
if (rnode->index == U32_MAX) {
efc_log_err(efc, "bad parameter rnode->index invalid\n");
return -EIO;
}
/* Update a remote node object with the remote port's service params */
if (!sli_cmd_reg_rpi(efc->sli, buf, rnode->indicator,
rnode->nport->indicator, rnode->fc_id, sparms, 0, 0))
rc = efc->tt.issue_mbox_rqst(efc->base, buf,
efc_cmd_node_attach_cb, rnode);
return rc;
}
int
efc_node_free_resources(struct efc *efc, struct efc_remote_node *rnode)
{
int rc = 0;
if (!rnode) {
efc_log_err(efc, "bad parameter rnode=%p\n", rnode);
return -EIO;
}
if (rnode->nport) {
if (rnode->attached) {
efc_log_err(efc, "rnode is still attached\n");
return -EIO;
}
if (rnode->indicator != U32_MAX) {
if (sli_resource_free(efc->sli, SLI4_RSRC_RPI,
rnode->indicator)) {
efc_log_err(efc,
"RPI free fail RPI %d addr=%#x\n",
rnode->indicator, rnode->fc_id);
rc = -EIO;
} else {
rnode->indicator = U32_MAX;
rnode->index = U32_MAX;
}
}
}
return rc;
}
static int
efc_cmd_node_free_cb(struct efc *efc, int status, u8 *mqe, void *arg)
{
struct efc_remote_node *rnode = arg;
struct sli4_mbox_command_header *hdr =
(struct sli4_mbox_command_header *)mqe;
int evt = EFC_EVT_NODE_FREE_FAIL;
int rc = 0;
if (status || le16_to_cpu(hdr->status)) {
efc_log_debug(efc, "bad status cqe=%#x mqe=%#x\n", status,
le16_to_cpu(hdr->status));
/*
* In certain cases, a non-zero MQE status is OK (all must be
* true):
* - node is attached
* - status is 0x1400
*/
if (!rnode->attached ||
(le16_to_cpu(hdr->status) != SLI4_MBX_STATUS_RPI_NOT_REG))
rc = -EIO;
}
if (!rc) {
rnode->attached = false;
evt = EFC_EVT_NODE_FREE_OK;
}
efc_remote_node_cb(efc, evt, rnode);
return rc;
}
int
efc_cmd_node_detach(struct efc *efc, struct efc_remote_node *rnode)
{
u8 buf[SLI4_BMBX_SIZE];
int rc = -EIO;
if (!rnode) {
efc_log_err(efc, "bad parameter rnode=%p\n", rnode);
return -EIO;
}
if (rnode->nport) {
if (!rnode->attached)
return -EIO;
rc = -EIO;
if (!sli_cmd_unreg_rpi(efc->sli, buf, rnode->indicator,
SLI4_RSRC_RPI, U32_MAX))
rc = efc->tt.issue_mbox_rqst(efc->base, buf,
efc_cmd_node_free_cb, rnode);
if (rc != 0) {
efc_log_err(efc, "UNREG_RPI failed\n");
rc = -EIO;
}
}
return rc;
}
@@ -0,0 +1,35 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2021 Broadcom. All Rights Reserved. The term
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*/
#ifndef __EFC_CMDS_H__
#define __EFC_CMDS_H__
#define EFC_SPARAM_DMA_SZ 112
int
efc_cmd_nport_alloc(struct efc *efc, struct efc_nport *nport,
struct efc_domain *domain, u8 *wwpn);
int
efc_cmd_nport_attach(struct efc *efc, struct efc_nport *nport, u32 fc_id);
int
efc_cmd_nport_free(struct efc *efc, struct efc_nport *nport);
int
efc_cmd_domain_alloc(struct efc *efc, struct efc_domain *domain, u32 fcf);
int
efc_cmd_domain_attach(struct efc *efc, struct efc_domain *domain, u32 fc_id);
int
efc_cmd_domain_free(struct efc *efc, struct efc_domain *domain);
int
efc_cmd_node_detach(struct efc *efc, struct efc_remote_node *rnode);
int
efc_node_free_resources(struct efc *efc, struct efc_remote_node *rnode);
int
efc_cmd_node_attach(struct efc *efc, struct efc_remote_node *rnode,
struct efc_dma *sparms);
int
efc_cmd_node_alloc(struct efc *efc, struct efc_remote_node *rnode, u32 fc_addr,
struct efc_nport *nport);
#endif /* __EFC_CMDS_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,72 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2021 Broadcom. All Rights Reserved. The term
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*/
/*
* Node state machine functions for remote device node sm
*/
#ifndef __EFCT_DEVICE_H__
#define __EFCT_DEVICE_H__
void
efc_node_init_device(struct efc_node *node, bool send_plogi);
void
efc_process_prli_payload(struct efc_node *node,
void *prli);
void
efc_d_send_prli_rsp(struct efc_node *node, uint16_t ox_id);
void
efc_send_ls_acc_after_attach(struct efc_node *node,
struct fc_frame_header *hdr,
enum efc_node_send_ls_acc ls);
void
__efc_d_wait_loop(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_d_wait_plogi_acc_cmpl(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_d_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg);
void
__efc_d_wait_plogi_rsp(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_d_wait_plogi_rsp_recvd_prli(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_d_wait_domain_attach(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_d_wait_topology_notify(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_d_wait_node_attach(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_d_wait_attach_evt_shutdown(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_d_initiate_shutdown(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_d_port_logged_in(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_d_wait_logo_acc_cmpl(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_d_device_ready(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_d_device_gone(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_d_wait_adisc_rsp(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_d_wait_logo_rsp(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
#endif /* __EFCT_DEVICE_H__ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,54 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2021 Broadcom. All Rights Reserved. The term
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*/
/*
* Declare driver's domain handler exported interface
*/
#ifndef __EFCT_DOMAIN_H__
#define __EFCT_DOMAIN_H__
struct efc_domain *
efc_domain_alloc(struct efc *efc, uint64_t fcf_wwn);
void
efc_domain_free(struct efc_domain *domain);
void
__efc_domain_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg);
void
__efc_domain_wait_alloc(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
void *arg);
void
__efc_domain_allocated(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
void *arg);
void
__efc_domain_wait_attach(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
void *arg);
void
__efc_domain_ready(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg);
void
__efc_domain_wait_nports_free(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
void *arg);
void
__efc_domain_wait_shutdown(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
void *arg);
void
__efc_domain_wait_domain_lost(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
void *arg);
void
efc_domain_attach(struct efc_domain *domain, u32 s_id);
int
efc_domain_post_event(struct efc_domain *domain, enum efc_sm_event event,
void *arg);
void
__efc_domain_attach_internal(struct efc_domain *domain, u32 s_id);
int
efc_domain_dispatch_frame(void *arg, struct efc_hw_sequence *seq);
void
efc_node_dispatch_frame(void *arg, struct efc_hw_sequence *seq);
#endif /* __EFCT_DOMAIN_H__ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,107 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2021 Broadcom. All Rights Reserved. The term
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*/
#ifndef __EFC_ELS_H__
#define __EFC_ELS_H__
#define EFC_STATUS_INVALID INT_MAX
#define EFC_ELS_IO_POOL_SZ 1024
struct efc_els_io_req {
struct list_head list_entry;
struct kref ref;
void (*release)(struct kref *arg);
struct efc_node *node;
void *cb;
u32 els_retries_remaining;
bool els_req_free;
struct timer_list delay_timer;
const char *display_name;
struct efc_disc_io io;
};
typedef int(*efc_hw_srrs_cb_t)(void *arg, u32 length, int status,
u32 ext_status);
void _efc_els_io_free(struct kref *arg);
struct efc_els_io_req *
efc_els_io_alloc(struct efc_node *node, u32 reqlen);
struct efc_els_io_req *
efc_els_io_alloc_size(struct efc_node *node, u32 reqlen, u32 rsplen);
void efc_els_io_free(struct efc_els_io_req *els);
/* ELS command send */
typedef void (*els_cb_t)(struct efc_node *node,
struct efc_node_cb *cbdata, void *arg);
int
efc_send_plogi(struct efc_node *node);
int
efc_send_flogi(struct efc_node *node);
int
efc_send_fdisc(struct efc_node *node);
int
efc_send_prli(struct efc_node *node);
int
efc_send_prlo(struct efc_node *node);
int
efc_send_logo(struct efc_node *node);
int
efc_send_adisc(struct efc_node *node);
int
efc_send_pdisc(struct efc_node *node);
int
efc_send_scr(struct efc_node *node);
int
efc_ns_send_rftid(struct efc_node *node);
int
efc_ns_send_rffid(struct efc_node *node);
int
efc_ns_send_gidpt(struct efc_node *node);
void
efc_els_io_cleanup(struct efc_els_io_req *els, int evt, void *arg);
/* ELS acc send */
int
efc_send_ls_acc(struct efc_node *node, u32 ox_id);
int
efc_send_ls_rjt(struct efc_node *node, u32 ox_id, u32 reason_cod,
u32 reason_code_expl, u32 vendor_unique);
int
efc_send_flogi_p2p_acc(struct efc_node *node, u32 ox_id, u32 s_id);
int
efc_send_flogi_acc(struct efc_node *node, u32 ox_id, u32 is_fport);
int
efc_send_plogi_acc(struct efc_node *node, u32 ox_id);
int
efc_send_prli_acc(struct efc_node *node, u32 ox_id);
int
efc_send_logo_acc(struct efc_node *node, u32 ox_id);
int
efc_send_prlo_acc(struct efc_node *node, u32 ox_id);
int
efc_send_adisc_acc(struct efc_node *node, u32 ox_id);
int
efc_bls_send_acc_hdr(struct efc *efc, struct efc_node *node,
struct fc_frame_header *hdr);
int
efc_bls_send_rjt_hdr(struct efc_els_io_req *io, struct fc_frame_header *hdr);
int
efc_els_io_list_empty(struct efc_node *node, struct list_head *list);
/* CT */
int
efc_send_ct_rsp(struct efc *efc, struct efc_node *node, u16 ox_id,
struct fc_ct_hdr *ct_hdr, u32 cmd_rsp_code, u32 reason_code,
u32 reason_code_explanation);
int
efc_send_bls_acc(struct efc_node *node, struct fc_frame_header *hdr);
#endif /* __EFC_ELS_H__ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,116 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2021 Broadcom. All Rights Reserved. The term
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*/
/*
* Declarations for the interface exported by efc_fabric
*/
#ifndef __EFCT_FABRIC_H__
#define __EFCT_FABRIC_H__
#include "scsi/fc/fc_els.h"
#include "scsi/fc/fc_fs.h"
#include "scsi/fc/fc_ns.h"
void
__efc_fabric_init(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_fabric_flogi_wait_rsp(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_fabric_domain_attach_wait(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_fabric_wait_domain_attach(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_vport_fabric_init(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_fabric_fdisc_wait_rsp(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_fabric_wait_nport_attach(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_ns_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg);
void
__efc_ns_plogi_wait_rsp(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_ns_rftid_wait_rsp(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_ns_rffid_wait_rsp(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_ns_wait_node_attach(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_fabric_wait_attach_evt_shutdown(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_ns_logo_wait_rsp(struct efc_sm_ctx *ctx,
enum efc_sm_event, void *arg);
void
__efc_ns_gidpt_wait_rsp(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_ns_idle(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg);
void
__efc_ns_gidpt_delay(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_fabctl_init(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_fabctl_wait_node_attach(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_fabctl_wait_scr_rsp(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_fabctl_ready(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_fabctl_wait_ls_acc_cmpl(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_fabric_idle(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_p2p_rnode_init(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_p2p_domain_attach_wait(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_p2p_wait_flogi_acc_cmpl(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_p2p_wait_plogi_rsp(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_p2p_wait_plogi_rsp_recvd_prli(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_p2p_wait_domain_attach(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_p2p_wait_node_attach(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
int
efc_p2p_setup(struct efc_nport *nport);
void
efc_fabric_set_topology(struct efc_node *node,
enum efc_nport_topology topology);
void efc_fabric_notify_topology(struct efc_node *node);
#endif /* __EFCT_FABRIC_H__ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,191 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2021 Broadcom. All Rights Reserved. The term
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*/
#if !defined(__EFC_NODE_H__)
#define __EFC_NODE_H__
#include "scsi/fc/fc_ns.h"
#define EFC_NODEDB_PAUSE_FABRIC_LOGIN (1 << 0)
#define EFC_NODEDB_PAUSE_NAMESERVER (1 << 1)
#define EFC_NODEDB_PAUSE_NEW_NODES (1 << 2)
#define MAX_ACC_REJECT_PAYLOAD sizeof(struct fc_els_ls_rjt)
#define scsi_io_printf(io, fmt, ...) \
efc_log_debug(io->efc, "[%s] [%04x][i:%04x t:%04x h:%04x]" fmt, \
io->node->display_name, io->instance_index, io->init_task_tag, \
io->tgt_task_tag, io->hw_tag, ##__VA_ARGS__)
static inline void
efc_node_evt_set(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
const char *handler)
{
struct efc_node *node = ctx->app;
if (evt == EFC_EVT_ENTER) {
strscpy_pad(node->current_state_name, handler,
sizeof(node->current_state_name));
} else if (evt == EFC_EVT_EXIT) {
memcpy(node->prev_state_name, node->current_state_name,
sizeof(node->prev_state_name));
strscpy_pad(node->current_state_name, "invalid",
sizeof(node->current_state_name));
}
node->prev_evt = node->current_evt;
node->current_evt = evt;
}
/**
* hold frames in pending frame list
*
* Unsolicited receive frames are held on the node pending frame list,
* rather than being processed.
*/
static inline void
efc_node_hold_frames(struct efc_node *node)
{
node->hold_frames = true;
}
/**
* accept frames
*
* Unsolicited receive frames processed rather than being held on the node
* pending frame list.
*/
static inline void
efc_node_accept_frames(struct efc_node *node)
{
node->hold_frames = false;
}
/*
* Node initiator/target enable defines
* All combinations of the SLI port (nport) initiator/target enable,
* and remote node initiator/target enable are enumerated.
* ex: EFC_NODE_ENABLE_T_TO_IT decodes to target mode is enabled on SLI port
* and I+T is enabled on remote node.
*/
enum efc_node_enable {
EFC_NODE_ENABLE_x_TO_x,
EFC_NODE_ENABLE_x_TO_T,
EFC_NODE_ENABLE_x_TO_I,
EFC_NODE_ENABLE_x_TO_IT,
EFC_NODE_ENABLE_T_TO_x,
EFC_NODE_ENABLE_T_TO_T,
EFC_NODE_ENABLE_T_TO_I,
EFC_NODE_ENABLE_T_TO_IT,
EFC_NODE_ENABLE_I_TO_x,
EFC_NODE_ENABLE_I_TO_T,
EFC_NODE_ENABLE_I_TO_I,
EFC_NODE_ENABLE_I_TO_IT,
EFC_NODE_ENABLE_IT_TO_x,
EFC_NODE_ENABLE_IT_TO_T,
EFC_NODE_ENABLE_IT_TO_I,
EFC_NODE_ENABLE_IT_TO_IT,
};
static inline enum efc_node_enable
efc_node_get_enable(struct efc_node *node)
{
u32 retval = 0;
if (node->nport->enable_ini)
retval |= (1U << 3);
if (node->nport->enable_tgt)
retval |= (1U << 2);
if (node->init)
retval |= (1U << 1);
if (node->targ)
retval |= (1U << 0);
return (enum efc_node_enable)retval;
}
int
efc_node_check_els_req(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg,
u8 cmd, void (*efc_node_common_func)(const char *,
struct efc_sm_ctx *, enum efc_sm_event, void *),
const char *funcname);
int
efc_node_check_ns_req(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg,
u16 cmd, void (*efc_node_common_func)(const char *,
struct efc_sm_ctx *, enum efc_sm_event, void *),
const char *funcname);
int
efc_node_attach(struct efc_node *node);
struct efc_node *
efc_node_alloc(struct efc_nport *nport, u32 port_id,
bool init, bool targ);
void
efc_node_free(struct efc_node *efc);
void
efc_node_update_display_name(struct efc_node *node);
void efc_node_post_event(struct efc_node *node, enum efc_sm_event evt,
void *arg);
void
__efc_node_shutdown(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_node_wait_node_free(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_node_wait_els_shutdown(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_node_wait_ios_shutdown(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
efc_node_save_sparms(struct efc_node *node, void *payload);
void
efc_node_transition(struct efc_node *node,
void (*state)(struct efc_sm_ctx *, enum efc_sm_event,
void *), void *data);
void
__efc_node_common(const char *funcname, struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
efc_node_initiate_cleanup(struct efc_node *node);
void
efc_node_build_eui_name(char *buf, u32 buf_len, uint64_t eui_name);
void
efc_node_pause(struct efc_node *node,
void (*state)(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg));
void
__efc_node_paused(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
int
efc_node_active_ios_empty(struct efc_node *node);
void
efc_node_send_ls_io_cleanup(struct efc_node *node);
int
efc_els_io_list_empty(struct efc_node *node, struct list_head *list);
void
efc_process_node_pending(struct efc_node *domain);
u64 efc_node_get_wwnn(struct efc_node *node);
struct efc_node *
efc_node_find(struct efc_nport *nport, u32 id);
void
efc_node_post_els_resp(struct efc_node *node, u32 evt, void *arg);
void
efc_node_recv_els_frame(struct efc_node *node, struct efc_hw_sequence *s);
void
efc_node_recv_ct_frame(struct efc_node *node, struct efc_hw_sequence *seq);
void
efc_node_recv_fcp_cmd(struct efc_node *node, struct efc_hw_sequence *seq);
#endif /* __EFC_NODE_H__ */
@@ -0,0 +1,777 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021 Broadcom. All Rights Reserved. The term
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*/
/*
* NPORT
*
* Port object for physical port and NPIV ports.
*/
/*
* NPORT REFERENCE COUNTING
*
* A nport reference should be taken when:
* - an nport is allocated
* - a vport populates associated nport
* - a remote node is allocated
* - a unsolicited frame is processed
* The reference should be dropped when:
* - the unsolicited frame processesing is done
* - the remote node is removed
* - the vport is removed
* - the nport is removed
*/
#include "efc.h"
void
efc_nport_cb(void *arg, int event, void *data)
{
struct efc *efc = arg;
struct efc_nport *nport = data;
unsigned long flags = 0;
efc_log_debug(efc, "nport event: %s\n", efc_sm_event_name(event));
spin_lock_irqsave(&efc->lock, flags);
efc_sm_post_event(&nport->sm, event, NULL);
spin_unlock_irqrestore(&efc->lock, flags);
}
static struct efc_nport *
efc_nport_find_wwn(struct efc_domain *domain, uint64_t wwnn, uint64_t wwpn)
{
struct efc_nport *nport = NULL;
/* Find a nport, given the WWNN and WWPN */
list_for_each_entry(nport, &domain->nport_list, list_entry) {
if (nport->wwnn == wwnn && nport->wwpn == wwpn)
return nport;
}
return NULL;
}
static void
_efc_nport_free(struct kref *arg)
{
struct efc_nport *nport = container_of(arg, struct efc_nport, ref);
kfree(nport);
}
struct efc_nport *
efc_nport_alloc(struct efc_domain *domain, uint64_t wwpn, uint64_t wwnn,
u32 fc_id, bool enable_ini, bool enable_tgt)
{
struct efc_nport *nport;
if (domain->efc->enable_ini)
enable_ini = 0;
/* Return a failure if this nport has already been allocated */
if ((wwpn != 0) || (wwnn != 0)) {
nport = efc_nport_find_wwn(domain, wwnn, wwpn);
if (nport) {
efc_log_err(domain->efc,
"NPORT %016llX %016llX already allocated\n",
wwnn, wwpn);
return NULL;
}
}
nport = kzalloc_obj(*nport, GFP_ATOMIC);
if (!nport)
return nport;
/* initialize refcount */
kref_init(&nport->ref);
nport->release = _efc_nport_free;
nport->efc = domain->efc;
snprintf(nport->display_name, sizeof(nport->display_name), "------");
nport->domain = domain;
xa_init(&nport->lookup);
nport->instance_index = domain->nport_count++;
nport->sm.app = nport;
nport->enable_ini = enable_ini;
nport->enable_tgt = enable_tgt;
nport->enable_rscn = (nport->enable_ini ||
(nport->enable_tgt && enable_target_rscn(nport->efc)));
/* Copy service parameters from domain */
memcpy(nport->service_params, domain->service_params,
sizeof(struct fc_els_flogi));
/* Update requested fc_id */
nport->fc_id = fc_id;
/* Update the nport's service parameters for the new wwn's */
nport->wwpn = wwpn;
nport->wwnn = wwnn;
snprintf(nport->wwnn_str, sizeof(nport->wwnn_str), "%016llX",
(unsigned long long)wwnn);
/*
* if this is the "first" nport of the domain,
* then make it the "phys" nport
*/
if (list_empty(&domain->nport_list))
domain->nport = nport;
INIT_LIST_HEAD(&nport->list_entry);
list_add_tail(&nport->list_entry, &domain->nport_list);
kref_get(&domain->ref);
efc_log_debug(domain->efc, "New Nport [%s]\n", nport->display_name);
return nport;
}
void
efc_nport_free(struct efc_nport *nport)
{
struct efc_domain *domain;
if (!nport)
return;
domain = nport->domain;
efc_log_debug(domain->efc, "[%s] free nport\n", nport->display_name);
list_del(&nport->list_entry);
/*
* if this is the physical nport,
* then clear it out of the domain
*/
if (nport == domain->nport)
domain->nport = NULL;
xa_destroy(&nport->lookup);
xa_erase(&domain->lookup, nport->fc_id);
if (list_empty(&domain->nport_list))
efc_domain_post_event(domain, EFC_EVT_ALL_CHILD_NODES_FREE,
NULL);
kref_put(&domain->ref, domain->release);
kref_put(&nport->ref, nport->release);
}
struct efc_nport *
efc_nport_find(struct efc_domain *domain, u32 d_id)
{
struct efc_nport *nport;
/* Find a nport object, given an FC_ID */
nport = xa_load(&domain->lookup, d_id);
if (!nport || !kref_get_unless_zero(&nport->ref))
return NULL;
return nport;
}
int
efc_nport_attach(struct efc_nport *nport, u32 fc_id)
{
int rc;
struct efc_node *node;
struct efc *efc = nport->efc;
unsigned long index;
/* Set our lookup */
rc = xa_err(xa_store(&nport->domain->lookup, fc_id, nport, GFP_ATOMIC));
if (rc) {
efc_log_err(efc, "Sport lookup store failed: %d\n", rc);
return rc;
}
/* Update our display_name */
efc_node_fcid_display(fc_id, nport->display_name,
sizeof(nport->display_name));
xa_for_each(&nport->lookup, index, node) {
efc_node_update_display_name(node);
}
efc_log_debug(nport->efc, "[%s] attach nport: fc_id x%06x\n",
nport->display_name, fc_id);
/* Register a nport, given an FC_ID */
rc = efc_cmd_nport_attach(efc, nport, fc_id);
if (rc < 0) {
efc_log_err(nport->efc,
"efc_hw_port_attach failed: %d\n", rc);
return -EIO;
}
return 0;
}
static void
efc_nport_shutdown(struct efc_nport *nport)
{
struct efc *efc = nport->efc;
struct efc_node *node;
unsigned long index;
xa_for_each(&nport->lookup, index, node) {
if (!(node->rnode.fc_id == FC_FID_FLOGI && nport->is_vport)) {
efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
continue;
}
/*
* If this is a vport, logout of the fabric
* controller so that it deletes the vport
* on the switch.
*/
/* if link is down, don't send logo */
if (efc->link_status == EFC_LINK_STATUS_DOWN) {
efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
continue;
}
efc_log_debug(efc, "[%s] nport shutdown vport, send logo\n",
node->display_name);
if (!efc_send_logo(node)) {
/* sent LOGO, wait for response */
efc_node_transition(node, __efc_d_wait_logo_rsp, NULL);
continue;
}
/*
* failed to send LOGO,
* go ahead and cleanup node anyways
*/
node_printf(node, "Failed to send LOGO\n");
efc_node_post_event(node, EFC_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
}
}
static void
efc_vport_link_down(struct efc_nport *nport)
{
struct efc *efc = nport->efc;
struct efc_vport *vport;
/* Clear the nport reference in the vport specification */
list_for_each_entry(vport, &efc->vport_list, list_entry) {
if (vport->nport == nport) {
kref_put(&nport->ref, nport->release);
vport->nport = NULL;
break;
}
}
}
static void
__efc_nport_common(const char *funcname, struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg)
{
struct efc_nport *nport = ctx->app;
struct efc_domain *domain = nport->domain;
struct efc *efc = nport->efc;
switch (evt) {
case EFC_EVT_ENTER:
case EFC_EVT_REENTER:
case EFC_EVT_EXIT:
case EFC_EVT_ALL_CHILD_NODES_FREE:
break;
case EFC_EVT_NPORT_ATTACH_OK:
efc_sm_transition(ctx, __efc_nport_attached, NULL);
break;
case EFC_EVT_SHUTDOWN:
/* Flag this nport as shutting down */
nport->shutting_down = true;
if (nport->is_vport)
efc_vport_link_down(nport);
if (xa_empty(&nport->lookup)) {
/* Remove the nport from the domain's lookup table */
xa_erase(&domain->lookup, nport->fc_id);
efc_sm_transition(ctx, __efc_nport_wait_port_free,
NULL);
if (efc_cmd_nport_free(efc, nport)) {
efc_log_debug(nport->efc,
"efc_hw_port_free failed\n");
/* Not much we can do, free the nport anyways */
efc_nport_free(nport);
}
} else {
/* sm: node list is not empty / shutdown nodes */
efc_sm_transition(ctx,
__efc_nport_wait_shutdown, NULL);
efc_nport_shutdown(nport);
}
break;
default:
efc_log_debug(nport->efc, "[%s] %-20s %-20s not handled\n",
nport->display_name, funcname,
efc_sm_event_name(evt));
}
}
void
__efc_nport_allocated(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg)
{
struct efc_nport *nport = ctx->app;
struct efc_domain *domain = nport->domain;
nport_sm_trace(nport);
switch (evt) {
/* the physical nport is attached */
case EFC_EVT_NPORT_ATTACH_OK:
WARN_ON(nport != domain->nport);
efc_sm_transition(ctx, __efc_nport_attached, NULL);
break;
case EFC_EVT_NPORT_ALLOC_OK:
/* ignore */
break;
default:
__efc_nport_common(__func__, ctx, evt, arg);
}
}
void
__efc_nport_vport_init(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg)
{
struct efc_nport *nport = ctx->app;
struct efc *efc = nport->efc;
nport_sm_trace(nport);
switch (evt) {
case EFC_EVT_ENTER: {
__be64 be_wwpn = cpu_to_be64(nport->wwpn);
if (nport->wwpn == 0)
efc_log_debug(efc, "vport: letting f/w select WWN\n");
if (nport->fc_id != U32_MAX) {
efc_log_debug(efc, "vport: hard coding port id: %x\n",
nport->fc_id);
}
efc_sm_transition(ctx, __efc_nport_vport_wait_alloc, NULL);
/* If wwpn is zero, then we'll let the f/w assign wwpn*/
if (efc_cmd_nport_alloc(efc, nport, nport->domain,
nport->wwpn == 0 ? NULL :
(uint8_t *)&be_wwpn)) {
efc_log_err(efc, "Can't allocate port\n");
break;
}
break;
}
default:
__efc_nport_common(__func__, ctx, evt, arg);
}
}
void
__efc_nport_vport_wait_alloc(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg)
{
struct efc_nport *nport = ctx->app;
struct efc *efc = nport->efc;
nport_sm_trace(nport);
switch (evt) {
case EFC_EVT_NPORT_ALLOC_OK: {
struct fc_els_flogi *sp;
sp = (struct fc_els_flogi *)nport->service_params;
if (nport->wwnn == 0) {
nport->wwnn = be64_to_cpu(nport->sli_wwnn);
nport->wwpn = be64_to_cpu(nport->sli_wwpn);
snprintf(nport->wwnn_str, sizeof(nport->wwnn_str),
"%016llX", nport->wwpn);
}
/* Update the nport's service parameters */
sp->fl_wwpn = cpu_to_be64(nport->wwpn);
sp->fl_wwnn = cpu_to_be64(nport->wwnn);
/*
* if nport->fc_id is uninitialized,
* then request that the fabric node use FDISC
* to find an fc_id.
* Otherwise we're restoring vports, or we're in
* fabric emulation mode, so attach the fc_id
*/
if (nport->fc_id == U32_MAX) {
struct efc_node *fabric;
fabric = efc_node_alloc(nport, FC_FID_FLOGI, false,
false);
if (!fabric) {
efc_log_err(efc, "efc_node_alloc() failed\n");
return;
}
efc_node_transition(fabric, __efc_vport_fabric_init,
NULL);
} else {
snprintf(nport->wwnn_str, sizeof(nport->wwnn_str),
"%016llX", nport->wwpn);
efc_nport_attach(nport, nport->fc_id);
}
efc_sm_transition(ctx, __efc_nport_vport_allocated, NULL);
break;
}
default:
__efc_nport_common(__func__, ctx, evt, arg);
}
}
void
__efc_nport_vport_allocated(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg)
{
struct efc_nport *nport = ctx->app;
struct efc *efc = nport->efc;
nport_sm_trace(nport);
/*
* This state is entered after the nport is allocated;
* it then waits for a fabric node
* FDISC to complete, which requests a nport attach.
* The nport attach complete is handled in this state.
*/
switch (evt) {
case EFC_EVT_NPORT_ATTACH_OK: {
struct efc_node *node;
/* Find our fabric node, and forward this event */
node = efc_node_find(nport, FC_FID_FLOGI);
if (!node) {
efc_log_debug(efc, "can't find node %06x\n", FC_FID_FLOGI);
break;
}
/* sm: / forward nport attach to fabric node */
efc_node_post_event(node, evt, NULL);
efc_sm_transition(ctx, __efc_nport_attached, NULL);
break;
}
default:
__efc_nport_common(__func__, ctx, evt, arg);
}
}
static void
efc_vport_update_spec(struct efc_nport *nport)
{
struct efc *efc = nport->efc;
struct efc_vport *vport;
unsigned long flags = 0;
spin_lock_irqsave(&efc->vport_lock, flags);
list_for_each_entry(vport, &efc->vport_list, list_entry) {
if (vport->nport == nport) {
vport->wwnn = nport->wwnn;
vport->wwpn = nport->wwpn;
vport->tgt_data = nport->tgt_data;
vport->ini_data = nport->ini_data;
break;
}
}
spin_unlock_irqrestore(&efc->vport_lock, flags);
}
void
__efc_nport_attached(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg)
{
struct efc_nport *nport = ctx->app;
struct efc *efc = nport->efc;
nport_sm_trace(nport);
switch (evt) {
case EFC_EVT_ENTER: {
struct efc_node *node;
unsigned long index;
efc_log_debug(efc,
"[%s] NPORT attached WWPN %016llX WWNN %016llX\n",
nport->display_name,
nport->wwpn, nport->wwnn);
xa_for_each(&nport->lookup, index, node)
efc_node_update_display_name(node);
efc->tt.new_nport(efc, nport);
/*
* Update the vport (if its not the physical nport)
* parameters
*/
if (nport->is_vport)
efc_vport_update_spec(nport);
break;
}
case EFC_EVT_EXIT:
efc_log_debug(efc,
"[%s] NPORT deattached WWPN %016llX WWNN %016llX\n",
nport->display_name,
nport->wwpn, nport->wwnn);
efc->tt.del_nport(efc, nport);
break;
default:
__efc_nport_common(__func__, ctx, evt, arg);
}
}
void
__efc_nport_wait_shutdown(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg)
{
struct efc_nport *nport = ctx->app;
struct efc_domain *domain = nport->domain;
struct efc *efc = nport->efc;
nport_sm_trace(nport);
switch (evt) {
case EFC_EVT_NPORT_ALLOC_OK:
case EFC_EVT_NPORT_ALLOC_FAIL:
case EFC_EVT_NPORT_ATTACH_OK:
case EFC_EVT_NPORT_ATTACH_FAIL:
/* ignore these events - just wait for the all free event */
break;
case EFC_EVT_ALL_CHILD_NODES_FREE: {
/*
* Remove the nport from the domain's
* sparse vector lookup table
*/
xa_erase(&domain->lookup, nport->fc_id);
efc_sm_transition(ctx, __efc_nport_wait_port_free, NULL);
if (efc_cmd_nport_free(efc, nport)) {
efc_log_err(nport->efc, "efc_hw_port_free failed\n");
/* Not much we can do, free the nport anyways */
efc_nport_free(nport);
}
break;
}
default:
__efc_nport_common(__func__, ctx, evt, arg);
}
}
void
__efc_nport_wait_port_free(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg)
{
struct efc_nport *nport = ctx->app;
nport_sm_trace(nport);
switch (evt) {
case EFC_EVT_NPORT_ATTACH_OK:
/* Ignore as we are waiting for the free CB */
break;
case EFC_EVT_NPORT_FREE_OK: {
/* All done, free myself */
efc_nport_free(nport);
break;
}
default:
__efc_nport_common(__func__, ctx, evt, arg);
}
}
static int
efc_vport_nport_alloc(struct efc_domain *domain, struct efc_vport *vport)
{
struct efc_nport *nport;
lockdep_assert_held(&domain->efc->lock);
nport = efc_nport_alloc(domain, vport->wwpn, vport->wwnn, vport->fc_id,
vport->enable_ini, vport->enable_tgt);
vport->nport = nport;
if (!nport)
return -EIO;
kref_get(&nport->ref);
nport->is_vport = true;
nport->tgt_data = vport->tgt_data;
nport->ini_data = vport->ini_data;
efc_sm_transition(&nport->sm, __efc_nport_vport_init, NULL);
return 0;
}
int
efc_vport_start(struct efc_domain *domain)
{
struct efc *efc = domain->efc;
struct efc_vport *vport;
struct efc_vport *next;
int rc = 0;
unsigned long flags = 0;
/* Use the vport spec to find the associated vports and start them */
spin_lock_irqsave(&efc->vport_lock, flags);
list_for_each_entry_safe(vport, next, &efc->vport_list, list_entry) {
if (!vport->nport) {
if (efc_vport_nport_alloc(domain, vport))
rc = -EIO;
}
}
spin_unlock_irqrestore(&efc->vport_lock, flags);
return rc;
}
int
efc_nport_vport_new(struct efc_domain *domain, uint64_t wwpn, uint64_t wwnn,
u32 fc_id, bool ini, bool tgt, void *tgt_data,
void *ini_data)
{
struct efc *efc = domain->efc;
struct efc_vport *vport;
int rc = 0;
unsigned long flags = 0;
if (ini && domain->efc->enable_ini == 0) {
efc_log_debug(efc, "driver initiator mode not enabled\n");
return -EIO;
}
if (tgt && domain->efc->enable_tgt == 0) {
efc_log_debug(efc, "driver target mode not enabled\n");
return -EIO;
}
/*
* Create a vport spec if we need to recreate
* this vport after a link up event
*/
vport = efc_vport_create_spec(domain->efc, wwnn, wwpn, fc_id, ini, tgt,
tgt_data, ini_data);
if (!vport) {
efc_log_err(efc, "failed to create vport object entry\n");
return -EIO;
}
spin_lock_irqsave(&efc->lock, flags);
rc = efc_vport_nport_alloc(domain, vport);
spin_unlock_irqrestore(&efc->lock, flags);
return rc;
}
int
efc_nport_vport_del(struct efc *efc, struct efc_domain *domain,
u64 wwpn, uint64_t wwnn)
{
struct efc_nport *nport;
struct efc_vport *vport;
struct efc_vport *next;
unsigned long flags = 0;
spin_lock_irqsave(&efc->vport_lock, flags);
/* walk the efc_vport_list and remove from there */
list_for_each_entry_safe(vport, next, &efc->vport_list, list_entry) {
if (vport->wwpn == wwpn && vport->wwnn == wwnn) {
list_del(&vport->list_entry);
kfree(vport);
break;
}
}
spin_unlock_irqrestore(&efc->vport_lock, flags);
if (!domain) {
/* No domain means no nport to look for */
return 0;
}
spin_lock_irqsave(&efc->lock, flags);
list_for_each_entry(nport, &domain->nport_list, list_entry) {
if (nport->wwpn == wwpn && nport->wwnn == wwnn) {
/* Shutdown this NPORT */
efc_sm_post_event(&nport->sm, EFC_EVT_SHUTDOWN, NULL);
kref_put(&nport->ref, nport->release);
break;
}
}
spin_unlock_irqrestore(&efc->lock, flags);
return 0;
}
void
efc_vport_del_all(struct efc *efc)
{
struct efc_vport *vport;
struct efc_vport *next;
unsigned long flags = 0;
spin_lock_irqsave(&efc->vport_lock, flags);
list_for_each_entry_safe(vport, next, &efc->vport_list, list_entry) {
list_del(&vport->list_entry);
kfree(vport);
}
spin_unlock_irqrestore(&efc->vport_lock, flags);
}
struct efc_vport *
efc_vport_create_spec(struct efc *efc, uint64_t wwnn, uint64_t wwpn,
u32 fc_id, bool enable_ini,
bool enable_tgt, void *tgt_data, void *ini_data)
{
struct efc_vport *vport;
unsigned long flags = 0;
/*
* walk the efc_vport_list and return failure
* if a valid(vport with non zero WWPN and WWNN) vport entry
* is already created
*/
spin_lock_irqsave(&efc->vport_lock, flags);
list_for_each_entry(vport, &efc->vport_list, list_entry) {
if ((wwpn && vport->wwpn == wwpn) &&
(wwnn && vport->wwnn == wwnn)) {
efc_log_err(efc,
"VPORT %016llX %016llX already allocated\n",
wwnn, wwpn);
spin_unlock_irqrestore(&efc->vport_lock, flags);
return NULL;
}
}
vport = kzalloc_obj(*vport, GFP_ATOMIC);
if (!vport) {
spin_unlock_irqrestore(&efc->vport_lock, flags);
return NULL;
}
vport->wwnn = wwnn;
vport->wwpn = wwpn;
vport->fc_id = fc_id;
vport->enable_tgt = enable_tgt;
vport->enable_ini = enable_ini;
vport->tgt_data = tgt_data;
vport->ini_data = ini_data;
INIT_LIST_HEAD(&vport->list_entry);
list_add_tail(&vport->list_entry, &efc->vport_list);
spin_unlock_irqrestore(&efc->vport_lock, flags);
return vport;
}
@@ -0,0 +1,50 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2021 Broadcom. All Rights Reserved. The term
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*/
/**
* EFC FC port (NPORT) exported declarations
*
*/
#ifndef __EFC_NPORT_H__
#define __EFC_NPORT_H__
struct efc_nport *
efc_nport_find(struct efc_domain *domain, u32 d_id);
struct efc_nport *
efc_nport_alloc(struct efc_domain *domain, uint64_t wwpn, uint64_t wwnn,
u32 fc_id, bool enable_ini, bool enable_tgt);
void
efc_nport_free(struct efc_nport *nport);
int
efc_nport_attach(struct efc_nport *nport, u32 fc_id);
void
__efc_nport_allocated(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_nport_wait_shutdown(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_nport_wait_port_free(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_nport_vport_init(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_nport_vport_wait_alloc(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_nport_vport_allocated(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
void
__efc_nport_attached(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
int
efc_vport_start(struct efc_domain *domain);
#endif /* __EFC_NPORT_H__ */
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021 Broadcom. All Rights Reserved. The term
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*/
/*
* Generic state machine framework.
*/
#include "efc.h"
#include "efc_sm.h"
/**
* efc_sm_post_event() - Post an event to a context.
*
* @ctx: State machine context
* @evt: Event to post
* @data: Event-specific data (if any)
*/
int
efc_sm_post_event(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *data)
{
if (!ctx->current_state)
return -EIO;
ctx->current_state(ctx, evt, data);
return 0;
}
void
efc_sm_transition(struct efc_sm_ctx *ctx,
void (*state)(struct efc_sm_ctx *,
enum efc_sm_event, void *), void *data)
{
if (ctx->current_state == state) {
efc_sm_post_event(ctx, EFC_EVT_REENTER, data);
} else {
efc_sm_post_event(ctx, EFC_EVT_EXIT, data);
ctx->current_state = state;
efc_sm_post_event(ctx, EFC_EVT_ENTER, data);
}
}
static char *event_name[] = EFC_SM_EVENT_NAME;
const char *efc_sm_event_name(enum efc_sm_event evt)
{
if (evt > EFC_EVT_LAST)
return "unknown";
return event_name[evt];
}
@@ -0,0 +1,197 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2021 Broadcom. All Rights Reserved. The term
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*
*/
/**
* Generic state machine framework declarations.
*/
#ifndef _EFC_SM_H
#define _EFC_SM_H
struct efc_sm_ctx;
/* State Machine events */
enum efc_sm_event {
/* Common Events */
EFC_EVT_ENTER,
EFC_EVT_REENTER,
EFC_EVT_EXIT,
EFC_EVT_SHUTDOWN,
EFC_EVT_ALL_CHILD_NODES_FREE,
EFC_EVT_RESUME,
EFC_EVT_TIMER_EXPIRED,
/* Domain Events */
EFC_EVT_RESPONSE,
EFC_EVT_ERROR,
EFC_EVT_DOMAIN_FOUND,
EFC_EVT_DOMAIN_ALLOC_OK,
EFC_EVT_DOMAIN_ALLOC_FAIL,
EFC_EVT_DOMAIN_REQ_ATTACH,
EFC_EVT_DOMAIN_ATTACH_OK,
EFC_EVT_DOMAIN_ATTACH_FAIL,
EFC_EVT_DOMAIN_LOST,
EFC_EVT_DOMAIN_FREE_OK,
EFC_EVT_DOMAIN_FREE_FAIL,
EFC_EVT_HW_DOMAIN_REQ_ATTACH,
EFC_EVT_HW_DOMAIN_REQ_FREE,
/* Sport Events */
EFC_EVT_NPORT_ALLOC_OK,
EFC_EVT_NPORT_ALLOC_FAIL,
EFC_EVT_NPORT_ATTACH_OK,
EFC_EVT_NPORT_ATTACH_FAIL,
EFC_EVT_NPORT_FREE_OK,
EFC_EVT_NPORT_FREE_FAIL,
EFC_EVT_NPORT_TOPOLOGY_NOTIFY,
EFC_EVT_HW_PORT_ALLOC_OK,
EFC_EVT_HW_PORT_ALLOC_FAIL,
EFC_EVT_HW_PORT_ATTACH_OK,
EFC_EVT_HW_PORT_REQ_ATTACH,
EFC_EVT_HW_PORT_REQ_FREE,
EFC_EVT_HW_PORT_FREE_OK,
/* Login Events */
EFC_EVT_SRRS_ELS_REQ_OK,
EFC_EVT_SRRS_ELS_CMPL_OK,
EFC_EVT_SRRS_ELS_REQ_FAIL,
EFC_EVT_SRRS_ELS_CMPL_FAIL,
EFC_EVT_SRRS_ELS_REQ_RJT,
EFC_EVT_NODE_ATTACH_OK,
EFC_EVT_NODE_ATTACH_FAIL,
EFC_EVT_NODE_FREE_OK,
EFC_EVT_NODE_FREE_FAIL,
EFC_EVT_ELS_FRAME,
EFC_EVT_ELS_REQ_TIMEOUT,
EFC_EVT_ELS_REQ_ABORTED,
/* request an ELS IO be aborted */
EFC_EVT_ABORT_ELS,
/* ELS abort process complete */
EFC_EVT_ELS_ABORT_CMPL,
EFC_EVT_ABTS_RCVD,
/* node is not in the GID_PT payload */
EFC_EVT_NODE_MISSING,
/* node is allocated and in the GID_PT payload */
EFC_EVT_NODE_REFOUND,
/* node shutting down due to PLOGI recvd (implicit logo) */
EFC_EVT_SHUTDOWN_IMPLICIT_LOGO,
/* node shutting down due to LOGO recvd/sent (explicit logo) */
EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
EFC_EVT_PLOGI_RCVD,
EFC_EVT_FLOGI_RCVD,
EFC_EVT_LOGO_RCVD,
EFC_EVT_PRLI_RCVD,
EFC_EVT_PRLO_RCVD,
EFC_EVT_PDISC_RCVD,
EFC_EVT_FDISC_RCVD,
EFC_EVT_ADISC_RCVD,
EFC_EVT_RSCN_RCVD,
EFC_EVT_SCR_RCVD,
EFC_EVT_ELS_RCVD,
EFC_EVT_FCP_CMD_RCVD,
EFC_EVT_GIDPT_DELAY_EXPIRED,
/* SCSI Target Server events */
EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY,
EFC_EVT_NODE_DEL_INI_COMPLETE,
EFC_EVT_NODE_DEL_TGT_COMPLETE,
EFC_EVT_NODE_SESS_REG_OK,
EFC_EVT_NODE_SESS_REG_FAIL,
/* Must be last */
EFC_EVT_LAST
};
/* State Machine event name lookup array */
#define EFC_SM_EVENT_NAME { \
[EFC_EVT_ENTER] = "EFC_EVT_ENTER", \
[EFC_EVT_REENTER] = "EFC_EVT_REENTER", \
[EFC_EVT_EXIT] = "EFC_EVT_EXIT", \
[EFC_EVT_SHUTDOWN] = "EFC_EVT_SHUTDOWN", \
[EFC_EVT_ALL_CHILD_NODES_FREE] = "EFC_EVT_ALL_CHILD_NODES_FREE",\
[EFC_EVT_RESUME] = "EFC_EVT_RESUME", \
[EFC_EVT_TIMER_EXPIRED] = "EFC_EVT_TIMER_EXPIRED", \
[EFC_EVT_RESPONSE] = "EFC_EVT_RESPONSE", \
[EFC_EVT_ERROR] = "EFC_EVT_ERROR", \
[EFC_EVT_DOMAIN_FOUND] = "EFC_EVT_DOMAIN_FOUND", \
[EFC_EVT_DOMAIN_ALLOC_OK] = "EFC_EVT_DOMAIN_ALLOC_OK", \
[EFC_EVT_DOMAIN_ALLOC_FAIL] = "EFC_EVT_DOMAIN_ALLOC_FAIL", \
[EFC_EVT_DOMAIN_REQ_ATTACH] = "EFC_EVT_DOMAIN_REQ_ATTACH", \
[EFC_EVT_DOMAIN_ATTACH_OK] = "EFC_EVT_DOMAIN_ATTACH_OK", \
[EFC_EVT_DOMAIN_ATTACH_FAIL] = "EFC_EVT_DOMAIN_ATTACH_FAIL", \
[EFC_EVT_DOMAIN_LOST] = "EFC_EVT_DOMAIN_LOST", \
[EFC_EVT_DOMAIN_FREE_OK] = "EFC_EVT_DOMAIN_FREE_OK", \
[EFC_EVT_DOMAIN_FREE_FAIL] = "EFC_EVT_DOMAIN_FREE_FAIL", \
[EFC_EVT_HW_DOMAIN_REQ_ATTACH] = "EFC_EVT_HW_DOMAIN_REQ_ATTACH",\
[EFC_EVT_HW_DOMAIN_REQ_FREE] = "EFC_EVT_HW_DOMAIN_REQ_FREE", \
[EFC_EVT_NPORT_ALLOC_OK] = "EFC_EVT_NPORT_ALLOC_OK", \
[EFC_EVT_NPORT_ALLOC_FAIL] = "EFC_EVT_NPORT_ALLOC_FAIL", \
[EFC_EVT_NPORT_ATTACH_OK] = "EFC_EVT_NPORT_ATTACH_OK", \
[EFC_EVT_NPORT_ATTACH_FAIL] = "EFC_EVT_NPORT_ATTACH_FAIL", \
[EFC_EVT_NPORT_FREE_OK] = "EFC_EVT_NPORT_FREE_OK", \
[EFC_EVT_NPORT_FREE_FAIL] = "EFC_EVT_NPORT_FREE_FAIL", \
[EFC_EVT_NPORT_TOPOLOGY_NOTIFY] = "EFC_EVT_NPORT_TOPOLOGY_NOTIFY",\
[EFC_EVT_HW_PORT_ALLOC_OK] = "EFC_EVT_HW_PORT_ALLOC_OK", \
[EFC_EVT_HW_PORT_ALLOC_FAIL] = "EFC_EVT_HW_PORT_ALLOC_FAIL", \
[EFC_EVT_HW_PORT_ATTACH_OK] = "EFC_EVT_HW_PORT_ATTACH_OK", \
[EFC_EVT_HW_PORT_REQ_ATTACH] = "EFC_EVT_HW_PORT_REQ_ATTACH", \
[EFC_EVT_HW_PORT_REQ_FREE] = "EFC_EVT_HW_PORT_REQ_FREE", \
[EFC_EVT_HW_PORT_FREE_OK] = "EFC_EVT_HW_PORT_FREE_OK", \
[EFC_EVT_SRRS_ELS_REQ_OK] = "EFC_EVT_SRRS_ELS_REQ_OK", \
[EFC_EVT_SRRS_ELS_CMPL_OK] = "EFC_EVT_SRRS_ELS_CMPL_OK", \
[EFC_EVT_SRRS_ELS_REQ_FAIL] = "EFC_EVT_SRRS_ELS_REQ_FAIL", \
[EFC_EVT_SRRS_ELS_CMPL_FAIL] = "EFC_EVT_SRRS_ELS_CMPL_FAIL", \
[EFC_EVT_SRRS_ELS_REQ_RJT] = "EFC_EVT_SRRS_ELS_REQ_RJT", \
[EFC_EVT_NODE_ATTACH_OK] = "EFC_EVT_NODE_ATTACH_OK", \
[EFC_EVT_NODE_ATTACH_FAIL] = "EFC_EVT_NODE_ATTACH_FAIL", \
[EFC_EVT_NODE_FREE_OK] = "EFC_EVT_NODE_FREE_OK", \
[EFC_EVT_NODE_FREE_FAIL] = "EFC_EVT_NODE_FREE_FAIL", \
[EFC_EVT_ELS_FRAME] = "EFC_EVT_ELS_FRAME", \
[EFC_EVT_ELS_REQ_TIMEOUT] = "EFC_EVT_ELS_REQ_TIMEOUT", \
[EFC_EVT_ELS_REQ_ABORTED] = "EFC_EVT_ELS_REQ_ABORTED", \
[EFC_EVT_ABORT_ELS] = "EFC_EVT_ABORT_ELS", \
[EFC_EVT_ELS_ABORT_CMPL] = "EFC_EVT_ELS_ABORT_CMPL", \
[EFC_EVT_ABTS_RCVD] = "EFC_EVT_ABTS_RCVD", \
[EFC_EVT_NODE_MISSING] = "EFC_EVT_NODE_MISSING", \
[EFC_EVT_NODE_REFOUND] = "EFC_EVT_NODE_REFOUND", \
[EFC_EVT_SHUTDOWN_IMPLICIT_LOGO] = "EFC_EVT_SHUTDOWN_IMPLICIT_LOGO",\
[EFC_EVT_SHUTDOWN_EXPLICIT_LOGO] = "EFC_EVT_SHUTDOWN_EXPLICIT_LOGO",\
[EFC_EVT_PLOGI_RCVD] = "EFC_EVT_PLOGI_RCVD", \
[EFC_EVT_FLOGI_RCVD] = "EFC_EVT_FLOGI_RCVD", \
[EFC_EVT_LOGO_RCVD] = "EFC_EVT_LOGO_RCVD", \
[EFC_EVT_PRLI_RCVD] = "EFC_EVT_PRLI_RCVD", \
[EFC_EVT_PRLO_RCVD] = "EFC_EVT_PRLO_RCVD", \
[EFC_EVT_PDISC_RCVD] = "EFC_EVT_PDISC_RCVD", \
[EFC_EVT_FDISC_RCVD] = "EFC_EVT_FDISC_RCVD", \
[EFC_EVT_ADISC_RCVD] = "EFC_EVT_ADISC_RCVD", \
[EFC_EVT_RSCN_RCVD] = "EFC_EVT_RSCN_RCVD", \
[EFC_EVT_SCR_RCVD] = "EFC_EVT_SCR_RCVD", \
[EFC_EVT_ELS_RCVD] = "EFC_EVT_ELS_RCVD", \
[EFC_EVT_FCP_CMD_RCVD] = "EFC_EVT_FCP_CMD_RCVD", \
[EFC_EVT_NODE_DEL_INI_COMPLETE] = "EFC_EVT_NODE_DEL_INI_COMPLETE",\
[EFC_EVT_NODE_DEL_TGT_COMPLETE] = "EFC_EVT_NODE_DEL_TGT_COMPLETE",\
[EFC_EVT_LAST] = "EFC_EVT_LAST", \
}
int
efc_sm_post_event(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *data);
void
efc_sm_transition(struct efc_sm_ctx *ctx,
void (*state)(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg),
void *data);
void efc_sm_disable(struct efc_sm_ctx *ctx);
const char *efc_sm_event_name(enum efc_sm_event evt);
#endif /* ! _EFC_SM_H */
@@ -0,0 +1,81 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021 Broadcom. All Rights Reserved. The term
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*/
/*
* LIBEFC LOCKING
*
* The critical sections protected by the efc's spinlock are quite broad and
* may be improved upon in the future. The libefc code and its locking doesn't
* influence the I/O path, so excessive locking doesn't impact I/O performance.
*
* The strategy is to lock whenever processing a request from user driver. This
* means that the entry points into the libefc library are protected by efc
* lock. So all the state machine transitions are protected.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include "efc.h"
int efcport_init(struct efc *efc)
{
u32 rc = 0;
spin_lock_init(&efc->lock);
INIT_LIST_HEAD(&efc->vport_list);
efc->hold_frames = false;
spin_lock_init(&efc->pend_frames_lock);
INIT_LIST_HEAD(&efc->pend_frames);
/* Create Node pool */
efc->node_pool = mempool_create_kmalloc_pool(EFC_MAX_REMOTE_NODES,
sizeof(struct efc_node));
if (!efc->node_pool) {
efc_log_err(efc, "Can't allocate node pool\n");
return -ENOMEM;
}
efc->node_dma_pool = dma_pool_create("node_dma_pool", &efc->pci->dev,
NODE_SPARAMS_SIZE, 0, 0);
if (!efc->node_dma_pool) {
efc_log_err(efc, "Can't allocate node dma pool\n");
mempool_destroy(efc->node_pool);
return -ENOMEM;
}
efc->els_io_pool = mempool_create_kmalloc_pool(EFC_ELS_IO_POOL_SZ,
sizeof(struct efc_els_io_req));
if (!efc->els_io_pool) {
efc_log_err(efc, "Can't allocate els io pool\n");
return -ENOMEM;
}
return rc;
}
static void
efc_purge_pending(struct efc *efc)
{
struct efc_hw_sequence *frame, *next;
unsigned long flags = 0;
spin_lock_irqsave(&efc->pend_frames_lock, flags);
list_for_each_entry_safe(frame, next, &efc->pend_frames, list_entry) {
list_del(&frame->list_entry);
efc->tt.hw_seq_free(efc, frame);
}
spin_unlock_irqrestore(&efc->pend_frames_lock, flags);
}
void efcport_destroy(struct efc *efc)
{
efc_purge_pending(efc);
mempool_destroy(efc->els_io_pool);
mempool_destroy(efc->node_pool);
dma_pool_destroy(efc->node_dma_pool);
}
@@ -0,0 +1,623 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2021 Broadcom. All Rights Reserved. The term
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*/
#ifndef __EFCLIB_H__
#define __EFCLIB_H__
#include "scsi/fc/fc_els.h"
#include "scsi/fc/fc_fs.h"
#include "scsi/fc/fc_ns.h"
#include "scsi/fc/fc_gs.h"
#include "scsi/fc_frame.h"
#include "../include/efc_common.h"
#include "../libefc_sli/sli4.h"
#define EFC_SERVICE_PARMS_LENGTH 120
#define EFC_NAME_LENGTH 32
#define EFC_SM_NAME_LENGTH 64
#define EFC_DISPLAY_BUS_INFO_LENGTH 16
#define EFC_WWN_LENGTH 32
#define EFC_FC_ELS_DEFAULT_RETRIES 3
/* Timeouts */
#define EFC_FC_ELS_SEND_DEFAULT_TIMEOUT 0
#define EFC_FC_FLOGI_TIMEOUT_SEC 5
#define EFC_SHUTDOWN_TIMEOUT_USEC 30000000
/* Return values for calls from base driver to libefc */
#define EFC_SCSI_CALL_COMPLETE 0
#define EFC_SCSI_CALL_ASYNC 1
/* Local port topology */
enum efc_nport_topology {
EFC_NPORT_TOPO_UNKNOWN = 0,
EFC_NPORT_TOPO_FABRIC,
EFC_NPORT_TOPO_P2P,
EFC_NPORT_TOPO_FC_AL,
};
#define enable_target_rscn(efc) 1
enum efc_node_shutd_rsn {
EFC_NODE_SHUTDOWN_DEFAULT = 0,
EFC_NODE_SHUTDOWN_EXPLICIT_LOGO,
EFC_NODE_SHUTDOWN_IMPLICIT_LOGO,
};
enum efc_node_send_ls_acc {
EFC_NODE_SEND_LS_ACC_NONE = 0,
EFC_NODE_SEND_LS_ACC_PLOGI,
EFC_NODE_SEND_LS_ACC_PRLI,
};
#define EFC_LINK_STATUS_UP 0
#define EFC_LINK_STATUS_DOWN 1
enum efc_sm_event;
/* State machine context header */
struct efc_sm_ctx {
void (*current_state)(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
const char *description;
void *app;
};
/* Description of discovered Fabric Domain */
struct efc_domain_record {
u32 index;
u32 priority;
u8 address[6];
u8 wwn[8];
union {
u8 vlan[512];
u8 loop[128];
} map;
u32 speed;
u32 fc_id;
bool is_loop;
bool is_nport;
};
/* Domain events */
enum efc_hw_domain_event {
EFC_HW_DOMAIN_ALLOC_OK,
EFC_HW_DOMAIN_ALLOC_FAIL,
EFC_HW_DOMAIN_ATTACH_OK,
EFC_HW_DOMAIN_ATTACH_FAIL,
EFC_HW_DOMAIN_FREE_OK,
EFC_HW_DOMAIN_FREE_FAIL,
EFC_HW_DOMAIN_LOST,
EFC_HW_DOMAIN_FOUND,
EFC_HW_DOMAIN_CHANGED,
};
/**
* Fibre Channel port object
*
* @list_entry: nport list entry
* @ref: reference count, each node takes a reference
* @release: function to free nport object
* @efc: pointer back to efc
* @instance_index: unique instance index value
* @display_name: port display name
* @is_vport: Is NPIV port
* @free_req_pending: pending request to free resources
* @attached: mark attached if reg VPI succeeds
* @p2p_winner: TRUE if we're the point-to-point winner
* @domain: pointer back to domain
* @wwpn: port wwpn
* @wwnn: port wwnn
* @tgt_data: target backend private port data
* @ini_data: initiator backend private port data
* @indicator: VPI
* @fc_id: port FC address
* @dma: memory for Service Parameters
* @wwnn_str: wwpn string
* @sli_wwpn: SLI provided wwpn
* @sli_wwnn: SLI provided wwnn
* @sm: nport state machine context
* @lookup: fc_id to node lookup object
* @enable_ini: SCSI initiator enabled for this port
* @enable_tgt: SCSI target enabled for this port
* @enable_rscn: port will be expecting RSCN
* @shutting_down: nport in process of shutting down
* @p2p_port_id: our port id for point-to-point
* @topology: topology: fabric/p2p/unknown
* @service_params: login parameters
* @p2p_remote_port_id: remote node's port id for point-to-point
*/
struct efc_nport {
struct list_head list_entry;
struct kref ref;
void (*release)(struct kref *arg);
struct efc *efc;
u32 instance_index;
char display_name[EFC_NAME_LENGTH];
bool is_vport;
bool free_req_pending;
bool attached;
bool attaching;
bool p2p_winner;
struct efc_domain *domain;
u64 wwpn;
u64 wwnn;
void *tgt_data;
void *ini_data;
u32 indicator;
u32 fc_id;
struct efc_dma dma;
u8 wwnn_str[EFC_WWN_LENGTH];
__be64 sli_wwpn;
__be64 sli_wwnn;
struct efc_sm_ctx sm;
struct xarray lookup;
bool enable_ini;
bool enable_tgt;
bool enable_rscn;
bool shutting_down;
u32 p2p_port_id;
enum efc_nport_topology topology;
u8 service_params[EFC_SERVICE_PARMS_LENGTH];
u32 p2p_remote_port_id;
};
/**
* Fibre Channel domain object
*
* This object is a container for the various SLI components needed
* to connect to the domain of a FC or FCoE switch
* @efc: pointer back to efc
* @instance_index: unique instance index value
* @display_name: Node display name
* @nport_list: linked list of nports associated with this domain
* @ref: Reference count, each nport takes a reference
* @release: Function to free domain object
* @ini_domain: initiator backend private domain data
* @tgt_domain: target backend private domain data
* @sm: state machine context
* @fcf: FC Forwarder table index
* @fcf_indicator: FCFI
* @indicator: VFI
* @nport_count: Number of nports allocated
* @dma: memory for Service Parameters
* @fcf_wwn: WWN for FCF/switch
* @drvsm: driver domain sm context
* @attached: set true after attach completes
* @is_fc: is FC
* @is_loop: is loop topology
* @is_nlport: is public loop
* @domain_found_pending:A domain found is pending, drec is updated
* @req_domain_free: True if domain object should be free'd
* @req_accept_frames: set in domain state machine to enable frames
* @domain_notify_pend: Set in domain SM to avoid duplicate node event post
* @pending_drec: Pending drec if a domain found is pending
* @service_params: any nports service parameters
* @flogi_service_params:Fabric/P2p service parameters from FLOGI
* @lookup: d_id to node lookup object
* @nport: Pointer to first (physical) SLI port
*/
struct efc_domain {
struct efc *efc;
char display_name[EFC_NAME_LENGTH];
struct list_head nport_list;
struct kref ref;
void (*release)(struct kref *arg);
void *ini_domain;
void *tgt_domain;
/* Declarations private to HW/SLI */
u32 fcf;
u32 fcf_indicator;
u32 indicator;
u32 nport_count;
struct efc_dma dma;
/* Declarations private to FC trannport */
u64 fcf_wwn;
struct efc_sm_ctx drvsm;
bool attached;
bool is_fc;
bool is_loop;
bool is_nlport;
bool domain_found_pending;
bool req_domain_free;
bool req_accept_frames;
bool domain_notify_pend;
struct efc_domain_record pending_drec;
u8 service_params[EFC_SERVICE_PARMS_LENGTH];
u8 flogi_service_params[EFC_SERVICE_PARMS_LENGTH];
struct xarray lookup;
struct efc_nport *nport;
};
/**
* Remote Node object
*
* This object represents a connection between the SLI port and another
* Nx_Port on the fabric. Note this can be either a well known port such
* as a F_Port (i.e. ff:ff:fe) or another N_Port.
* @indicator: RPI
* @fc_id: FC address
* @attached: true if attached
* @nport: associated SLI port
* @node: associated node
*/
struct efc_remote_node {
u32 indicator;
u32 index;
u32 fc_id;
bool attached;
struct efc_nport *nport;
void *node;
};
/**
* FC Node object
* @efc: pointer back to efc structure
* @display_name: Node display name
* @nort: Assosiated nport pointer.
* @hold_frames: hold incoming frames if true
* @els_io_enabled: Enable allocating els ios for this node
* @els_ios_lock: lock to protect the els ios list
* @els_ios_list: ELS I/O's for this node
* @ini_node: backend initiator private node data
* @tgt_node: backend target private node data
* @rnode: Remote node
* @sm: state machine context
* @evtdepth: current event posting nesting depth
* @req_free: this node is to be free'd
* @attached: node is attached (REGLOGIN complete)
* @fcp_enabled: node is enabled to handle FCP
* @rscn_pending: for name server node RSCN is pending
* @send_plogi: send PLOGI accept, upon completion of node attach
* @send_plogi_acc: TRUE if io_alloc() is enabled.
* @send_ls_acc: type of LS acc to send
* @ls_acc_io: SCSI IO for LS acc
* @ls_acc_oxid: OX_ID for pending accept
* @ls_acc_did: D_ID for pending accept
* @shutdown_reason: reason for node shutdown
* @sparm_dma_buf: service parameters buffer
* @service_params: plogi/acc frame from remote device
* @pend_frames_lock: lock for inbound pending frames list
* @pend_frames: inbound pending frames list
* @pend_frames_processed:count of frames processed in hold frames interval
* @ox_id_in_use: used to verify one at a time us of ox_id
* @els_retries_remaining:for ELS, number of retries remaining
* @els_req_cnt: number of outstanding ELS requests
* @els_cmpl_cnt: number of outstanding ELS completions
* @abort_cnt: Abort counter for debugging purpos
* @current_state_name: current node state
* @prev_state_name: previous node state
* @current_evt: current event
* @prev_evt: previous event
* @targ: node is target capable
* @init: node is init capable
* @refound: Handle node refound case when node is being deleted
* @els_io_pend_list: list of pending (not yet processed) ELS IOs
* @els_io_active_list: list of active (processed) ELS IOs
* @nodedb_state: Node debugging, saved state
* @gidpt_delay_timer: GIDPT delay timer
* @time_last_gidpt_msec:Start time of last target RSCN GIDPT
* @wwnn: remote port WWNN
* @wwpn: remote port WWPN
*/
struct efc_node {
struct efc *efc;
char display_name[EFC_NAME_LENGTH];
struct efc_nport *nport;
struct kref ref;
void (*release)(struct kref *arg);
bool hold_frames;
bool els_io_enabled;
bool send_plogi_acc;
bool send_plogi;
bool rscn_pending;
bool fcp_enabled;
bool attached;
bool req_free;
spinlock_t els_ios_lock;
struct list_head els_ios_list;
void *ini_node;
void *tgt_node;
struct efc_remote_node rnode;
/* Declarations private to FC trannport */
struct efc_sm_ctx sm;
u32 evtdepth;
enum efc_node_send_ls_acc send_ls_acc;
void *ls_acc_io;
u32 ls_acc_oxid;
u32 ls_acc_did;
enum efc_node_shutd_rsn shutdown_reason;
bool targ;
bool init;
bool refound;
struct efc_dma sparm_dma_buf;
u8 service_params[EFC_SERVICE_PARMS_LENGTH];
spinlock_t pend_frames_lock;
struct list_head pend_frames;
u32 pend_frames_processed;
u32 ox_id_in_use;
u32 els_retries_remaining;
u32 els_req_cnt;
u32 els_cmpl_cnt;
u32 abort_cnt;
char current_state_name[EFC_SM_NAME_LENGTH];
char prev_state_name[EFC_SM_NAME_LENGTH];
int current_evt;
int prev_evt;
void (*nodedb_state)(struct efc_sm_ctx *ctx,
enum efc_sm_event evt, void *arg);
struct timer_list gidpt_delay_timer;
u64 time_last_gidpt_msec;
char wwnn[EFC_WWN_LENGTH];
char wwpn[EFC_WWN_LENGTH];
};
/**
* NPIV port
*
* Collection of the information required to restore a virtual port across
* link events
* @wwnn: node name
* @wwpn: port name
* @fc_id: port id
* @tgt_data: target backend pointer
* @ini_data: initiator backend pointe
* @nport: Used to match record after attaching for update
*
*/
struct efc_vport {
struct list_head list_entry;
u64 wwnn;
u64 wwpn;
u32 fc_id;
bool enable_tgt;
bool enable_ini;
void *tgt_data;
void *ini_data;
struct efc_nport *nport;
};
#define node_printf(node, fmt, args...) \
efc_log_info(node->efc, "[%s] " fmt, node->display_name, ##args)
/* Node SM IO Context Callback structure */
struct efc_node_cb {
int status;
int ext_status;
struct efc_hw_rq_buffer *header;
struct efc_hw_rq_buffer *payload;
struct efc_dma els_rsp;
/* Actual length of data received */
int rsp_len;
};
struct efc_hw_rq_buffer {
u16 rqindex;
struct efc_dma dma;
};
/**
* FC sequence object
*
* Defines a general FC sequence object
* @hw: HW that owns this sequence
* @fcfi: FCFI associated with sequence
* @header: Received frame header
* @payload: Received frame header
* @hw_priv: HW private context
*/
struct efc_hw_sequence {
struct list_head list_entry;
void *hw;
u8 fcfi;
struct efc_hw_rq_buffer *header;
struct efc_hw_rq_buffer *payload;
void *hw_priv;
};
enum efc_disc_io_type {
EFC_DISC_IO_ELS_REQ,
EFC_DISC_IO_ELS_RESP,
EFC_DISC_IO_CT_REQ,
EFC_DISC_IO_CT_RESP
};
struct efc_io_els_params {
u32 s_id;
u16 ox_id;
u8 timeout;
};
struct efc_io_ct_params {
u8 r_ctl;
u8 type;
u8 df_ctl;
u8 timeout;
u16 ox_id;
};
union efc_disc_io_param {
struct efc_io_els_params els;
struct efc_io_ct_params ct;
};
struct efc_disc_io {
struct efc_dma req; /* send buffer */
struct efc_dma rsp; /* receive buffer */
enum efc_disc_io_type io_type; /* EFC_DISC_IO_TYPE enum*/
u16 xmit_len; /* Length of els request*/
u16 rsp_len; /* Max length of rsps to be rcvd */
u32 rpi; /* Registered RPI */
u32 vpi; /* VPI for this nport */
u32 s_id;
u32 d_id;
bool rpi_registered; /* if false, use tmp RPI */
union efc_disc_io_param iparam;
};
/* Return value indiacating the sequence can not be freed */
#define EFC_HW_SEQ_HOLD 0
/* Return value indiacating the sequence can be freed */
#define EFC_HW_SEQ_FREE 1
struct libefc_function_template {
/*Sport*/
int (*new_nport)(struct efc *efc, struct efc_nport *sp);
void (*del_nport)(struct efc *efc, struct efc_nport *sp);
/*Scsi Node*/
int (*scsi_new_node)(struct efc *efc, struct efc_node *n);
int (*scsi_del_node)(struct efc *efc, struct efc_node *n, int reason);
int (*issue_mbox_rqst)(void *efct, void *buf, void *cb, void *arg);
/*Send ELS IO*/
int (*send_els)(struct efc *efc, struct efc_disc_io *io);
/*Send BLS IO*/
int (*send_bls)(struct efc *efc, u32 type, struct sli_bls_params *bls);
/*Free HW frame*/
int (*hw_seq_free)(struct efc *efc, struct efc_hw_sequence *seq);
};
#define EFC_LOG_LIB 0x01
#define EFC_LOG_NODE 0x02
#define EFC_LOG_PORT 0x04
#define EFC_LOG_DOMAIN 0x08
#define EFC_LOG_ELS 0x10
#define EFC_LOG_DOMAIN_SM 0x20
#define EFC_LOG_SM 0x40
/* efc library port structure */
struct efc {
void *base;
struct pci_dev *pci;
struct sli4 *sli;
u32 fcfi;
u64 req_wwpn;
u64 req_wwnn;
u64 def_wwpn;
u64 def_wwnn;
u64 max_xfer_size;
mempool_t *node_pool;
struct dma_pool *node_dma_pool;
u32 nodes_count;
u32 link_status;
struct list_head vport_list;
/* lock to protect the vport list */
spinlock_t vport_lock;
struct libefc_function_template tt;
/* lock to protect the discovery library.
* Refer to efclib.c for more details.
*/
spinlock_t lock;
bool enable_ini;
bool enable_tgt;
u32 log_level;
struct efc_domain *domain;
void (*domain_free_cb)(struct efc *efc, void *arg);
void *domain_free_cb_arg;
u64 tgt_rscn_delay_msec;
u64 tgt_rscn_period_msec;
bool external_loopback;
u32 nodedb_mask;
u32 logmask;
mempool_t *els_io_pool;
atomic_t els_io_alloc_failed_count;
/* hold pending frames */
bool hold_frames;
/* lock to protect pending frames list access */
spinlock_t pend_frames_lock;
struct list_head pend_frames;
/* count of pending frames that were processed */
u32 pend_frames_processed;
};
/*
* EFC library registration
* **********************************/
int efcport_init(struct efc *efc);
void efcport_destroy(struct efc *efc);
/*
* EFC Domain
* **********************************/
int efc_domain_cb(void *arg, int event, void *data);
void
efc_register_domain_free_cb(struct efc *efc,
void (*callback)(struct efc *efc, void *arg),
void *arg);
/*
* EFC nport
* **********************************/
void efc_nport_cb(void *arg, int event, void *data);
struct efc_vport *
efc_vport_create_spec(struct efc *efc, u64 wwnn, u64 wwpn, u32 fc_id,
bool enable_ini, bool enable_tgt,
void *tgt_data, void *ini_data);
int efc_nport_vport_new(struct efc_domain *domain, u64 wwpn,
u64 wwnn, u32 fc_id, bool ini, bool tgt,
void *tgt_data, void *ini_data);
int efc_nport_vport_del(struct efc *efc, struct efc_domain *domain,
u64 wwpn, u64 wwnn);
void efc_vport_del_all(struct efc *efc);
/*
* EFC Node
* **********************************/
int efc_remote_node_cb(void *arg, int event, void *data);
void efc_node_fcid_display(u32 fc_id, char *buffer, u32 buf_len);
void efc_node_post_shutdown(struct efc_node *node, void *arg);
u64 efc_node_get_wwpn(struct efc_node *node);
/*
* EFC FCP/ELS/CT interface
* **********************************/
void efc_dispatch_frame(struct efc *efc, struct efc_hw_sequence *seq);
void efc_disc_io_complete(struct efc_disc_io *io, u32 len, u32 status,
u32 ext_status);
/*
* EFC SCSI INTERACTION LAYER
* **********************************/
void efc_scsi_sess_reg_complete(struct efc_node *node, u32 status);
void efc_scsi_del_initiator_complete(struct efc *efc, struct efc_node *node);
void efc_scsi_del_target_complete(struct efc *efc, struct efc_node *node);
void efc_scsi_io_list_empty(struct efc *efc, struct efc_node *node);
#endif /* __EFCLIB_H__ */