All of lore.kernel.org
 help / color / mirror / Atom feed
From: Daniel Wagner <dwagner@suse.de>
To: James Smart <jsmart2021@gmail.com>
Cc: linux-scsi@vger.kernel.org, maier@linux.ibm.com,
	bvanassche@acm.org, herbszt@gmx.de, natechancellor@gmail.com,
	rdunlap@infradead.org, hare@suse.de,
	Ram Vegesna <ram.vegesna@broadcom.com>
Subject: Re: [PATCH v3 13/31] elx: libefc: Fabric node state machine interfaces
Date: Wed, 15 Apr 2020 20:51:42 +0200	[thread overview]
Message-ID: <20200415185142.j5yo66gsmyse6m72@carbon> (raw)
In-Reply-To: <20200412033303.29574-14-jsmart2021@gmail.com>

On Sat, Apr 11, 2020 at 08:32:45PM -0700, James Smart wrote:
> This patch continues the libefc library population.
> 
> This patch adds library interface definitions for:
> - Fabric node initialization and logins.
> - Name/Directory Services node.
> - Fabric Controller node to process rscn events.
> 
> These are all interactions with remote ports that correspond
> to well-known fabric entities
> 
> Signed-off-by: Ram Vegesna <ram.vegesna@broadcom.com>
> Signed-off-by: James Smart <jsmart2021@gmail.com>
> 
> ---
> v3:
>   Replace efc_assert with WARN_ON
>   Return defined return values
> ---
>  drivers/scsi/elx/libefc/efc_fabric.c | 1759 ++++++++++++++++++++++++++++++++++
>  drivers/scsi/elx/libefc/efc_fabric.h |  116 +++
>  2 files changed, 1875 insertions(+)
>  create mode 100644 drivers/scsi/elx/libefc/efc_fabric.c
>  create mode 100644 drivers/scsi/elx/libefc/efc_fabric.h
> 
> diff --git a/drivers/scsi/elx/libefc/efc_fabric.c b/drivers/scsi/elx/libefc/efc_fabric.c
> new file mode 100644
> index 000000000000..251f8702dbc5
> --- /dev/null
> +++ b/drivers/scsi/elx/libefc/efc_fabric.c
> @@ -0,0 +1,1759 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2019 Broadcom. All Rights Reserved. The term
> + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
> + */
> +
> +/*
> + * This file implements remote node state machines for:
> + * - Fabric logins.
> + * - Fabric controller events.
> + * - Name/directory services interaction.
> + * - Point-to-point logins.
> + */
> +
> +/*
> + * fabric_sm Node State Machine: Fabric States
> + * ns_sm Node State Machine: Name/Directory Services States
> + * p2p_sm Node State Machine: Point-to-Point Node States
> + */
> +
> +#include "efc.h"
> +
> +static void
> +efc_fabric_initiate_shutdown(struct efc_node *node)
> +{
> +	int rc;
> +	struct efc *efc = node->efc;
> +
> +	efc->tt.scsi_io_alloc_disable(efc, node);
> +
> +	if (node->attached) {
> +		/* issue hw node free; don't care if succeeds right away
> +		 * or sometime later, will check node->attached later in
> +		 * shutdown process
> +		 */
> +		rc = efc->tt.hw_node_detach(efc, &node->rnode);
> +		if (rc != EFC_HW_RTN_SUCCESS &&
> +		    rc != EFC_HW_RTN_SUCCESS_SYNC) {
> +			node_printf(node, "Failed freeing HW node, rc=%d\n",
> +				    rc);
> +		}
> +	}
> +	/*
> +	 * node has either been detached or is in the process of being detached,
> +	 * call common node's initiate cleanup function
> +	 */
> +	efc_node_initiate_cleanup(node);
> +}
> +
> +static void *
> +__efc_fabric_common(const char *funcname, struct efc_sm_ctx *ctx,
> +		    enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node *node = NULL;
> +
> +	node = ctx->app;
> +
> +	switch (evt) {
> +	case EFC_EVT_DOMAIN_ATTACH_OK:
> +		break;
> +	case EFC_EVT_SHUTDOWN:
> +		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
> +		efc_fabric_initiate_shutdown(node);
> +		break;
> +
> +	default:
> +		/* call default event handler common to all nodes */
> +		__efc_node_common(funcname, ctx, evt, arg);
> +		break;
> +	}
> +	return NULL;
> +}
> +
> +void *
> +__efc_fabric_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
> +		  void *arg)
> +{
> +	struct efc_node *node = ctx->app;
> +	struct efc *efc = node->efc;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_REENTER:	/* not sure why we're getting these ... */
> +		efc_log_debug(efc, ">>> reenter !!\n");
> +		/* fall through */

IIRC, /* fall through */ has been replaced by fallthrough;

> +	case EFC_EVT_ENTER:
> +		/*  sm: / send FLOGI */
> +		efc->tt.els_send(efc, node, ELS_FLOGI,
> +				EFC_FC_FLOGI_TIMEOUT_SEC,
> +				EFC_FC_ELS_DEFAULT_RETRIES);
> +		efc_node_transition(node, __efc_fabric_flogi_wait_rsp, NULL);
> +		break;
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		break;
> +	}
> +
> +	return NULL;
> +}
> +
> +void
> +efc_fabric_set_topology(struct efc_node *node,
> +			enum efc_sport_topology topology)
> +{
> +	node->sport->topology = topology;
> +}
> +
> +void
> +efc_fabric_notify_topology(struct efc_node *node)
> +{
> +	struct efc_node *tmp_node;
> +	struct efc_node *next;
> +	enum efc_sport_topology topology = node->sport->topology;
> +
> +	/*
> +	 * now loop through the nodes in the sport
> +	 * and send topology notification
> +	 */
> +	list_for_each_entry_safe(tmp_node, next, &node->sport->node_list,
> +				 list_entry) {
> +		if (tmp_node != node) {
> +			efc_node_post_event(tmp_node,
> +					    EFC_EVT_SPORT_TOPOLOGY_NOTIFY,
> +					    (void *)topology);
> +		}
> +	}
> +}
> +
> +static bool efc_rnode_is_nport(struct fc_els_flogi *rsp)
> +{
> +	return !(ntohs(rsp->fl_csp.sp_features) & FC_SP_FT_FPORT);
> +}
> +
> +static bool efc_rnode_is_npiv_capable(struct fc_els_flogi *rsp)
> +{
> +	return !!(ntohs(rsp->fl_csp.sp_features) & FC_SP_FT_NPIV_ACC);
> +}
> +
> +void *
> +__efc_fabric_flogi_wait_rsp(struct efc_sm_ctx *ctx,
> +			    enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node_cb *cbdata = arg;
> +	struct efc_node *node = ctx->app;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_SRRS_ELS_REQ_OK: {
> +		if (efc_node_check_els_req(ctx, evt, arg, ELS_FLOGI,
> +					   __efc_fabric_common, __func__)) {
> +			return NULL;
> +		}
> +		WARN_ON(!node->els_req_cnt);
> +		node->els_req_cnt--;
> +
> +		memcpy(node->sport->domain->flogi_service_params,
> +		       cbdata->els_rsp.virt,
> +		       sizeof(struct fc_els_flogi));
> +
> +		/* Check to see if the fabric is an F_PORT or and N_PORT */
> +		if (!efc_rnode_is_nport(cbdata->els_rsp.virt)) {
> +			/* sm: if not nport / efc_domain_attach */
> +			/* ext_status has the fc_id, attach domain */
> +			if (efc_rnode_is_npiv_capable(cbdata->els_rsp.virt)) {
> +				efc_log_debug(node->efc,
> +					      " NPIV is enabled at switch side\n");
> +				//node->efc->sw_feature_cap |= 1<<10;

Looks like a left over.

> +			}
> +			efc_fabric_set_topology(node,
> +						EFC_SPORT_TOPOLOGY_FABRIC);
> +			efc_fabric_notify_topology(node);
> +			WARN_ON(node->sport->domain->attached);
> +			efc_domain_attach(node->sport->domain,
> +					  cbdata->ext_status);
> +			efc_node_transition(node,
> +					    __efc_fabric_wait_domain_attach,
> +					    NULL);
> +			break;
> +		}
> +
> +		/*  sm: if nport and p2p_winner / efc_domain_attach */
> +		efc_fabric_set_topology(node, EFC_SPORT_TOPOLOGY_P2P);
> +		if (efc_p2p_setup(node->sport)) {
> +			node_printf(node,
> +				    "p2p setup failed, shutting down node\n");
> +			node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
> +			efc_fabric_initiate_shutdown(node);
> +			break;
> +		}
> +
> +		if (node->sport->p2p_winner) {
> +			efc_node_transition(node,
> +					    __efc_p2p_wait_domain_attach,
> +					     NULL);
> +			if (node->sport->domain->attached &&
> +			    !node->sport->domain->domain_notify_pend) {
> +				/*
> +				 * already attached,
> +				 * just send ATTACH_OK
> +				 */
> +				node_printf(node,
> +					    "p2p winner, domain already attached\n");
> +				efc_node_post_event(node,
> +						    EFC_EVT_DOMAIN_ATTACH_OK,
> +						    NULL);
> +			}
> +		} else {
> +			/*
> +			 * peer is p2p winner;
> +			 * PLOGI will be received on the
> +			 * remote SID=1 node;
> +			 * this node has served its purpose
> +			 */
> +			node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
> +			efc_fabric_initiate_shutdown(node);
> +		}
> +
> +		break;
> +	}
> +
> +	case EFC_EVT_ELS_REQ_ABORTED:
> +	case EFC_EVT_SRRS_ELS_REQ_RJT:
> +	case EFC_EVT_SRRS_ELS_REQ_FAIL: {
> +		struct efc_sli_port *sport = node->sport;
> +		/*
> +		 * with these errors, we have no recovery,
> +		 * so shutdown the sport, leave the link
> +		 * up and the domain ready
> +		 */
> +		if (efc_node_check_els_req(ctx, evt, arg, ELS_FLOGI,
> +					   __efc_fabric_common, __func__)) {
> +			return NULL;
> +		}
> +		node_printf(node,
> +			    "FLOGI failed evt=%s, shutting down sport [%s]\n",
> +			    efc_sm_event_name(evt), sport->display_name);
> +		WARN_ON(!node->els_req_cnt);
> +		node->els_req_cnt--;
> +		efc_sm_post_event(&sport->sm, EFC_EVT_SHUTDOWN, NULL);
> +		break;
> +	}
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		break;
> +	}
> +
> +	return NULL;
> +}
> +
> +void *
> +__efc_vport_fabric_init(struct efc_sm_ctx *ctx,
> +			enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node *node = ctx->app;
> +	struct efc *efc = node->efc;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_ENTER:
> +		/* sm: / send FDISC */
> +		efc->tt.els_send(efc, node, ELS_FDISC,
> +				EFC_FC_FLOGI_TIMEOUT_SEC,
> +				EFC_FC_ELS_DEFAULT_RETRIES);
> +
> +		efc_node_transition(node, __efc_fabric_fdisc_wait_rsp, NULL);
> +		break;
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		break;
> +	}
> +
> +	return NULL;
> +}
> +
> +void *
> +__efc_fabric_fdisc_wait_rsp(struct efc_sm_ctx *ctx,
> +			    enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node_cb *cbdata = arg;
> +	struct efc_node *node = ctx->app;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_SRRS_ELS_REQ_OK: {
> +		/* fc_id is in ext_status */
> +		if (efc_node_check_els_req(ctx, evt, arg, ELS_FDISC,
> +					   __efc_fabric_common, __func__)) {
> +			return NULL;
> +		}
> +
> +		WARN_ON(!node->els_req_cnt);
> +		node->els_req_cnt--;
> +		/* sm: / efc_sport_attach */
> +		efc_sport_attach(node->sport, cbdata->ext_status);
> +		efc_node_transition(node, __efc_fabric_wait_domain_attach,
> +				    NULL);
> +		break;
> +	}
> +
> +	case EFC_EVT_SRRS_ELS_REQ_RJT:
> +	case EFC_EVT_SRRS_ELS_REQ_FAIL: {
> +		if (efc_node_check_els_req(ctx, evt, arg, ELS_FDISC,
> +					   __efc_fabric_common, __func__)) {
> +			return NULL;
> +		}
> +		WARN_ON(!node->els_req_cnt);
> +		node->els_req_cnt--;
> +		efc_log_err(node->efc, "FDISC failed, shutting down sport\n");
> +		/* sm: / shutdown sport */
> +		efc_sm_post_event(&node->sport->sm, EFC_EVT_SHUTDOWN, NULL);
> +		break;
> +	}
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		break;
> +	}
> +
> +	return NULL;
> +}
> +
> +static int
> +efc_start_ns_node(struct efc_sli_port *sport)
> +{
> +	struct efc_node *ns;
> +
> +	/* Instantiate a name services node */
> +	ns = efc_node_find(sport, FC_FID_DIR_SERV);
> +	if (!ns) {
> +		ns = efc_node_alloc(sport, FC_FID_DIR_SERV, false, false);
> +		if (!ns)
> +			return EFC_FAIL;
> +	}
> +	/*
> +	 * for found ns, should we be transitioning from here?
> +	 * breaks transition only
> +	 *  1. from within state machine or
> +	 *  2. if after alloc
> +	 */
> +	if (ns->efc->nodedb_mask & EFC_NODEDB_PAUSE_NAMESERVER)
> +		efc_node_pause(ns, __efc_ns_init);
> +	else
> +		efc_node_transition(ns, __efc_ns_init, NULL);
> +	return EFC_SUCCESS;
> +}
> +
> +static int
> +efc_start_fabctl_node(struct efc_sli_port *sport)
> +{
> +	struct efc_node *fabctl;
> +
> +	fabctl = efc_node_find(sport, FC_FID_FCTRL);
> +	if (!fabctl) {
> +		fabctl = efc_node_alloc(sport, FC_FID_FCTRL,
> +					false, false);
> +		if (!fabctl)
> +			return EFC_FAIL;
> +	}
> +	/*
> +	 * for found ns, should we be transitioning from here?
> +	 * breaks transition only
> +	 *  1. from within state machine or
> +	 *  2. if after alloc
> +	 */
> +	efc_node_transition(fabctl, __efc_fabctl_init, NULL);
> +	return EFC_SUCCESS;
> +}
> +
> +void *
> +__efc_fabric_wait_domain_attach(struct efc_sm_ctx *ctx,
> +				enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node *node = ctx->app;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_ENTER:
> +		efc_node_hold_frames(node);
> +		break;
> +
> +	case EFC_EVT_EXIT:
> +		efc_node_accept_frames(node);
> +		break;
> +	case EFC_EVT_DOMAIN_ATTACH_OK:
> +	case EFC_EVT_SPORT_ATTACH_OK: {
> +		int rc;
> +
> +		rc = efc_start_ns_node(node->sport);
> +		if (rc)
> +			return NULL;
> +
> +		/* sm: if enable_ini / start fabctl node */
> +		/* Instantiate the fabric controller (sends SCR) */
> +		if (node->sport->enable_rscn) {
> +			rc = efc_start_fabctl_node(node->sport);
> +			if (rc)
> +				return NULL;
> +		}
> +		efc_node_transition(node, __efc_fabric_idle, NULL);
> +		break;
> +	}
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +void *
> +__efc_fabric_idle(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
> +		  void *arg)
> +{
> +	struct efc_node *node = ctx->app;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_DOMAIN_ATTACH_OK:
> +		break;
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +void *
> +__efc_ns_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node *node = ctx->app;
> +	struct efc *efc = node->efc;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_ENTER:
> +		/* sm: / send PLOGI */
> +		efc->tt.els_send(efc, node, ELS_PLOGI,
> +				EFC_FC_FLOGI_TIMEOUT_SEC,
> +				EFC_FC_ELS_DEFAULT_RETRIES);
> +		efc_node_transition(node, __efc_ns_plogi_wait_rsp, NULL);
> +		break;
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		break;
> +	}
> +
> +	return NULL;
> +}
> +
> +void *
> +__efc_ns_plogi_wait_rsp(struct efc_sm_ctx *ctx,
> +			enum efc_sm_event evt, void *arg)
> +{
> +	int rc;
> +	struct efc_node_cb *cbdata = arg;
> +	struct efc_node *node = ctx->app;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_SRRS_ELS_REQ_OK: {
> +		/* Save service parameters */
> +		if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
> +					   __efc_fabric_common, __func__)) {
> +			return NULL;
> +		}
> +		WARN_ON(!node->els_req_cnt);
> +		node->els_req_cnt--;
> +		/* sm: / save sparams, efc_node_attach */
> +		efc_node_save_sparms(node, cbdata->els_rsp.virt);
> +		rc = efc_node_attach(node);
> +		efc_node_transition(node, __efc_ns_wait_node_attach, NULL);
> +		if (rc == EFC_HW_RTN_SUCCESS_SYNC)
> +			efc_node_post_event(node, EFC_EVT_NODE_ATTACH_OK,
> +					    NULL);
> +		break;
> +	}
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +void *
> +__efc_ns_wait_node_attach(struct efc_sm_ctx *ctx,
> +			  enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node *node = ctx->app;
> +	struct efc *efc = node->efc;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_ENTER:
> +		efc_node_hold_frames(node);
> +		break;
> +
> +	case EFC_EVT_EXIT:
> +		efc_node_accept_frames(node);
> +		break;
> +
> +	case EFC_EVT_NODE_ATTACH_OK:
> +		node->attached = true;
> +		/* sm: / send RFTID */
> +		efc->tt.els_send_ct(efc, node, FC_RCTL_ELS_REQ,
> +				EFC_FC_ELS_SEND_DEFAULT_TIMEOUT,
> +				EFC_FC_ELS_DEFAULT_RETRIES);
> +		efc_node_transition(node, __efc_ns_rftid_wait_rsp, NULL);
> +		break;
> +
> +	case EFC_EVT_NODE_ATTACH_FAIL:
> +		/* node attach failed, shutdown the node */
> +		node->attached = false;
> +		node_printf(node, "Node attach failed\n");
> +		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
> +		efc_fabric_initiate_shutdown(node);
> +		break;
> +
> +	case EFC_EVT_SHUTDOWN:
> +		node_printf(node, "Shutdown event received\n");
> +		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
> +		efc_node_transition(node,
> +				    __efc_fabric_wait_attach_evt_shutdown,
> +				     NULL);
> +		break;
> +
> +	/*
> +	 * if receive RSCN just ignore,
> +	 * we haven't sent GID_PT yet (ACC sent by fabctl node)
> +	 */
> +	case EFC_EVT_RSCN_RCVD:
> +		break;
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +void *
> +__efc_fabric_wait_attach_evt_shutdown(struct efc_sm_ctx *ctx,
> +				      enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node *node = ctx->app;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_ENTER:
> +		efc_node_hold_frames(node);
> +		break;
> +
> +	case EFC_EVT_EXIT:
> +		efc_node_accept_frames(node);
> +		break;
> +
> +	/* wait for any of these attach events and then shutdown */
> +	case EFC_EVT_NODE_ATTACH_OK:
> +		node->attached = true;
> +		node_printf(node, "Attach evt=%s, proceed to shutdown\n",
> +			    efc_sm_event_name(evt));
> +		efc_fabric_initiate_shutdown(node);
> +		break;
> +
> +	case EFC_EVT_NODE_ATTACH_FAIL:
> +		node->attached = false;
> +		node_printf(node, "Attach evt=%s, proceed to shutdown\n",
> +			    efc_sm_event_name(evt));
> +		efc_fabric_initiate_shutdown(node);
> +		break;
> +
> +	/* ignore shutdown event as we're already in shutdown path */
> +	case EFC_EVT_SHUTDOWN:
> +		node_printf(node, "Shutdown event received\n");
> +		break;
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +void *
> +__efc_ns_rftid_wait_rsp(struct efc_sm_ctx *ctx,
> +			enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node *node = ctx->app;
> +	struct efc *efc = node->efc;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_SRRS_ELS_REQ_OK:
> +		if (efc_node_check_ns_req(ctx, evt, arg, FC_NS_RFT_ID,
> +					  __efc_fabric_common, __func__)) {
> +			return NULL;
> +		}
> +		WARN_ON(!node->els_req_cnt);
> +		node->els_req_cnt--;
> +		/* sm: / send RFFID */
> +		efc->tt.els_send_ct(efc, node, FC_NS_RFF_ID,
> +				EFC_FC_ELS_SEND_DEFAULT_TIMEOUT,
> +				EFC_FC_ELS_DEFAULT_RETRIES);
> +		efc_node_transition(node, __efc_ns_rffid_wait_rsp, NULL);
> +		break;
> +
> +	/*
> +	 * if receive RSCN just ignore,
> +	 * we haven't sent GID_PT yet (ACC sent by fabctl node)
> +	 */
> +	case EFC_EVT_RSCN_RCVD:
> +		break;
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +/**
> + * Waits for an RFFID response event; if configured for an initiator operation,
> + * a GIDPT name services request is issued.
> + */
> +void *
> +__efc_ns_rffid_wait_rsp(struct efc_sm_ctx *ctx,
> +			enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node *node = ctx->app;
> +	struct efc *efc = node->efc;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_SRRS_ELS_REQ_OK:	{
> +		if (efc_node_check_ns_req(ctx, evt, arg, FC_NS_RFF_ID,
> +					  __efc_fabric_common, __func__)) {
> +			return NULL;
> +		}
> +		WARN_ON(!node->els_req_cnt);
> +		node->els_req_cnt--;
> +		if (node->sport->enable_rscn) {
> +			/* sm: if enable_rscn / send GIDPT */
> +			efc->tt.els_send_ct(efc, node, FC_NS_GID_PT,
> +					EFC_FC_ELS_SEND_DEFAULT_TIMEOUT,
> +					EFC_FC_ELS_DEFAULT_RETRIES);
> +
> +			efc_node_transition(node, __efc_ns_gidpt_wait_rsp,
> +					    NULL);
> +		} else {
> +			/* if 'T' only, we're done, go to idle */
> +			efc_node_transition(node, __efc_ns_idle, NULL);
> +		}
> +		break;
> +	}
> +	/*
> +	 * if receive RSCN just ignore,
> +	 * we haven't sent GID_PT yet (ACC sent by fabctl node)
> +	 */
> +	case EFC_EVT_RSCN_RCVD:
> +		break;
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +static int
> +efc_process_gidpt_payload(struct efc_node *node,
> +			  void *data, u32 gidpt_len)
> +{
> +	u32 i, j;
> +	struct efc_node *newnode;
> +	struct efc_sli_port *sport = node->sport;
> +	struct efc *efc = node->efc;
> +	u32 port_id = 0, port_count, portlist_count;
> +	struct efc_node *n;
> +	struct efc_node **active_nodes;
> +	int residual;
> +	struct fc_ct_hdr *hdr = data;
> +	struct fc_gid_pn_resp *gidpt = data + sizeof(*hdr);
> +
> +	residual = be16_to_cpu(hdr->ct_mr_size);
> +
> +	if (residual != 0)
> +		efc_log_debug(node->efc, "residual is %u words\n", residual);
> +
> +	if (be16_to_cpu(hdr->ct_cmd) == FC_FS_RJT) {
> +		node_printf(node,
> +			    "GIDPT request failed: rsn x%x rsn_expl x%x\n",
> +			    hdr->ct_reason, hdr->ct_explan);
> +		return EFC_FAIL;
> +	}
> +
> +	portlist_count = (gidpt_len - sizeof(*hdr)) / sizeof(*gidpt);
> +
> +	/* Count the number of nodes */
> +	port_count = 0;
> +	list_for_each_entry(n, &sport->node_list, list_entry) {
> +		port_count++;
> +	}
> +
> +	/* Allocate a buffer for all nodes */
> +	active_nodes = kzalloc(port_count * sizeof(*active_nodes), GFP_ATOMIC);
> +	if (!active_nodes) {
> +		node_printf(node, "efc_malloc failed\n");
> +		return EFC_FAIL;
> +	}
> +
> +	/* Fill buffer with fc_id of active nodes */
> +	i = 0;
> +	list_for_each_entry(n, &sport->node_list, list_entry) {
> +		port_id = n->rnode.fc_id;
> +		switch (port_id) {
> +		case FC_FID_FLOGI:
> +		case FC_FID_FCTRL:
> +		case FC_FID_DIR_SERV:
> +			break;
> +		default:
> +			if (port_id != FC_FID_DOM_MGR)
> +				active_nodes[i++] = n;
> +			break;
> +		}
> +	}
> +
> +	/* update the active nodes buffer */
> +	for (i = 0; i < portlist_count; i++) {
> +		hton24(gidpt[i].fp_fid, port_id);
> +
> +		for (j = 0; j < port_count; j++) {
> +			if (active_nodes[j] &&
> +			    port_id == active_nodes[j]->rnode.fc_id) {
> +				active_nodes[j] = NULL;
> +			}
> +		}
> +
> +		if (gidpt[i].fp_resvd & FC_NS_FID_LAST)
> +			break;
> +	}
> +
> +	/* Those remaining in the active_nodes[] are now gone ! */
> +	for (i = 0; i < port_count; i++) {
> +		/*
> +		 * if we're an initiator and the remote node
> +		 * is a target, then post the node missing event.
> +		 * if we're target and we have enabled
> +		 * target RSCN, then post the node missing event.
> +		 */
> +		if (active_nodes[i]) {
> +			if ((node->sport->enable_ini &&
> +			     active_nodes[i]->targ) ||
> +			     (node->sport->enable_tgt &&
> +			     enable_target_rscn(efc))) {
> +				efc_node_post_event(active_nodes[i],
> +						    EFC_EVT_NODE_MISSING,
> +						     NULL);
> +			} else {
> +				node_printf(node,
> +					    "GID_PT: skipping non-tgt port_id x%06x\n",
> +					    active_nodes[i]->rnode.fc_id);
> +			}
> +		}
> +	}
> +	kfree(active_nodes);
> +
> +	for (i = 0; i < portlist_count; i++) {
> +		hton24(gidpt[i].fp_fid, port_id);
> +
> +		/* Don't create node for ourselves */
> +		if (port_id != node->rnode.sport->fc_id) {
> +			newnode = efc_node_find(sport, port_id);
> +			if (!newnode) {
> +				if (node->sport->enable_ini) {
> +					newnode = efc_node_alloc(sport,
> +								 port_id,
> +								  false,
> +								  false);
> +					if (!newnode) {
> +						efc_log_err(efc,
> +							    "efc_node_alloc() failed\n");
> +						return EFC_FAIL;
> +					}
> +					/*
> +					 * send PLOGI automatically
> +					 * if initiator
> +					 */
> +					efc_node_init_device(newnode, true);
> +				}
> +				continue;
> +			}
> +
> +			if (node->sport->enable_ini && newnode->targ) {
> +				efc_node_post_event(newnode,
> +						    EFC_EVT_NODE_REFOUND,
> +						    NULL);
> +			}
> +			/*
> +			 * original code sends ADISC,
> +			 * has notion of "refound"
> +			 */
> +		}

A helper function or something which makes this heavy idention go
away, please. This is hard to read.

> +
> +		if (gidpt[i].fp_resvd & FC_NS_FID_LAST)
> +			break;
> +	}
> +	return EFC_SUCCESS;
> +}
> +
> +/**
> + * Wait for a GIDPT response from the name server. Process the FC_IDs that are
> + * reported by creating new remote ports, as needed.
> + */
> +void *
> +__efc_ns_gidpt_wait_rsp(struct efc_sm_ctx *ctx,
> +			enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node_cb *cbdata = arg;
> +	struct efc_node *node = ctx->app;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_SRRS_ELS_REQ_OK:	{
> +		if (efc_node_check_ns_req(ctx, evt, arg, FC_NS_GID_PT,
> +					  __efc_fabric_common, __func__)) {
> +			return NULL;
> +		}
> +		WARN_ON(!node->els_req_cnt);
> +		node->els_req_cnt--;
> +		/* sm: / process GIDPT payload */
> +		efc_process_gidpt_payload(node, cbdata->els_rsp.virt,
> +					  cbdata->els_rsp.len);
> +		efc_node_transition(node, __efc_ns_idle, NULL);
> +		break;
> +	}
> +
> +	case EFC_EVT_SRRS_ELS_REQ_FAIL:	{
> +		/* not much we can do; will retry with the next RSCN */
> +		node_printf(node, "GID_PT failed to complete\n");
> +		WARN_ON(!node->els_req_cnt);
> +		node->els_req_cnt--;
> +		efc_node_transition(node, __efc_ns_idle, NULL);
> +		break;
> +	}
> +
> +	/* if receive RSCN here, queue up another discovery processing */
> +	case EFC_EVT_RSCN_RCVD: {
> +		node_printf(node, "RSCN received during GID_PT processing\n");
> +		node->rscn_pending = true;
> +		break;
> +	}
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +/**
> + * Idle. Waiting for RSCN received events
> + * (posted from the fabric controller), and
> + * restarts the GIDPT name services query and processing.
> + */

Not a proper kerneldoc. There are more of those in this file.

> +void *
> +__efc_ns_idle(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node *node = ctx->app;
> +	struct efc *efc = node->efc;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_ENTER:
> +		if (!node->rscn_pending)
> +			break;
> +
> +		node_printf(node, "RSCN pending, restart discovery\n");
> +		node->rscn_pending = false;
> +
> +			/* fall through */
> +
> +	case EFC_EVT_RSCN_RCVD: {
> +		/* sm: / send GIDPT */
> +		/*
> +		 * If target RSCN processing is enabled,
> +		 * and this is target only (not initiator),
> +		 * and tgt_rscn_delay is non-zero,
> +		 * then we delay issuing the GID_PT
> +		 */
> +		if (efc->tgt_rscn_delay_msec != 0 &&
> +		    !node->sport->enable_ini && node->sport->enable_tgt &&
> +		    enable_target_rscn(efc)) {
> +			efc_node_transition(node, __efc_ns_gidpt_delay, NULL);
> +		} else {
> +			efc->tt.els_send_ct(efc, node, FC_NS_GID_PT,
> +					EFC_FC_ELS_SEND_DEFAULT_TIMEOUT,
> +					EFC_FC_ELS_DEFAULT_RETRIES);
> +			efc_node_transition(node, __efc_ns_gidpt_wait_rsp,
> +					    NULL);
> +		}
> +		break;
> +	}
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		break;
> +	}
> +
> +	return NULL;
> +}
> +
> +/**
> + * Handle GIDPT delay timer callback
> + * Post an EFC_EVT_GIDPT_DEIALY_EXPIRED event to the passed in node.
> + */
> +static void
> +gidpt_delay_timer_cb(struct timer_list *t)
> +{
> +	struct efc_node *node = from_timer(node, t, gidpt_delay_timer);
> +
> +	del_timer(&node->gidpt_delay_timer);
> +
> +	efc_node_post_event(node, EFC_EVT_GIDPT_DELAY_EXPIRED, NULL);
> +}
> +
> +/**
> + * Name services node state machine: Delayed GIDPT.
> + *
> + * Waiting for GIDPT delay to expire before submitting GIDPT to name server.
> + */
> +void *
> +__efc_ns_gidpt_delay(struct efc_sm_ctx *ctx,
> +		     enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node *node = ctx->app;
> +	struct efc *efc = node->efc;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_ENTER: {
> +		time_t delay_msec;
> +
> +		/*
> +		 * Compute the delay time.
> +		 * Set to tgt_rscn_delay, if the time since last GIDPT
> +		 * is less than tgt_rscn_period, then use tgt_rscn_period.
> +		 */
> +		delay_msec = efc->tgt_rscn_delay_msec;
> +		if ((jiffies_to_msecs(jiffies) - node->time_last_gidpt_msec)
> +		    < efc->tgt_rscn_period_msec) {

Maybe the first part of the condition as new variable to make the if readable.

> +			delay_msec = efc->tgt_rscn_period_msec;
> +		}
> +		timer_setup(&node->gidpt_delay_timer, &gidpt_delay_timer_cb,
> +			    0);
> +		mod_timer(&node->gidpt_delay_timer,
> +			  jiffies + msecs_to_jiffies(delay_msec));
> +
> +		break;
> +	}
> +
> +	case EFC_EVT_GIDPT_DELAY_EXPIRED:
> +		node->time_last_gidpt_msec = jiffies_to_msecs(jiffies);
> +
> +		efc->tt.els_send_ct(efc, node, FC_NS_GID_PT,
> +				EFC_FC_ELS_SEND_DEFAULT_TIMEOUT,
> +				EFC_FC_ELS_DEFAULT_RETRIES);
> +		efc_node_transition(node, __efc_ns_gidpt_wait_rsp, NULL);
> +		break;
> +
> +	case EFC_EVT_RSCN_RCVD: {
> +		efc_log_debug(efc,
> +			      "RSCN received while in GIDPT delay - no action\n");
> +		break;
> +	}
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		break;
> +	}
> +
> +	return NULL;
> +}
> +
> +/**
> + * Fabric controller node state machine: Initial state.
> + *
> + * Issue a PLOGI to a well-known fabric controller address.
> + */
> +void *
> +__efc_fabctl_init(struct efc_sm_ctx *ctx,
> +		  enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node *node = ctx->app;
> +	struct efc *efc = node->efc;
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_ENTER:
> +		/* no need to login to fabric controller, just send SCR */
> +		efc->tt.els_send(efc, node, ELS_SCR,
> +				EFC_FC_FLOGI_TIMEOUT_SEC,
> +				EFC_FC_ELS_DEFAULT_RETRIES);
> +		efc_node_transition(node, __efc_fabctl_wait_scr_rsp, NULL);
> +		break;
> +
> +	case EFC_EVT_NODE_ATTACH_OK:
> +		node->attached = true;
> +		break;
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +/**
> + * Fabric controller node state machine: Wait for a node attach request
> + * to complete.
> + *
> + * Wait for a node attach to complete. If successful, issue an SCR
> + * to the fabric controller, subscribing to all RSCN.
> + */
> +void *
> +__efc_fabctl_wait_node_attach(struct efc_sm_ctx *ctx,
> +			      enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node *node = ctx->app;
> +	struct efc *efc = node->efc;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_ENTER:
> +		efc_node_hold_frames(node);
> +		break;
> +
> +	case EFC_EVT_EXIT:
> +		efc_node_accept_frames(node);
> +		break;
> +
> +	case EFC_EVT_NODE_ATTACH_OK:
> +		node->attached = true;
> +		/* sm: / send SCR */
> +		efc->tt.els_send(efc, node, ELS_SCR,
> +				EFC_FC_ELS_SEND_DEFAULT_TIMEOUT,
> +				EFC_FC_ELS_DEFAULT_RETRIES);
> +		efc_node_transition(node, __efc_fabctl_wait_scr_rsp, NULL);
> +		break;
> +
> +	case EFC_EVT_NODE_ATTACH_FAIL:
> +		/* node attach failed, shutdown the node */
> +		node->attached = false;
> +		node_printf(node, "Node attach failed\n");
> +		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
> +		efc_fabric_initiate_shutdown(node);
> +		break;
> +
> +	case EFC_EVT_SHUTDOWN:
> +		node_printf(node, "Shutdown event received\n");
> +		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
> +		efc_node_transition(node,
> +				    __efc_fabric_wait_attach_evt_shutdown,
> +				     NULL);
> +		break;
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +/**
> + * Fabric controller node state machine:
> + * Wait for an SCR response from the fabric controller.
> + */
> +void *
> +__efc_fabctl_wait_scr_rsp(struct efc_sm_ctx *ctx,
> +			  enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node *node = ctx->app;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_SRRS_ELS_REQ_OK:
> +		if (efc_node_check_els_req(ctx, evt, arg, ELS_SCR,
> +					   __efc_fabric_common, __func__)) {
> +			return NULL;
> +		}
> +		WARN_ON(!node->els_req_cnt);
> +		node->els_req_cnt--;
> +		efc_node_transition(node, __efc_fabctl_ready, NULL);
> +		break;
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +static void
> +efc_process_rscn(struct efc_node *node, struct efc_node_cb *cbdata)
> +{
> +	struct efc *efc = node->efc;
> +	struct efc_sli_port *sport = node->sport;
> +	struct efc_node *ns;
> +
> +	/* Forward this event to the name-services node */
> +	ns = efc_node_find(sport, FC_FID_DIR_SERV);
> +	if (ns)
> +		efc_node_post_event(ns, EFC_EVT_RSCN_RCVD, cbdata);
> +	else
> +		efc_log_warn(efc, "can't find name server node\n");
> +}
> +
> +/* Fabric controller node state machine: Ready.
> + * In this state, the fabric controller sends a RSCN, which is received
> + * by this node and is forwarded to the name services node object; and
> + * the RSCN LS_ACC is sent.
> + */
> +void *
> +__efc_fabctl_ready(struct efc_sm_ctx *ctx,
> +		   enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node_cb *cbdata = arg;
> +	struct efc_node *node = ctx->app;
> +	struct efc *efc = node->efc;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_RSCN_RCVD: {
> +		struct fc_frame_header *hdr = cbdata->header->dma.virt;
> +
> +		/*
> +		 * sm: / process RSCN (forward to name services node),
> +		 * send LS_ACC
> +		 */
> +		efc_process_rscn(node, cbdata);
> +		efc->tt.els_send_resp(efc, node, ELS_LS_ACC,
> +					be16_to_cpu(hdr->fh_ox_id));
> +		efc_node_transition(node, __efc_fabctl_wait_ls_acc_cmpl,
> +				    NULL);
> +		break;
> +	}
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +void *
> +__efc_fabctl_wait_ls_acc_cmpl(struct efc_sm_ctx *ctx,
> +			      enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node *node = ctx->app;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_ENTER:
> +		efc_node_hold_frames(node);
> +		break;
> +
> +	case EFC_EVT_EXIT:
> +		efc_node_accept_frames(node);
> +		break;
> +
> +	case EFC_EVT_SRRS_ELS_CMPL_OK:
> +		WARN_ON(!node->els_cmpl_cnt);
> +		node->els_cmpl_cnt--;
> +		efc_node_transition(node, __efc_fabctl_ready, NULL);
> +		break;
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +static uint64_t
> +efc_get_wwpn(struct fc_els_flogi *sp)
> +{
> +	return be64_to_cpu(sp->fl_wwnn);
> +}
> +
> +static int
> +efc_rnode_is_winner(struct efc_sli_port *sport)
> +{
> +	struct fc_els_flogi *remote_sp;
> +	u64 remote_wwpn;
> +	u64 local_wwpn = sport->wwpn;
> +	u64 wwn_bump = 0;
> +
> +	remote_sp = (struct fc_els_flogi *)sport->domain->flogi_service_params;
> +	remote_wwpn = efc_get_wwpn(remote_sp);
> +
> +	local_wwpn ^= wwn_bump;
> +
> +	remote_wwpn = efc_get_wwpn(remote_sp);
> +
> +	efc_log_debug(sport->efc, "r: %llx\n",
> +		      be64_to_cpu(remote_sp->fl_wwpn));
> +	efc_log_debug(sport->efc, "l: %llx\n", local_wwpn);
> +
> +	if (remote_wwpn == local_wwpn) {
> +		efc_log_warn(sport->efc,
> +			     "WWPN of remote node [%08x %08x] matches local WWPN\n",
> +			     (u32)(local_wwpn >> 32ll),
> +			     (u32)local_wwpn);
> +		return -1;
> +	}
> +
> +	return (remote_wwpn > local_wwpn);
> +}
> +
> +void *
> +__efc_p2p_wait_domain_attach(struct efc_sm_ctx *ctx,
> +			     enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node *node = ctx->app;
> +	struct efc *efc = node->efc;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_ENTER:
> +		efc_node_hold_frames(node);
> +		break;
> +
> +	case EFC_EVT_EXIT:
> +		efc_node_accept_frames(node);
> +		break;
> +
> +	case EFC_EVT_DOMAIN_ATTACH_OK: {
> +		struct efc_sli_port *sport = node->sport;
> +		struct efc_node *rnode;
> +
> +		/*
> +		 * this transient node (SID=0 (recv'd FLOGI)
> +		 * or DID=fabric (sent FLOGI))
> +		 * is the p2p winner, will use a separate node
> +		 * to send PLOGI to peer
> +		 */
> +		WARN_ON(!node->sport->p2p_winner);
> +
> +		rnode = efc_node_find(sport, node->sport->p2p_remote_port_id);
> +		if (rnode) {
> +			/*
> +			 * the "other" transient p2p node has
> +			 * already kicked off the
> +			 * new node from which PLOGI is sent
> +			 */
> +			node_printf(node,
> +				    "Node with fc_id x%x already exists\n",
> +				    rnode->rnode.fc_id);
> +		} else {
> +			/*
> +			 * create new node (SID=1, DID=2)
> +			 * from which to send PLOGI
> +			 */
> +			rnode = efc_node_alloc(sport,
> +					       sport->p2p_remote_port_id,
> +						false, false);
> +			if (!rnode) {
> +				efc_log_err(efc, "node alloc failed\n");
> +				return NULL;
> +			}
> +
> +			efc_fabric_notify_topology(node);
> +			/* sm: / allocate p2p remote node */
> +			efc_node_transition(rnode, __efc_p2p_rnode_init,
> +					    NULL);
> +		}
> +
> +		/*
> +		 * the transient node (SID=0 or DID=fabric)
> +		 * has served its purpose
> +		 */
> +		if (node->rnode.fc_id == 0) {
> +			/*
> +			 * if this is the SID=0 node,
> +			 * move to the init state in case peer
> +			 * has restarted FLOGI discovery and FLOGI is pending
> +			 */
> +			/* don't send PLOGI on efc_d_init entry */
> +			efc_node_init_device(node, false);
> +		} else {
> +			/*
> +			 * if this is the DID=fabric node
> +			 * (we initiated FLOGI), shut it down
> +			 */
> +			node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
> +			efc_fabric_initiate_shutdown(node);
> +		}
> +		break;
> +	}
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +void *
> +__efc_p2p_rnode_init(struct efc_sm_ctx *ctx,
> +		     enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node_cb *cbdata = arg;
> +	struct efc_node *node = ctx->app;
> +	struct efc *efc = node->efc;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_ENTER:
> +		/* sm: / send PLOGI */
> +		efc->tt.els_send(efc, node, ELS_PLOGI,
> +				EFC_FC_FLOGI_TIMEOUT_SEC,
> +				EFC_FC_ELS_DEFAULT_RETRIES);
> +		efc_node_transition(node, __efc_p2p_wait_plogi_rsp, NULL);
> +		break;
> +
> +	case EFC_EVT_ABTS_RCVD:
> +		/* sm: send BA_ACC */
> +		efc->tt.bls_send_acc_hdr(efc, node, cbdata->header->dma.virt);
> +		break;
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +void *
> +__efc_p2p_wait_flogi_acc_cmpl(struct efc_sm_ctx *ctx,
> +			      enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node_cb *cbdata = arg;
> +	struct efc_node *node = ctx->app;
> +	struct efc *efc = node->efc;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_ENTER:
> +		efc_node_hold_frames(node);
> +		break;
> +
> +	case EFC_EVT_EXIT:
> +		efc_node_accept_frames(node);
> +		break;
> +
> +	case EFC_EVT_SRRS_ELS_CMPL_OK:
> +		WARN_ON(!node->els_cmpl_cnt);
> +		node->els_cmpl_cnt--;
> +
> +		/* sm: if p2p_winner / domain_attach */
> +		if (node->sport->p2p_winner) {
> +			efc_node_transition(node,
> +					    __efc_p2p_wait_domain_attach,
> +					NULL);
> +			if (!node->sport->domain->attached) {
> +				node_printf(node, "Domain not attached\n");
> +				efc_domain_attach(node->sport->domain,
> +						  node->sport->p2p_port_id);
> +			} else {
> +				node_printf(node, "Domain already attached\n");
> +				efc_node_post_event(node,
> +						    EFC_EVT_DOMAIN_ATTACH_OK,
> +						    NULL);
> +			}
> +		} else {
> +			/* this node has served its purpose;
> +			 * we'll expect a PLOGI on a separate
> +			 * node (remote SID=0x1); return this node
> +			 * to init state in case peer
> +			 * restarts discovery -- it may already
> +			 * have (pending frames may exist).
> +			 */
> +			/* don't send PLOGI on efc_d_init entry */
> +			efc_node_init_device(node, false);
> +		}
> +		break;
> +
> +	case EFC_EVT_SRRS_ELS_CMPL_FAIL:
> +		/*
> +		 * LS_ACC failed, possibly due to link down;
> +		 * shutdown node and wait
> +		 * for FLOGI discovery to restart
> +		 */
> +		node_printf(node, "FLOGI LS_ACC failed, shutting down\n");
> +		WARN_ON(!node->els_cmpl_cnt);
> +		node->els_cmpl_cnt--;
> +		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
> +		efc_fabric_initiate_shutdown(node);
> +		break;
> +
> +	case EFC_EVT_ABTS_RCVD: {
> +		/* sm: / send BA_ACC */
> +		efc->tt.bls_send_acc_hdr(efc, node,
> +					 cbdata->header->dma.virt);
> +		break;
> +	}
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +void *
> +__efc_p2p_wait_plogi_rsp(struct efc_sm_ctx *ctx,
> +			 enum efc_sm_event evt, void *arg)
> +{
> +	int rc;
> +	struct efc_node_cb *cbdata = arg;
> +	struct efc_node *node = ctx->app;
> +	struct efc *efc = node->efc;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_SRRS_ELS_REQ_OK: {
> +		if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
> +					   __efc_fabric_common, __func__)) {
> +			return NULL;
> +		}
> +		WARN_ON(!node->els_req_cnt);
> +		node->els_req_cnt--;
> +		/* sm: / save sparams, efc_node_attach */
> +		efc_node_save_sparms(node, cbdata->els_rsp.virt);
> +		rc = efc_node_attach(node);
> +		efc_node_transition(node, __efc_p2p_wait_node_attach, NULL);
> +		if (rc == EFC_HW_RTN_SUCCESS_SYNC)
> +			efc_node_post_event(node, EFC_EVT_NODE_ATTACH_OK,
> +					    NULL);
> +		break;
> +	}
> +	case EFC_EVT_SRRS_ELS_REQ_FAIL: {
> +		if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
> +					   __efc_fabric_common, __func__)) {
> +			return NULL;
> +		}
> +		node_printf(node, "PLOGI failed, shutting down\n");
> +		WARN_ON(!node->els_req_cnt);
> +		node->els_req_cnt--;
> +		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
> +		efc_fabric_initiate_shutdown(node);
> +		break;
> +	}
> +
> +	case EFC_EVT_PLOGI_RCVD: {
> +		struct fc_frame_header *hdr = cbdata->header->dma.virt;
> +		/* if we're in external loopback mode, just send LS_ACC */
> +		if (node->efc->external_loopback) {
> +			efc->tt.els_send_resp(efc, node, ELS_PLOGI,
> +						be16_to_cpu(hdr->fh_ox_id));
> +		} else {
> +			/*
> +			 * if this isn't external loopback,
> +			 * pass to default handler
> +			 */
> +			__efc_fabric_common(__func__, ctx, evt, arg);
> +		}
> +		break;
> +	}
> +	case EFC_EVT_PRLI_RCVD:
> +		/* I, or I+T */
> +		/* sent PLOGI and before completion was seen, received the
> +		 * PRLI from the remote node (WCQEs and RCQEs come in on
> +		 * different queues and order of processing cannot be assumed)
> +		 * Save OXID so PRLI can be sent after the attach and continue
> +		 * to wait for PLOGI response
> +		 */
> +		efc_process_prli_payload(node, cbdata->payload->dma.virt);
> +		efc_send_ls_acc_after_attach(node,
> +					     cbdata->header->dma.virt,
> +					     EFC_NODE_SEND_LS_ACC_PRLI);
> +		efc_node_transition(node, __efc_p2p_wait_plogi_rsp_recvd_prli,
> +				    NULL);
> +		break;
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +void *
> +__efc_p2p_wait_plogi_rsp_recvd_prli(struct efc_sm_ctx *ctx,
> +				    enum efc_sm_event evt, void *arg)
> +{
> +	int rc;
> +	struct efc_node_cb *cbdata = arg;
> +	struct efc_node *node = ctx->app;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_ENTER:
> +		/*
> +		 * Since we've received a PRLI, we have a port login and will
> +		 * just need to wait for the PLOGI response to do the node
> +		 * attach and then we can send the LS_ACC for the PRLI. If,
> +		 * during this time, we receive FCP_CMNDs (which is possible
> +		 * since we've already sent a PRLI and our peer may have
> +		 * accepted).
> +		 * At this time, we are not waiting on any other unsolicited
> +		 * frames to continue with the login process. Thus, it will not
> +		 * hurt to hold frames here.
> +		 */
> +		efc_node_hold_frames(node);
> +		break;
> +
> +	case EFC_EVT_EXIT:
> +		efc_node_accept_frames(node);
> +		break;
> +
> +	case EFC_EVT_SRRS_ELS_REQ_OK:	/* PLOGI response received */
> +		/* Completion from PLOGI sent */
> +		if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
> +					   __efc_fabric_common, __func__)) {
> +			return NULL;
> +		}
> +		WARN_ON(!node->els_req_cnt);
> +		node->els_req_cnt--;
> +		/* sm: / save sparams, efc_node_attach */
> +		efc_node_save_sparms(node, cbdata->els_rsp.virt);
> +		rc = efc_node_attach(node);
> +		efc_node_transition(node, __efc_p2p_wait_node_attach, NULL);
> +		if (rc == EFC_HW_RTN_SUCCESS_SYNC)
> +			efc_node_post_event(node, EFC_EVT_NODE_ATTACH_OK,
> +					    NULL);
> +		break;
> +
> +	case EFC_EVT_SRRS_ELS_REQ_FAIL:	/* PLOGI response received */
> +	case EFC_EVT_SRRS_ELS_REQ_RJT:
> +		/* PLOGI failed, shutdown the node */
> +		if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
> +					   __efc_fabric_common, __func__)) {
> +			return NULL;
> +		}
> +		WARN_ON(!node->els_req_cnt);
> +		node->els_req_cnt--;
> +		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
> +		efc_fabric_initiate_shutdown(node);
> +		break;
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +void *
> +__efc_p2p_wait_node_attach(struct efc_sm_ctx *ctx,
> +			   enum efc_sm_event evt, void *arg)
> +{
> +	struct efc_node_cb *cbdata = arg;
> +	struct efc_node *node = ctx->app;
> +
> +	efc_node_evt_set(ctx, evt, __func__);
> +
> +	node_sm_trace();
> +
> +	switch (evt) {
> +	case EFC_EVT_ENTER:
> +		efc_node_hold_frames(node);
> +		break;
> +
> +	case EFC_EVT_EXIT:
> +		efc_node_accept_frames(node);
> +		break;
> +
> +	case EFC_EVT_NODE_ATTACH_OK:
> +		node->attached = true;
> +		switch (node->send_ls_acc) {
> +		case EFC_NODE_SEND_LS_ACC_PRLI: {
> +			efc_d_send_prli_rsp(node->ls_acc_io,
> +					    node->ls_acc_oxid);
> +			node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE;
> +			node->ls_acc_io = NULL;
> +			break;
> +		}
> +		case EFC_NODE_SEND_LS_ACC_PLOGI: /* Can't happen in P2P */
> +		case EFC_NODE_SEND_LS_ACC_NONE:
> +		default:
> +			/* Normal case for I */
> +			/* sm: send_plogi_acc is not set / send PLOGI acc */
> +			efc_node_transition(node, __efc_d_port_logged_in,
> +					    NULL);
> +			break;
> +		}
> +		break;
> +
> +	case EFC_EVT_NODE_ATTACH_FAIL:
> +		/* node attach failed, shutdown the node */
> +		node->attached = false;
> +		node_printf(node, "Node attach failed\n");
> +		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
> +		efc_fabric_initiate_shutdown(node);
> +		break;
> +
> +	case EFC_EVT_SHUTDOWN:
> +		node_printf(node, "%s received\n", efc_sm_event_name(evt));
> +		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
> +		efc_node_transition(node,
> +				    __efc_fabric_wait_attach_evt_shutdown,
> +				     NULL);
> +		break;
> +	case EFC_EVT_PRLI_RCVD:
> +		node_printf(node, "%s: PRLI received before node is attached\n",
> +			    efc_sm_event_name(evt));
> +		efc_process_prli_payload(node, cbdata->payload->dma.virt);
> +		efc_send_ls_acc_after_attach(node,
> +					     cbdata->header->dma.virt,
> +				EFC_NODE_SEND_LS_ACC_PRLI);
> +		break;
> +
> +	default:
> +		__efc_fabric_common(__func__, ctx, evt, arg);
> +		return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +int
> +efc_p2p_setup(struct efc_sli_port *sport)
> +{
> +	struct efc *efc = sport->efc;
> +	int rnode_winner;
> +
> +	rnode_winner = efc_rnode_is_winner(sport);
> +
> +	/* set sport flags to indicate p2p "winner" */
> +	if (rnode_winner == 1) {
> +		sport->p2p_remote_port_id = 0;
> +		sport->p2p_port_id = 0;
> +		sport->p2p_winner = false;
> +	} else if (rnode_winner == 0) {
> +		sport->p2p_remote_port_id = 2;
> +		sport->p2p_port_id = 1;
> +		sport->p2p_winner = true;
> +	} else {
> +		/* no winner; only okay if external loopback enabled */
> +		if (sport->efc->external_loopback) {
> +			/*
> +			 * External loopback mode enabled;
> +			 * local sport and remote node
> +			 * will be registered with an NPortID = 1;
> +			 */
> +			efc_log_debug(efc,
> +				      "External loopback mode enabled\n");
> +			sport->p2p_remote_port_id = 1;
> +			sport->p2p_port_id = 1;
> +			sport->p2p_winner = true;
> +		} else {
> +			efc_log_warn(efc,
> +				     "failed to determine p2p winner\n");
> +			return rnode_winner;
> +		}
> +	}
> +	return EFC_SUCCESS;
> +}
> diff --git a/drivers/scsi/elx/libefc/efc_fabric.h b/drivers/scsi/elx/libefc/efc_fabric.h
> new file mode 100644
> index 000000000000..9571b4b7b2ce
> --- /dev/null
> +++ b/drivers/scsi/elx/libefc/efc_fabric.h
> @@ -0,0 +1,116 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2019 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_sport_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_sli_port *sport);
> +void
> +efc_fabric_set_topology(struct efc_node *node,
> +			enum efc_sport_topology topology);
> +void efc_fabric_notify_topology(struct efc_node *node);
> +
> +#endif /* __EFCT_FABRIC_H__ */
> -- 
> 2.16.4
> 
> 

Thanks,
Daniel

  reply	other threads:[~2020-04-15 19:08 UTC|newest]

Thread overview: 124+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-12  3:32 [PATCH v3 00/31] [NEW] efct: Broadcom (Emulex) FC Target driver James Smart
2020-04-12  3:32 ` [PATCH v3 01/31] elx: libefc_sli: SLI-4 register offsets and field definitions James Smart
2020-04-14 15:23   ` Daniel Wagner
2020-04-22  4:28     ` James Smart
2020-04-15 12:06   ` Hannes Reinecke
2020-04-23  1:52   ` Roman Bolshakov
2020-04-12  3:32 ` [PATCH v3 02/31] elx: libefc_sli: SLI Descriptors and Queue entries James Smart
2020-04-14 18:02   ` Daniel Wagner
2020-04-22  4:41     ` James Smart
2020-04-15 12:14   ` Hannes Reinecke
2020-04-15 17:43     ` James Bottomley
2020-04-22  4:44     ` James Smart
2020-04-12  3:32 ` [PATCH v3 03/31] elx: libefc_sli: Data structures and defines for mbox commands James Smart
2020-04-14 19:01   ` Daniel Wagner
2020-04-15 12:22   ` Hannes Reinecke
2020-04-12  3:32 ` [PATCH v3 04/31] elx: libefc_sli: queue create/destroy/parse routines James Smart
2020-04-15 10:04   ` Daniel Wagner
2020-04-22  5:05     ` James Smart
2020-04-24  7:29       ` Daniel Wagner
2020-04-24 15:21         ` James Smart
2020-04-15 12:27   ` Hannes Reinecke
2020-04-12  3:32 ` [PATCH v3 05/31] elx: libefc_sli: Populate and post different WQEs James Smart
2020-04-15 14:34   ` Daniel Wagner
2020-04-22  5:08     ` James Smart
2020-04-12  3:32 ` [PATCH v3 06/31] elx: libefc_sli: bmbx routines and SLI config commands James Smart
2020-04-15 16:10   ` Daniel Wagner
2020-04-22  5:12     ` James Smart
2020-04-12  3:32 ` [PATCH v3 07/31] elx: libefc_sli: APIs to setup SLI library James Smart
2020-04-15 12:49   ` Hannes Reinecke
2020-04-15 17:06   ` Daniel Wagner
2020-04-12  3:32 ` [PATCH v3 08/31] elx: libefc: Generic state machine framework James Smart
2020-04-15 12:37   ` Hannes Reinecke
2020-04-15 17:20   ` Daniel Wagner
2020-04-12  3:32 ` [PATCH v3 09/31] elx: libefc: Emulex FC discovery library APIs and definitions James Smart
2020-04-15 12:41   ` Hannes Reinecke
2020-04-15 17:32   ` Daniel Wagner
2020-04-12  3:32 ` [PATCH v3 10/31] elx: libefc: FC Domain state machine interfaces James Smart
2020-04-15 12:50   ` Hannes Reinecke
2020-04-15 17:50   ` Daniel Wagner
2020-04-12  3:32 ` [PATCH v3 11/31] elx: libefc: SLI and FC PORT " James Smart
2020-04-15 15:38   ` Hannes Reinecke
2020-04-22 23:12     ` James Smart
2020-04-15 18:04   ` Daniel Wagner
2020-04-12  3:32 ` [PATCH v3 12/31] elx: libefc: Remote node " James Smart
2020-04-15 15:51   ` Hannes Reinecke
2020-04-23  1:35     ` James Smart
2020-04-23  8:02       ` Daniel Wagner
2020-04-23 18:24         ` James Smart
2020-04-15 18:19   ` Daniel Wagner
2020-04-23  1:32     ` James Smart
2020-04-23  7:49       ` Daniel Wagner
2020-04-12  3:32 ` [PATCH v3 13/31] elx: libefc: Fabric " James Smart
2020-04-15 18:51   ` Daniel Wagner [this message]
2020-04-16  6:37   ` Hannes Reinecke
2020-04-23  1:38     ` James Smart
2020-04-12  3:32 ` [PATCH v3 14/31] elx: libefc: FC node ELS and state handling James Smart
2020-04-15 18:56   ` Daniel Wagner
2020-04-23  2:50     ` James Smart
2020-04-23  8:05       ` Daniel Wagner
2020-04-23  8:12         ` Nathan Chancellor
2020-04-16  6:47   ` Hannes Reinecke
2020-04-23  2:55     ` James Smart
2020-04-12  3:32 ` [PATCH v3 15/31] elx: efct: Data structures and defines for hw operations James Smart
2020-04-16  6:51   ` Hannes Reinecke
2020-04-23  2:57     ` James Smart
2020-04-16  7:22   ` Daniel Wagner
2020-04-23  2:59     ` James Smart
2020-04-12  3:32 ` [PATCH v3 16/31] elx: efct: Driver initialization routines James Smart
2020-04-16  7:11   ` Hannes Reinecke
2020-04-23  3:09     ` James Smart
2020-04-16  8:03   ` Daniel Wagner
2020-04-12  3:32 ` [PATCH v3 17/31] elx: efct: Hardware queues creation and deletion James Smart
2020-04-16  7:14   ` Hannes Reinecke
2020-04-16  8:24   ` Daniel Wagner
2020-04-12  3:32 ` [PATCH v3 18/31] elx: efct: RQ buffer, memory pool allocation and deallocation APIs James Smart
2020-04-16  7:24   ` Hannes Reinecke
2020-04-23  3:16     ` James Smart
2020-04-16  8:41   ` Daniel Wagner
2020-04-12  3:32 ` [PATCH v3 19/31] elx: efct: Hardware IO and SGL initialization James Smart
2020-04-16  7:32   ` Hannes Reinecke
2020-04-16  8:47   ` Daniel Wagner
2020-04-12  3:32 ` [PATCH v3 20/31] elx: efct: Hardware queues processing James Smart
2020-04-16  7:37   ` Hannes Reinecke
2020-04-16  9:17   ` Daniel Wagner
2020-04-12  3:32 ` [PATCH v3 21/31] elx: efct: Unsolicited FC frame processing routines James Smart
2020-04-16  9:36   ` Daniel Wagner
2020-04-12  3:32 ` [PATCH v3 22/31] elx: efct: Extended link Service IO handling James Smart
2020-04-16  7:58   ` Hannes Reinecke
2020-04-23  3:30     ` James Smart
2020-04-16  9:49   ` Daniel Wagner
2020-04-12  3:32 ` [PATCH v3 23/31] elx: efct: SCSI IO handling routines James Smart
2020-04-16 11:40   ` Daniel Wagner
2020-04-12  3:32 ` [PATCH v3 24/31] elx: efct: LIO backend interface routines James Smart
2020-04-12  4:57   ` Bart Van Assche
2020-04-16 11:48     ` Daniel Wagner
2020-04-22  4:20     ` James Smart
2020-04-22  5:09       ` Bart Van Assche
2020-04-23  1:39         ` James Smart
2020-04-16  8:02   ` Hannes Reinecke
2020-04-16 12:34   ` Daniel Wagner
2020-04-22  4:20     ` James Smart
2020-04-12  3:32 ` [PATCH v3 25/31] elx: efct: Hardware IO submission routines James Smart
2020-04-16  8:10   ` Hannes Reinecke
2020-04-16 12:45     ` Daniel Wagner
2020-04-23  3:37       ` James Smart
2020-04-16 12:44   ` Daniel Wagner
2020-04-12  3:32 ` [PATCH v3 26/31] elx: efct: link statistics and SFP data James Smart
2020-04-16 12:55   ` Daniel Wagner
2020-04-12  3:32 ` [PATCH v3 27/31] elx: efct: xport and hardware teardown routines James Smart
2020-04-16  9:45   ` Hannes Reinecke
2020-04-16 13:01   ` Daniel Wagner
2020-04-12  3:33 ` [PATCH v3 28/31] elx: efct: Firmware update, async link processing James Smart
2020-04-16 10:01   ` Hannes Reinecke
2020-04-16 13:10   ` Daniel Wagner
2020-04-12  3:33 ` [PATCH v3 29/31] elx: efct: scsi_transport_fc host interface support James Smart
2020-04-12  3:33 ` [PATCH v3 30/31] elx: efct: Add Makefile and Kconfig for efct driver James Smart
2020-04-16 10:02   ` Hannes Reinecke
2020-04-16 13:15   ` Daniel Wagner
2020-04-12  3:33 ` [PATCH v3 31/31] elx: efct: Tie into kernel Kconfig and build process James Smart
2020-04-12  6:16   ` kbuild test robot
2020-04-12  6:16     ` kbuild test robot
2020-04-12  7:56   ` kbuild test robot
2020-04-12  7:56     ` kbuild test robot
2020-04-16 13:15   ` Daniel Wagner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200415185142.j5yo66gsmyse6m72@carbon \
    --to=dwagner@suse.de \
    --cc=bvanassche@acm.org \
    --cc=hare@suse.de \
    --cc=herbszt@gmx.de \
    --cc=jsmart2021@gmail.com \
    --cc=linux-scsi@vger.kernel.org \
    --cc=maier@linux.ibm.com \
    --cc=natechancellor@gmail.com \
    --cc=ram.vegesna@broadcom.com \
    --cc=rdunlap@infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.