1202bfdffSJames Smart // SPDX-License-Identifier: GPL-2.0
2202bfdffSJames Smart /*
3202bfdffSJames Smart  * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
4202bfdffSJames Smart  * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
5202bfdffSJames Smart  */
6202bfdffSJames Smart 
7202bfdffSJames Smart /*
8202bfdffSJames Smart  * device_sm Node State Machine: Remote Device States
9202bfdffSJames Smart  */
10202bfdffSJames Smart 
11202bfdffSJames Smart #include "efc.h"
12202bfdffSJames Smart #include "efc_device.h"
13202bfdffSJames Smart #include "efc_fabric.h"
14202bfdffSJames Smart 
15202bfdffSJames Smart void
efc_d_send_prli_rsp(struct efc_node * node,u16 ox_id)16202bfdffSJames Smart efc_d_send_prli_rsp(struct efc_node *node, u16 ox_id)
17202bfdffSJames Smart {
1899cf9226SColin Ian King 	int rc = EFC_SCSI_CALL_COMPLETE;
19202bfdffSJames Smart 	struct efc *efc = node->efc;
20202bfdffSJames Smart 
21202bfdffSJames Smart 	node->ls_acc_oxid = ox_id;
22202bfdffSJames Smart 	node->send_ls_acc = EFC_NODE_SEND_LS_ACC_PRLI;
23202bfdffSJames Smart 
24202bfdffSJames Smart 	/*
25202bfdffSJames Smart 	 * Wait for backend session registration
26202bfdffSJames Smart 	 * to complete before sending PRLI resp
27202bfdffSJames Smart 	 */
28202bfdffSJames Smart 
29202bfdffSJames Smart 	if (node->init) {
30202bfdffSJames Smart 		efc_log_info(efc, "[%s] found(initiator) WWPN:%s WWNN:%s\n",
31202bfdffSJames Smart 			     node->display_name, node->wwpn, node->wwnn);
32202bfdffSJames Smart 		if (node->nport->enable_tgt)
33202bfdffSJames Smart 			rc = efc->tt.scsi_new_node(efc, node);
34202bfdffSJames Smart 	}
35202bfdffSJames Smart 
36202bfdffSJames Smart 	if (rc < 0)
37202bfdffSJames Smart 		efc_node_post_event(node, EFC_EVT_NODE_SESS_REG_FAIL, NULL);
38202bfdffSJames Smart 
39202bfdffSJames Smart 	if (rc == EFC_SCSI_CALL_COMPLETE)
40202bfdffSJames Smart 		efc_node_post_event(node, EFC_EVT_NODE_SESS_REG_OK, NULL);
41202bfdffSJames Smart }
42202bfdffSJames Smart 
43202bfdffSJames Smart static void
__efc_d_common(const char * funcname,struct efc_sm_ctx * ctx,enum efc_sm_event evt,void * arg)44202bfdffSJames Smart __efc_d_common(const char *funcname, struct efc_sm_ctx *ctx,
45202bfdffSJames Smart 	       enum efc_sm_event evt, void *arg)
46202bfdffSJames Smart {
47202bfdffSJames Smart 	struct efc_node *node = NULL;
48202bfdffSJames Smart 	struct efc *efc = NULL;
49202bfdffSJames Smart 
50202bfdffSJames Smart 	node = ctx->app;
51202bfdffSJames Smart 	efc = node->efc;
52202bfdffSJames Smart 
53202bfdffSJames Smart 	switch (evt) {
54202bfdffSJames Smart 	/* Handle shutdown events */
55202bfdffSJames Smart 	case EFC_EVT_SHUTDOWN:
56202bfdffSJames Smart 		efc_log_debug(efc, "[%s] %-20s %-20s\n", node->display_name,
57202bfdffSJames Smart 			      funcname, efc_sm_event_name(evt));
58202bfdffSJames Smart 		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
59202bfdffSJames Smart 		efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
60202bfdffSJames Smart 		break;
61202bfdffSJames Smart 	case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
62202bfdffSJames Smart 		efc_log_debug(efc, "[%s] %-20s %-20s\n",
63202bfdffSJames Smart 			      node->display_name, funcname,
64202bfdffSJames Smart 				efc_sm_event_name(evt));
65202bfdffSJames Smart 		node->shutdown_reason = EFC_NODE_SHUTDOWN_EXPLICIT_LOGO;
66202bfdffSJames Smart 		efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
67202bfdffSJames Smart 		break;
68202bfdffSJames Smart 	case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
69202bfdffSJames Smart 		efc_log_debug(efc, "[%s] %-20s %-20s\n", node->display_name,
70202bfdffSJames Smart 			      funcname, efc_sm_event_name(evt));
71202bfdffSJames Smart 		node->shutdown_reason = EFC_NODE_SHUTDOWN_IMPLICIT_LOGO;
72202bfdffSJames Smart 		efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
73202bfdffSJames Smart 		break;
74202bfdffSJames Smart 
75202bfdffSJames Smart 	default:
76202bfdffSJames Smart 		/* call default event handler common to all nodes */
77202bfdffSJames Smart 		__efc_node_common(funcname, ctx, evt, arg);
78202bfdffSJames Smart 	}
79202bfdffSJames Smart }
80202bfdffSJames Smart 
81202bfdffSJames Smart static void
__efc_d_wait_del_node(struct efc_sm_ctx * ctx,enum efc_sm_event evt,void * arg)82202bfdffSJames Smart __efc_d_wait_del_node(struct efc_sm_ctx *ctx,
83202bfdffSJames Smart 		      enum efc_sm_event evt, void *arg)
84202bfdffSJames Smart {
85202bfdffSJames Smart 	struct efc_node *node = ctx->app;
86202bfdffSJames Smart 
87202bfdffSJames Smart 	efc_node_evt_set(ctx, evt, __func__);
88202bfdffSJames Smart 
89202bfdffSJames Smart 	/*
90202bfdffSJames Smart 	 * State is entered when a node sends a delete initiator/target call
91202bfdffSJames Smart 	 * to the target-server/initiator-client and needs to wait for that
92202bfdffSJames Smart 	 * work to complete.
93202bfdffSJames Smart 	 */
94202bfdffSJames Smart 	node_sm_trace();
95202bfdffSJames Smart 
96202bfdffSJames Smart 	switch (evt) {
97202bfdffSJames Smart 	case EFC_EVT_ENTER:
98202bfdffSJames Smart 		efc_node_hold_frames(node);
99202bfdffSJames Smart 		fallthrough;
100202bfdffSJames Smart 
101202bfdffSJames Smart 	case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
102202bfdffSJames Smart 	case EFC_EVT_ALL_CHILD_NODES_FREE:
103202bfdffSJames Smart 		/* These are expected events. */
104202bfdffSJames Smart 		break;
105202bfdffSJames Smart 
106202bfdffSJames Smart 	case EFC_EVT_NODE_DEL_INI_COMPLETE:
107202bfdffSJames Smart 	case EFC_EVT_NODE_DEL_TGT_COMPLETE:
108202bfdffSJames Smart 		/*
109202bfdffSJames Smart 		 * node has either been detached or is in the process
110202bfdffSJames Smart 		 * of being detached,
111202bfdffSJames Smart 		 * call common node's initiate cleanup function
112202bfdffSJames Smart 		 */
113202bfdffSJames Smart 		efc_node_initiate_cleanup(node);
114202bfdffSJames Smart 		break;
115202bfdffSJames Smart 
116202bfdffSJames Smart 	case EFC_EVT_EXIT:
117202bfdffSJames Smart 		efc_node_accept_frames(node);
118202bfdffSJames Smart 		break;
119202bfdffSJames Smart 
120202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_REQ_FAIL:
121202bfdffSJames Smart 		/* Can happen as ELS IO IO's complete */
122202bfdffSJames Smart 		WARN_ON(!node->els_req_cnt);
123202bfdffSJames Smart 		node->els_req_cnt--;
124202bfdffSJames Smart 		break;
125202bfdffSJames Smart 
126202bfdffSJames Smart 	/* ignore shutdown events as we're already in shutdown path */
127202bfdffSJames Smart 	case EFC_EVT_SHUTDOWN:
128202bfdffSJames Smart 		/* have default shutdown event take precedence */
129202bfdffSJames Smart 		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
130202bfdffSJames Smart 		fallthrough;
131202bfdffSJames Smart 
132202bfdffSJames Smart 	case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
133202bfdffSJames Smart 	case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
134202bfdffSJames Smart 		node_printf(node, "%s received\n", efc_sm_event_name(evt));
135202bfdffSJames Smart 		break;
136202bfdffSJames Smart 	case EFC_EVT_DOMAIN_ATTACH_OK:
137202bfdffSJames Smart 		/* don't care about domain_attach_ok */
138202bfdffSJames Smart 		break;
139202bfdffSJames Smart 	default:
140202bfdffSJames Smart 		__efc_d_common(__func__, ctx, evt, arg);
141202bfdffSJames Smart 	}
142202bfdffSJames Smart }
143202bfdffSJames Smart 
144202bfdffSJames Smart static void
__efc_d_wait_del_ini_tgt(struct efc_sm_ctx * ctx,enum efc_sm_event evt,void * arg)145202bfdffSJames Smart __efc_d_wait_del_ini_tgt(struct efc_sm_ctx *ctx,
146202bfdffSJames Smart 			 enum efc_sm_event evt, void *arg)
147202bfdffSJames Smart {
148202bfdffSJames Smart 	struct efc_node *node = ctx->app;
149202bfdffSJames Smart 
150202bfdffSJames Smart 	efc_node_evt_set(ctx, evt, __func__);
151202bfdffSJames Smart 
152202bfdffSJames Smart 	node_sm_trace();
153202bfdffSJames Smart 
154202bfdffSJames Smart 	switch (evt) {
155202bfdffSJames Smart 	case EFC_EVT_ENTER:
156202bfdffSJames Smart 		efc_node_hold_frames(node);
157202bfdffSJames Smart 		fallthrough;
158202bfdffSJames Smart 
159202bfdffSJames Smart 	case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
160202bfdffSJames Smart 	case EFC_EVT_ALL_CHILD_NODES_FREE:
161202bfdffSJames Smart 		/* These are expected events. */
162202bfdffSJames Smart 		break;
163202bfdffSJames Smart 
164202bfdffSJames Smart 	case EFC_EVT_NODE_DEL_INI_COMPLETE:
165202bfdffSJames Smart 	case EFC_EVT_NODE_DEL_TGT_COMPLETE:
166202bfdffSJames Smart 		efc_node_transition(node, __efc_d_wait_del_node, NULL);
167202bfdffSJames Smart 		break;
168202bfdffSJames Smart 
169202bfdffSJames Smart 	case EFC_EVT_EXIT:
170202bfdffSJames Smart 		efc_node_accept_frames(node);
171202bfdffSJames Smart 		break;
172202bfdffSJames Smart 
173202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_REQ_FAIL:
174202bfdffSJames Smart 		/* Can happen as ELS IO IO's complete */
175202bfdffSJames Smart 		WARN_ON(!node->els_req_cnt);
176202bfdffSJames Smart 		node->els_req_cnt--;
177202bfdffSJames Smart 		break;
178202bfdffSJames Smart 
179202bfdffSJames Smart 	/* ignore shutdown events as we're already in shutdown path */
180202bfdffSJames Smart 	case EFC_EVT_SHUTDOWN:
181202bfdffSJames Smart 		/* have default shutdown event take precedence */
182202bfdffSJames Smart 		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
183202bfdffSJames Smart 		fallthrough;
184202bfdffSJames Smart 
185202bfdffSJames Smart 	case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
186202bfdffSJames Smart 	case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
187202bfdffSJames Smart 		node_printf(node, "%s received\n", efc_sm_event_name(evt));
188202bfdffSJames Smart 		break;
189202bfdffSJames Smart 	case EFC_EVT_DOMAIN_ATTACH_OK:
190202bfdffSJames Smart 		/* don't care about domain_attach_ok */
191202bfdffSJames Smart 		break;
192202bfdffSJames Smart 	default:
193202bfdffSJames Smart 		__efc_d_common(__func__, ctx, evt, arg);
194202bfdffSJames Smart 	}
195202bfdffSJames Smart }
196202bfdffSJames Smart 
197202bfdffSJames Smart void
__efc_d_initiate_shutdown(struct efc_sm_ctx * ctx,enum efc_sm_event evt,void * arg)198202bfdffSJames Smart __efc_d_initiate_shutdown(struct efc_sm_ctx *ctx,
199202bfdffSJames Smart 			  enum efc_sm_event evt, void *arg)
200202bfdffSJames Smart {
201202bfdffSJames Smart 	struct efc_node *node = ctx->app;
202202bfdffSJames Smart 	struct efc *efc = node->efc;
203202bfdffSJames Smart 
204202bfdffSJames Smart 	efc_node_evt_set(ctx, evt, __func__);
205202bfdffSJames Smart 
206202bfdffSJames Smart 	node_sm_trace();
207202bfdffSJames Smart 
208202bfdffSJames Smart 	switch (evt) {
209202bfdffSJames Smart 	case EFC_EVT_ENTER: {
210202bfdffSJames Smart 		int rc = EFC_SCSI_CALL_COMPLETE;
211202bfdffSJames Smart 
212202bfdffSJames Smart 		/* assume no wait needed */
213202bfdffSJames Smart 		node->els_io_enabled = false;
214202bfdffSJames Smart 
215202bfdffSJames Smart 		/* make necessary delete upcall(s) */
216202bfdffSJames Smart 		if (node->init && !node->targ) {
217202bfdffSJames Smart 			efc_log_info(node->efc,
218202bfdffSJames Smart 				     "[%s] delete (initiator) WWPN %s WWNN %s\n",
219202bfdffSJames Smart 				node->display_name,
220202bfdffSJames Smart 				node->wwpn, node->wwnn);
221202bfdffSJames Smart 			efc_node_transition(node,
222202bfdffSJames Smart 					    __efc_d_wait_del_node,
223202bfdffSJames Smart 					     NULL);
224202bfdffSJames Smart 			if (node->nport->enable_tgt)
225202bfdffSJames Smart 				rc = efc->tt.scsi_del_node(efc, node,
226202bfdffSJames Smart 					EFC_SCSI_INITIATOR_DELETED);
227202bfdffSJames Smart 
228202bfdffSJames Smart 			if (rc == EFC_SCSI_CALL_COMPLETE || rc < 0)
229202bfdffSJames Smart 				efc_node_post_event(node,
230202bfdffSJames Smart 					EFC_EVT_NODE_DEL_INI_COMPLETE, NULL);
231202bfdffSJames Smart 
232202bfdffSJames Smart 		} else if (node->targ && !node->init) {
233202bfdffSJames Smart 			efc_log_info(node->efc,
234202bfdffSJames Smart 				     "[%s] delete (target) WWPN %s WWNN %s\n",
235202bfdffSJames Smart 				node->display_name,
236202bfdffSJames Smart 				node->wwpn, node->wwnn);
237202bfdffSJames Smart 			efc_node_transition(node,
238202bfdffSJames Smart 					    __efc_d_wait_del_node,
239202bfdffSJames Smart 					     NULL);
240202bfdffSJames Smart 			if (node->nport->enable_ini)
241202bfdffSJames Smart 				rc = efc->tt.scsi_del_node(efc, node,
242202bfdffSJames Smart 					EFC_SCSI_TARGET_DELETED);
243202bfdffSJames Smart 
244202bfdffSJames Smart 			if (rc == EFC_SCSI_CALL_COMPLETE)
245202bfdffSJames Smart 				efc_node_post_event(node,
246202bfdffSJames Smart 					EFC_EVT_NODE_DEL_TGT_COMPLETE, NULL);
247202bfdffSJames Smart 
248202bfdffSJames Smart 		} else if (node->init && node->targ) {
249202bfdffSJames Smart 			efc_log_info(node->efc,
250202bfdffSJames Smart 				     "[%s] delete (I+T) WWPN %s WWNN %s\n",
251202bfdffSJames Smart 				node->display_name, node->wwpn, node->wwnn);
252202bfdffSJames Smart 			efc_node_transition(node, __efc_d_wait_del_ini_tgt,
253202bfdffSJames Smart 					    NULL);
254202bfdffSJames Smart 			if (node->nport->enable_tgt)
255202bfdffSJames Smart 				rc = efc->tt.scsi_del_node(efc, node,
256202bfdffSJames Smart 						EFC_SCSI_INITIATOR_DELETED);
257202bfdffSJames Smart 
258202bfdffSJames Smart 			if (rc == EFC_SCSI_CALL_COMPLETE)
259202bfdffSJames Smart 				efc_node_post_event(node,
260202bfdffSJames Smart 					EFC_EVT_NODE_DEL_INI_COMPLETE, NULL);
261202bfdffSJames Smart 			/* assume no wait needed */
262202bfdffSJames Smart 			rc = EFC_SCSI_CALL_COMPLETE;
263202bfdffSJames Smart 			if (node->nport->enable_ini)
264202bfdffSJames Smart 				rc = efc->tt.scsi_del_node(efc, node,
265202bfdffSJames Smart 						EFC_SCSI_TARGET_DELETED);
266202bfdffSJames Smart 
267202bfdffSJames Smart 			if (rc == EFC_SCSI_CALL_COMPLETE)
268202bfdffSJames Smart 				efc_node_post_event(node,
269202bfdffSJames Smart 					EFC_EVT_NODE_DEL_TGT_COMPLETE, NULL);
270202bfdffSJames Smart 		}
271202bfdffSJames Smart 
272202bfdffSJames Smart 		/* we've initiated the upcalls as needed, now kick off the node
273202bfdffSJames Smart 		 * detach to precipitate the aborting of outstanding exchanges
274202bfdffSJames Smart 		 * associated with said node
275202bfdffSJames Smart 		 *
276202bfdffSJames Smart 		 * Beware: if we've made upcall(s), we've already transitioned
277202bfdffSJames Smart 		 * to a new state by the time we execute this.
278202bfdffSJames Smart 		 * consider doing this before the upcalls?
279202bfdffSJames Smart 		 */
280202bfdffSJames Smart 		if (node->attached) {
281202bfdffSJames Smart 			/* issue hw node free; don't care if succeeds right
282202bfdffSJames Smart 			 * away or sometime later, will check node->attached
283202bfdffSJames Smart 			 * later in shutdown process
284202bfdffSJames Smart 			 */
285202bfdffSJames Smart 			rc = efc_cmd_node_detach(efc, &node->rnode);
286202bfdffSJames Smart 			if (rc < 0)
287202bfdffSJames Smart 				node_printf(node,
288202bfdffSJames Smart 					    "Failed freeing HW node, rc=%d\n",
289202bfdffSJames Smart 					rc);
290202bfdffSJames Smart 		}
291202bfdffSJames Smart 
292202bfdffSJames Smart 		/* if neither initiator nor target, proceed to cleanup */
293202bfdffSJames Smart 		if (!node->init && !node->targ) {
294202bfdffSJames Smart 			/*
295202bfdffSJames Smart 			 * node has either been detached or is in
296202bfdffSJames Smart 			 * the process of being detached,
297202bfdffSJames Smart 			 * call common node's initiate cleanup function
298202bfdffSJames Smart 			 */
299202bfdffSJames Smart 			efc_node_initiate_cleanup(node);
300202bfdffSJames Smart 		}
301202bfdffSJames Smart 		break;
302202bfdffSJames Smart 	}
303202bfdffSJames Smart 	case EFC_EVT_ALL_CHILD_NODES_FREE:
304202bfdffSJames Smart 		/* Ignore, this can happen if an ELS is
305202bfdffSJames Smart 		 * aborted while in a delay/retry state
306202bfdffSJames Smart 		 */
307202bfdffSJames Smart 		break;
308202bfdffSJames Smart 	default:
309202bfdffSJames Smart 		__efc_d_common(__func__, ctx, evt, arg);
310202bfdffSJames Smart 	}
311202bfdffSJames Smart }
312202bfdffSJames Smart 
313202bfdffSJames Smart void
__efc_d_wait_loop(struct efc_sm_ctx * ctx,enum efc_sm_event evt,void * arg)314202bfdffSJames Smart __efc_d_wait_loop(struct efc_sm_ctx *ctx,
315202bfdffSJames Smart 		  enum efc_sm_event evt, void *arg)
316202bfdffSJames Smart {
317202bfdffSJames Smart 	struct efc_node *node = ctx->app;
318202bfdffSJames Smart 
319202bfdffSJames Smart 	efc_node_evt_set(ctx, evt, __func__);
320202bfdffSJames Smart 
321202bfdffSJames Smart 	node_sm_trace();
322202bfdffSJames Smart 
323202bfdffSJames Smart 	switch (evt) {
324202bfdffSJames Smart 	case EFC_EVT_ENTER:
325202bfdffSJames Smart 		efc_node_hold_frames(node);
326202bfdffSJames Smart 		break;
327202bfdffSJames Smart 
328202bfdffSJames Smart 	case EFC_EVT_EXIT:
329202bfdffSJames Smart 		efc_node_accept_frames(node);
330202bfdffSJames Smart 		break;
331202bfdffSJames Smart 
332202bfdffSJames Smart 	case EFC_EVT_DOMAIN_ATTACH_OK: {
333202bfdffSJames Smart 		/* send PLOGI automatically if initiator */
334202bfdffSJames Smart 		efc_node_init_device(node, true);
335202bfdffSJames Smart 		break;
336202bfdffSJames Smart 	}
337202bfdffSJames Smart 	default:
338202bfdffSJames Smart 		__efc_d_common(__func__, ctx, evt, arg);
339202bfdffSJames Smart 	}
340202bfdffSJames Smart }
341202bfdffSJames Smart 
342202bfdffSJames Smart void
efc_send_ls_acc_after_attach(struct efc_node * node,struct fc_frame_header * hdr,enum efc_node_send_ls_acc ls)343202bfdffSJames Smart efc_send_ls_acc_after_attach(struct efc_node *node,
344202bfdffSJames Smart 			     struct fc_frame_header *hdr,
345202bfdffSJames Smart 			     enum efc_node_send_ls_acc ls)
346202bfdffSJames Smart {
347202bfdffSJames Smart 	u16 ox_id = be16_to_cpu(hdr->fh_ox_id);
348202bfdffSJames Smart 
349202bfdffSJames Smart 	/* Save the OX_ID for sending LS_ACC sometime later */
350202bfdffSJames Smart 	WARN_ON(node->send_ls_acc != EFC_NODE_SEND_LS_ACC_NONE);
351202bfdffSJames Smart 
352202bfdffSJames Smart 	node->ls_acc_oxid = ox_id;
353202bfdffSJames Smart 	node->send_ls_acc = ls;
354202bfdffSJames Smart 	node->ls_acc_did = ntoh24(hdr->fh_d_id);
355202bfdffSJames Smart }
356202bfdffSJames Smart 
357202bfdffSJames Smart void
efc_process_prli_payload(struct efc_node * node,void * prli)358202bfdffSJames Smart efc_process_prli_payload(struct efc_node *node, void *prli)
359202bfdffSJames Smart {
360202bfdffSJames Smart 	struct {
361202bfdffSJames Smart 		struct fc_els_prli prli;
362202bfdffSJames Smart 		struct fc_els_spp sp;
363202bfdffSJames Smart 	} *pp;
364202bfdffSJames Smart 
365202bfdffSJames Smart 	pp = prli;
366202bfdffSJames Smart 	node->init = (pp->sp.spp_flags & FCP_SPPF_INIT_FCN) != 0;
367202bfdffSJames Smart 	node->targ = (pp->sp.spp_flags & FCP_SPPF_TARG_FCN) != 0;
368202bfdffSJames Smart }
369202bfdffSJames Smart 
370202bfdffSJames Smart void
__efc_d_wait_plogi_acc_cmpl(struct efc_sm_ctx * ctx,enum efc_sm_event evt,void * arg)371202bfdffSJames Smart __efc_d_wait_plogi_acc_cmpl(struct efc_sm_ctx *ctx,
372202bfdffSJames Smart 			    enum efc_sm_event evt, void *arg)
373202bfdffSJames Smart {
374202bfdffSJames Smart 	struct efc_node *node = ctx->app;
375202bfdffSJames Smart 
376202bfdffSJames Smart 	efc_node_evt_set(ctx, evt, __func__);
377202bfdffSJames Smart 
378202bfdffSJames Smart 	node_sm_trace();
379202bfdffSJames Smart 
380202bfdffSJames Smart 	switch (evt) {
381202bfdffSJames Smart 	case EFC_EVT_ENTER:
382202bfdffSJames Smart 		efc_node_hold_frames(node);
383202bfdffSJames Smart 		break;
384202bfdffSJames Smart 
385202bfdffSJames Smart 	case EFC_EVT_EXIT:
386202bfdffSJames Smart 		efc_node_accept_frames(node);
387202bfdffSJames Smart 		break;
388202bfdffSJames Smart 
389202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_CMPL_FAIL:
390202bfdffSJames Smart 		WARN_ON(!node->els_cmpl_cnt);
391202bfdffSJames Smart 		node->els_cmpl_cnt--;
392202bfdffSJames Smart 		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
393202bfdffSJames Smart 		efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
394202bfdffSJames Smart 		break;
395202bfdffSJames Smart 
396202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_CMPL_OK:	/* PLOGI ACC completions */
397202bfdffSJames Smart 		WARN_ON(!node->els_cmpl_cnt);
398202bfdffSJames Smart 		node->els_cmpl_cnt--;
399202bfdffSJames Smart 		efc_node_transition(node, __efc_d_port_logged_in, NULL);
400202bfdffSJames Smart 		break;
401202bfdffSJames Smart 
402202bfdffSJames Smart 	default:
403202bfdffSJames Smart 		__efc_d_common(__func__, ctx, evt, arg);
404202bfdffSJames Smart 	}
405202bfdffSJames Smart }
406202bfdffSJames Smart 
407202bfdffSJames Smart void
__efc_d_wait_logo_rsp(struct efc_sm_ctx * ctx,enum efc_sm_event evt,void * arg)408202bfdffSJames Smart __efc_d_wait_logo_rsp(struct efc_sm_ctx *ctx,
409202bfdffSJames Smart 		      enum efc_sm_event evt, void *arg)
410202bfdffSJames Smart {
411202bfdffSJames Smart 	struct efc_node *node = ctx->app;
412202bfdffSJames Smart 
413202bfdffSJames Smart 	efc_node_evt_set(ctx, evt, __func__);
414202bfdffSJames Smart 
415202bfdffSJames Smart 	node_sm_trace();
416202bfdffSJames Smart 
417202bfdffSJames Smart 	switch (evt) {
418202bfdffSJames Smart 	case EFC_EVT_ENTER:
419202bfdffSJames Smart 		efc_node_hold_frames(node);
420202bfdffSJames Smart 		break;
421202bfdffSJames Smart 
422202bfdffSJames Smart 	case EFC_EVT_EXIT:
423202bfdffSJames Smart 		efc_node_accept_frames(node);
424202bfdffSJames Smart 		break;
425202bfdffSJames Smart 
426202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_REQ_OK:
427202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_REQ_RJT:
428202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_REQ_FAIL:
429202bfdffSJames Smart 		/* LOGO response received, sent shutdown */
430202bfdffSJames Smart 		if (efc_node_check_els_req(ctx, evt, arg, ELS_LOGO,
431202bfdffSJames Smart 					   __efc_d_common, __func__))
432202bfdffSJames Smart 			return;
433202bfdffSJames Smart 
434202bfdffSJames Smart 		WARN_ON(!node->els_req_cnt);
435202bfdffSJames Smart 		node->els_req_cnt--;
436202bfdffSJames Smart 		node_printf(node,
437202bfdffSJames Smart 			    "LOGO sent (evt=%s), shutdown node\n",
438202bfdffSJames Smart 			efc_sm_event_name(evt));
439202bfdffSJames Smart 		/* sm: / post explicit logout */
440202bfdffSJames Smart 		efc_node_post_event(node, EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
441202bfdffSJames Smart 				    NULL);
442202bfdffSJames Smart 		break;
443202bfdffSJames Smart 
444202bfdffSJames Smart 	default:
445202bfdffSJames Smart 		__efc_d_common(__func__, ctx, evt, arg);
446202bfdffSJames Smart 	}
447202bfdffSJames Smart }
448202bfdffSJames Smart 
449202bfdffSJames Smart void
efc_node_init_device(struct efc_node * node,bool send_plogi)450202bfdffSJames Smart efc_node_init_device(struct efc_node *node, bool send_plogi)
451202bfdffSJames Smart {
452202bfdffSJames Smart 	node->send_plogi = send_plogi;
453202bfdffSJames Smart 	if ((node->efc->nodedb_mask & EFC_NODEDB_PAUSE_NEW_NODES) &&
454202bfdffSJames Smart 	    (node->rnode.fc_id != FC_FID_DOM_MGR)) {
455202bfdffSJames Smart 		node->nodedb_state = __efc_d_init;
456202bfdffSJames Smart 		efc_node_transition(node, __efc_node_paused, NULL);
457202bfdffSJames Smart 	} else {
458202bfdffSJames Smart 		efc_node_transition(node, __efc_d_init, NULL);
459202bfdffSJames Smart 	}
460202bfdffSJames Smart }
461202bfdffSJames Smart 
462202bfdffSJames Smart static void
efc_d_check_plogi_topology(struct efc_node * node,u32 d_id)463202bfdffSJames Smart efc_d_check_plogi_topology(struct efc_node *node, u32 d_id)
464202bfdffSJames Smart {
465202bfdffSJames Smart 	switch (node->nport->topology) {
466202bfdffSJames Smart 	case EFC_NPORT_TOPO_P2P:
467202bfdffSJames Smart 		/* we're not attached and nport is p2p,
468202bfdffSJames Smart 		 * need to attach
469202bfdffSJames Smart 		 */
470202bfdffSJames Smart 		efc_domain_attach(node->nport->domain, d_id);
471202bfdffSJames Smart 		efc_node_transition(node, __efc_d_wait_domain_attach, NULL);
472202bfdffSJames Smart 		break;
473202bfdffSJames Smart 	case EFC_NPORT_TOPO_FABRIC:
474202bfdffSJames Smart 		/* we're not attached and nport is fabric, domain
475202bfdffSJames Smart 		 * attach should have already been requested as part
476202bfdffSJames Smart 		 * of the fabric state machine, wait for it
477202bfdffSJames Smart 		 */
478202bfdffSJames Smart 		efc_node_transition(node, __efc_d_wait_domain_attach, NULL);
479202bfdffSJames Smart 		break;
480202bfdffSJames Smart 	case EFC_NPORT_TOPO_UNKNOWN:
481202bfdffSJames Smart 		/* Two possibilities:
482202bfdffSJames Smart 		 * 1. received a PLOGI before our FLOGI has completed
483202bfdffSJames Smart 		 *    (possible since completion comes in on another
484202bfdffSJames Smart 		 *    CQ), thus we don't know what we're connected to
485202bfdffSJames Smart 		 *    yet; transition to a state to wait for the
486202bfdffSJames Smart 		 *    fabric node to tell us;
487202bfdffSJames Smart 		 * 2. PLOGI received before link went down and we
488202bfdffSJames Smart 		 * haven't performed domain attach yet.
489202bfdffSJames Smart 		 * Note: we cannot distinguish between 1. and 2.
490202bfdffSJames Smart 		 * so have to assume PLOGI
491202bfdffSJames Smart 		 * was received after link back up.
492202bfdffSJames Smart 		 */
493202bfdffSJames Smart 		node_printf(node, "received PLOGI, unknown topology did=0x%x\n",
494202bfdffSJames Smart 			    d_id);
495202bfdffSJames Smart 		efc_node_transition(node, __efc_d_wait_topology_notify, NULL);
496202bfdffSJames Smart 		break;
497202bfdffSJames Smart 	default:
498202bfdffSJames Smart 		node_printf(node, "received PLOGI, unexpected topology %d\n",
499202bfdffSJames Smart 			    node->nport->topology);
500202bfdffSJames Smart 	}
501202bfdffSJames Smart }
502202bfdffSJames Smart 
503202bfdffSJames Smart void
__efc_d_init(struct efc_sm_ctx * ctx,enum efc_sm_event evt,void * arg)504202bfdffSJames Smart __efc_d_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg)
505202bfdffSJames Smart {
506202bfdffSJames Smart 	struct efc_node_cb *cbdata = arg;
507202bfdffSJames Smart 	struct efc_node *node = ctx->app;
508202bfdffSJames Smart 
509202bfdffSJames Smart 	efc_node_evt_set(ctx, evt, __func__);
510202bfdffSJames Smart 
511202bfdffSJames Smart 	node_sm_trace();
512202bfdffSJames Smart 
513202bfdffSJames Smart 	/*
514202bfdffSJames Smart 	 * This state is entered when a node is instantiated,
515202bfdffSJames Smart 	 * either having been discovered from a name services query,
516202bfdffSJames Smart 	 * or having received a PLOGI/FLOGI.
517202bfdffSJames Smart 	 */
518202bfdffSJames Smart 	switch (evt) {
519202bfdffSJames Smart 	case EFC_EVT_ENTER:
520202bfdffSJames Smart 		if (!node->send_plogi)
521202bfdffSJames Smart 			break;
522202bfdffSJames Smart 		/* only send if we have initiator capability,
523202bfdffSJames Smart 		 * and domain is attached
524202bfdffSJames Smart 		 */
525202bfdffSJames Smart 		if (node->nport->enable_ini &&
526202bfdffSJames Smart 		    node->nport->domain->attached) {
527202bfdffSJames Smart 			efc_send_plogi(node);
528202bfdffSJames Smart 
529202bfdffSJames Smart 			efc_node_transition(node, __efc_d_wait_plogi_rsp, NULL);
530202bfdffSJames Smart 		} else {
531202bfdffSJames Smart 			node_printf(node, "not sending plogi nport.ini=%d,",
532202bfdffSJames Smart 				    node->nport->enable_ini);
533202bfdffSJames Smart 			node_printf(node, "domain attached=%d\n",
534202bfdffSJames Smart 				    node->nport->domain->attached);
535202bfdffSJames Smart 		}
536202bfdffSJames Smart 		break;
537202bfdffSJames Smart 	case EFC_EVT_PLOGI_RCVD: {
538202bfdffSJames Smart 		/* T, or I+T */
539202bfdffSJames Smart 		struct fc_frame_header *hdr = cbdata->header->dma.virt;
540202bfdffSJames Smart 		int rc;
541202bfdffSJames Smart 
542202bfdffSJames Smart 		efc_node_save_sparms(node, cbdata->payload->dma.virt);
543202bfdffSJames Smart 		efc_send_ls_acc_after_attach(node,
544202bfdffSJames Smart 					     cbdata->header->dma.virt,
545202bfdffSJames Smart 					     EFC_NODE_SEND_LS_ACC_PLOGI);
546202bfdffSJames Smart 
547202bfdffSJames Smart 		/* domain not attached; several possibilities: */
548202bfdffSJames Smart 		if (!node->nport->domain->attached) {
549202bfdffSJames Smart 			efc_d_check_plogi_topology(node, ntoh24(hdr->fh_d_id));
550202bfdffSJames Smart 			break;
551202bfdffSJames Smart 		}
552202bfdffSJames Smart 
553202bfdffSJames Smart 		/* domain already attached */
554202bfdffSJames Smart 		rc = efc_node_attach(node);
555202bfdffSJames Smart 		efc_node_transition(node, __efc_d_wait_node_attach, NULL);
556202bfdffSJames Smart 		if (rc < 0)
557202bfdffSJames Smart 			efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL, NULL);
558202bfdffSJames Smart 
559202bfdffSJames Smart 		break;
560202bfdffSJames Smart 	}
561202bfdffSJames Smart 
562202bfdffSJames Smart 	case EFC_EVT_FDISC_RCVD: {
563202bfdffSJames Smart 		__efc_d_common(__func__, ctx, evt, arg);
564202bfdffSJames Smart 		break;
565202bfdffSJames Smart 	}
566202bfdffSJames Smart 
567202bfdffSJames Smart 	case EFC_EVT_FLOGI_RCVD: {
568202bfdffSJames Smart 		struct fc_frame_header *hdr = cbdata->header->dma.virt;
569202bfdffSJames Smart 		u32 d_id = ntoh24(hdr->fh_d_id);
570202bfdffSJames Smart 
571202bfdffSJames Smart 		/* sm: / save sparams, send FLOGI acc */
572202bfdffSJames Smart 		memcpy(node->nport->domain->flogi_service_params,
573202bfdffSJames Smart 		       cbdata->payload->dma.virt,
574202bfdffSJames Smart 		       sizeof(struct fc_els_flogi));
575202bfdffSJames Smart 
576202bfdffSJames Smart 		/* send FC LS_ACC response, override s_id */
577202bfdffSJames Smart 		efc_fabric_set_topology(node, EFC_NPORT_TOPO_P2P);
578202bfdffSJames Smart 
579202bfdffSJames Smart 		efc_send_flogi_p2p_acc(node, be16_to_cpu(hdr->fh_ox_id), d_id);
580202bfdffSJames Smart 
581202bfdffSJames Smart 		if (efc_p2p_setup(node->nport)) {
582202bfdffSJames Smart 			node_printf(node, "p2p failed, shutting down node\n");
583202bfdffSJames Smart 			efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
584202bfdffSJames Smart 			break;
585202bfdffSJames Smart 		}
586202bfdffSJames Smart 
587202bfdffSJames Smart 		efc_node_transition(node,  __efc_p2p_wait_flogi_acc_cmpl, NULL);
588202bfdffSJames Smart 		break;
589202bfdffSJames Smart 	}
590202bfdffSJames Smart 
591202bfdffSJames Smart 	case EFC_EVT_LOGO_RCVD: {
592202bfdffSJames Smart 		struct fc_frame_header *hdr = cbdata->header->dma.virt;
593202bfdffSJames Smart 
594202bfdffSJames Smart 		if (!node->nport->domain->attached) {
595202bfdffSJames Smart 			/* most likely a frame left over from before a link
596202bfdffSJames Smart 			 * down; drop and
597202bfdffSJames Smart 			 * shut node down w/ "explicit logout" so pending
598202bfdffSJames Smart 			 * frames are processed
599202bfdffSJames Smart 			 */
600202bfdffSJames Smart 			node_printf(node, "%s domain not attached, dropping\n",
601202bfdffSJames Smart 				    efc_sm_event_name(evt));
602202bfdffSJames Smart 			efc_node_post_event(node,
603202bfdffSJames Smart 					EFC_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
604202bfdffSJames Smart 			break;
605202bfdffSJames Smart 		}
606202bfdffSJames Smart 
607202bfdffSJames Smart 		efc_send_logo_acc(node, be16_to_cpu(hdr->fh_ox_id));
608202bfdffSJames Smart 		efc_node_transition(node, __efc_d_wait_logo_acc_cmpl, NULL);
609202bfdffSJames Smart 		break;
610202bfdffSJames Smart 	}
611202bfdffSJames Smart 
612202bfdffSJames Smart 	case EFC_EVT_PRLI_RCVD:
613202bfdffSJames Smart 	case EFC_EVT_PRLO_RCVD:
614202bfdffSJames Smart 	case EFC_EVT_PDISC_RCVD:
615202bfdffSJames Smart 	case EFC_EVT_ADISC_RCVD:
616202bfdffSJames Smart 	case EFC_EVT_RSCN_RCVD: {
617202bfdffSJames Smart 		struct fc_frame_header *hdr = cbdata->header->dma.virt;
618202bfdffSJames Smart 
619202bfdffSJames Smart 		if (!node->nport->domain->attached) {
620202bfdffSJames Smart 			/* most likely a frame left over from before a link
621202bfdffSJames Smart 			 * down; drop and shut node down w/ "explicit logout"
622202bfdffSJames Smart 			 * so pending frames are processed
623202bfdffSJames Smart 			 */
624202bfdffSJames Smart 			node_printf(node, "%s domain not attached, dropping\n",
625202bfdffSJames Smart 				    efc_sm_event_name(evt));
626202bfdffSJames Smart 
627202bfdffSJames Smart 			efc_node_post_event(node,
628202bfdffSJames Smart 					    EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
629202bfdffSJames Smart 					    NULL);
630202bfdffSJames Smart 			break;
631202bfdffSJames Smart 		}
632202bfdffSJames Smart 		node_printf(node, "%s received, sending reject\n",
633202bfdffSJames Smart 			    efc_sm_event_name(evt));
634202bfdffSJames Smart 
635202bfdffSJames Smart 		efc_send_ls_rjt(node, be16_to_cpu(hdr->fh_ox_id),
636202bfdffSJames Smart 				ELS_RJT_UNAB, ELS_EXPL_PLOGI_REQD, 0);
637202bfdffSJames Smart 
638202bfdffSJames Smart 		break;
639202bfdffSJames Smart 	}
640202bfdffSJames Smart 
641202bfdffSJames Smart 	case EFC_EVT_FCP_CMD_RCVD: {
642202bfdffSJames Smart 		/* note: problem, we're now expecting an ELS REQ completion
643202bfdffSJames Smart 		 * from both the LOGO and PLOGI
644202bfdffSJames Smart 		 */
645202bfdffSJames Smart 		if (!node->nport->domain->attached) {
646202bfdffSJames Smart 			/* most likely a frame left over from before a
647202bfdffSJames Smart 			 * link down; drop and
648202bfdffSJames Smart 			 * shut node down w/ "explicit logout" so pending
649202bfdffSJames Smart 			 * frames are processed
650202bfdffSJames Smart 			 */
651202bfdffSJames Smart 			node_printf(node, "%s domain not attached, dropping\n",
652202bfdffSJames Smart 				    efc_sm_event_name(evt));
653202bfdffSJames Smart 			efc_node_post_event(node,
654202bfdffSJames Smart 					    EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
655202bfdffSJames Smart 					    NULL);
656202bfdffSJames Smart 			break;
657202bfdffSJames Smart 		}
658202bfdffSJames Smart 
659202bfdffSJames Smart 		/* Send LOGO */
660202bfdffSJames Smart 		node_printf(node, "FCP_CMND received, send LOGO\n");
661202bfdffSJames Smart 		if (efc_send_logo(node)) {
662202bfdffSJames Smart 			/*
663202bfdffSJames Smart 			 * failed to send LOGO, go ahead and cleanup node
664202bfdffSJames Smart 			 * anyways
665202bfdffSJames Smart 			 */
666202bfdffSJames Smart 			node_printf(node, "Failed to send LOGO\n");
667202bfdffSJames Smart 			efc_node_post_event(node,
668202bfdffSJames Smart 					    EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
669202bfdffSJames Smart 					    NULL);
670202bfdffSJames Smart 		} else {
671202bfdffSJames Smart 			/* sent LOGO, wait for response */
672202bfdffSJames Smart 			efc_node_transition(node,
673202bfdffSJames Smart 					    __efc_d_wait_logo_rsp, NULL);
674202bfdffSJames Smart 		}
675202bfdffSJames Smart 		break;
676202bfdffSJames Smart 	}
677202bfdffSJames Smart 	case EFC_EVT_DOMAIN_ATTACH_OK:
678202bfdffSJames Smart 		/* don't care about domain_attach_ok */
679202bfdffSJames Smart 		break;
680202bfdffSJames Smart 
681202bfdffSJames Smart 	default:
682202bfdffSJames Smart 		__efc_d_common(__func__, ctx, evt, arg);
683202bfdffSJames Smart 	}
684202bfdffSJames Smart }
685202bfdffSJames Smart 
686202bfdffSJames Smart void
__efc_d_wait_plogi_rsp(struct efc_sm_ctx * ctx,enum efc_sm_event evt,void * arg)687202bfdffSJames Smart __efc_d_wait_plogi_rsp(struct efc_sm_ctx *ctx,
688202bfdffSJames Smart 		       enum efc_sm_event evt, void *arg)
689202bfdffSJames Smart {
690202bfdffSJames Smart 	int rc;
691202bfdffSJames Smart 	struct efc_node_cb *cbdata = arg;
692202bfdffSJames Smart 	struct efc_node *node = ctx->app;
693202bfdffSJames Smart 
694202bfdffSJames Smart 	efc_node_evt_set(ctx, evt, __func__);
695202bfdffSJames Smart 
696202bfdffSJames Smart 	node_sm_trace();
697202bfdffSJames Smart 
698202bfdffSJames Smart 	switch (evt) {
699202bfdffSJames Smart 	case EFC_EVT_PLOGI_RCVD: {
700202bfdffSJames Smart 		/* T, or I+T */
701202bfdffSJames Smart 		/* received PLOGI with svc parms, go ahead and attach node
702202bfdffSJames Smart 		 * when PLOGI that was sent ultimately completes, it'll be a
703202bfdffSJames Smart 		 * no-op
704202bfdffSJames Smart 		 *
705202bfdffSJames Smart 		 * If there is an outstanding PLOGI sent, can we set a flag
706202bfdffSJames Smart 		 * to indicate that we don't want to retry it if it times out?
707202bfdffSJames Smart 		 */
708202bfdffSJames Smart 		efc_node_save_sparms(node, cbdata->payload->dma.virt);
709202bfdffSJames Smart 		efc_send_ls_acc_after_attach(node,
710202bfdffSJames Smart 					     cbdata->header->dma.virt,
711202bfdffSJames Smart 				EFC_NODE_SEND_LS_ACC_PLOGI);
712202bfdffSJames Smart 		/* sm: domain->attached / efc_node_attach */
713202bfdffSJames Smart 		rc = efc_node_attach(node);
714202bfdffSJames Smart 		efc_node_transition(node, __efc_d_wait_node_attach, NULL);
715202bfdffSJames Smart 		if (rc < 0)
716202bfdffSJames Smart 			efc_node_post_event(node,
717202bfdffSJames Smart 					    EFC_EVT_NODE_ATTACH_FAIL, NULL);
718202bfdffSJames Smart 
719202bfdffSJames Smart 		break;
720202bfdffSJames Smart 	}
721202bfdffSJames Smart 
722202bfdffSJames Smart 	case EFC_EVT_PRLI_RCVD:
723202bfdffSJames Smart 		/* I, or I+T */
724202bfdffSJames Smart 		/* sent PLOGI and before completion was seen, received the
725202bfdffSJames Smart 		 * PRLI from the remote node (WCQEs and RCQEs come in on
726202bfdffSJames Smart 		 * different queues and order of processing cannot be assumed)
727202bfdffSJames Smart 		 * Save OXID so PRLI can be sent after the attach and continue
728202bfdffSJames Smart 		 * to wait for PLOGI response
729202bfdffSJames Smart 		 */
730202bfdffSJames Smart 		efc_process_prli_payload(node, cbdata->payload->dma.virt);
731202bfdffSJames Smart 		efc_send_ls_acc_after_attach(node,
732202bfdffSJames Smart 					     cbdata->header->dma.virt,
733202bfdffSJames Smart 				EFC_NODE_SEND_LS_ACC_PRLI);
734202bfdffSJames Smart 		efc_node_transition(node, __efc_d_wait_plogi_rsp_recvd_prli,
735202bfdffSJames Smart 				    NULL);
736202bfdffSJames Smart 		break;
737202bfdffSJames Smart 
738202bfdffSJames Smart 	case EFC_EVT_LOGO_RCVD: /* why don't we do a shutdown here?? */
739202bfdffSJames Smart 	case EFC_EVT_PRLO_RCVD:
740202bfdffSJames Smart 	case EFC_EVT_PDISC_RCVD:
741202bfdffSJames Smart 	case EFC_EVT_FDISC_RCVD:
742202bfdffSJames Smart 	case EFC_EVT_ADISC_RCVD:
743202bfdffSJames Smart 	case EFC_EVT_RSCN_RCVD:
744202bfdffSJames Smart 	case EFC_EVT_SCR_RCVD: {
745202bfdffSJames Smart 		struct fc_frame_header *hdr = cbdata->header->dma.virt;
746202bfdffSJames Smart 
747202bfdffSJames Smart 		node_printf(node, "%s received, sending reject\n",
748202bfdffSJames Smart 			    efc_sm_event_name(evt));
749202bfdffSJames Smart 
750202bfdffSJames Smart 		efc_send_ls_rjt(node, be16_to_cpu(hdr->fh_ox_id),
751202bfdffSJames Smart 				ELS_RJT_UNAB, ELS_EXPL_PLOGI_REQD, 0);
752202bfdffSJames Smart 
753202bfdffSJames Smart 		break;
754202bfdffSJames Smart 	}
755202bfdffSJames Smart 
756202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_REQ_OK:	/* PLOGI response received */
757202bfdffSJames Smart 		/* Completion from PLOGI sent */
758202bfdffSJames Smart 		if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
759202bfdffSJames Smart 					   __efc_d_common, __func__))
760202bfdffSJames Smart 			return;
761202bfdffSJames Smart 
762202bfdffSJames Smart 		WARN_ON(!node->els_req_cnt);
763202bfdffSJames Smart 		node->els_req_cnt--;
764202bfdffSJames Smart 		/* sm: / save sparams, efc_node_attach */
765202bfdffSJames Smart 		efc_node_save_sparms(node, cbdata->els_rsp.virt);
766202bfdffSJames Smart 		rc = efc_node_attach(node);
767202bfdffSJames Smart 		efc_node_transition(node, __efc_d_wait_node_attach, NULL);
768202bfdffSJames Smart 		if (rc < 0)
769202bfdffSJames Smart 			efc_node_post_event(node,
770202bfdffSJames Smart 					    EFC_EVT_NODE_ATTACH_FAIL, NULL);
771202bfdffSJames Smart 
772202bfdffSJames Smart 		break;
773202bfdffSJames Smart 
774202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_REQ_FAIL:	/* PLOGI response received */
775202bfdffSJames Smart 		/* PLOGI failed, shutdown the node */
776202bfdffSJames Smart 		if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
777202bfdffSJames Smart 					   __efc_d_common, __func__))
778202bfdffSJames Smart 			return;
779202bfdffSJames Smart 
780202bfdffSJames Smart 		WARN_ON(!node->els_req_cnt);
781202bfdffSJames Smart 		node->els_req_cnt--;
782202bfdffSJames Smart 		efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
783202bfdffSJames Smart 		break;
784202bfdffSJames Smart 
785202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_REQ_RJT:
786202bfdffSJames Smart 		/* Our PLOGI was rejected, this is ok in some cases */
787202bfdffSJames Smart 		if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
788202bfdffSJames Smart 					   __efc_d_common, __func__))
789202bfdffSJames Smart 			return;
790202bfdffSJames Smart 
791202bfdffSJames Smart 		WARN_ON(!node->els_req_cnt);
792202bfdffSJames Smart 		node->els_req_cnt--;
793202bfdffSJames Smart 		break;
794202bfdffSJames Smart 
795202bfdffSJames Smart 	case EFC_EVT_FCP_CMD_RCVD: {
796202bfdffSJames Smart 		/* not logged in yet and outstanding PLOGI so don't send LOGO,
797202bfdffSJames Smart 		 * just drop
798202bfdffSJames Smart 		 */
799202bfdffSJames Smart 		node_printf(node, "FCP_CMND received, drop\n");
800202bfdffSJames Smart 		break;
801202bfdffSJames Smart 	}
802202bfdffSJames Smart 
803202bfdffSJames Smart 	default:
804202bfdffSJames Smart 		__efc_d_common(__func__, ctx, evt, arg);
805202bfdffSJames Smart 	}
806202bfdffSJames Smart }
807202bfdffSJames Smart 
808202bfdffSJames Smart void
__efc_d_wait_plogi_rsp_recvd_prli(struct efc_sm_ctx * ctx,enum efc_sm_event evt,void * arg)809202bfdffSJames Smart __efc_d_wait_plogi_rsp_recvd_prli(struct efc_sm_ctx *ctx,
810202bfdffSJames Smart 				  enum efc_sm_event evt, void *arg)
811202bfdffSJames Smart {
812202bfdffSJames Smart 	int rc;
813202bfdffSJames Smart 	struct efc_node_cb *cbdata = arg;
814202bfdffSJames Smart 	struct efc_node *node = ctx->app;
815202bfdffSJames Smart 
816202bfdffSJames Smart 	efc_node_evt_set(ctx, evt, __func__);
817202bfdffSJames Smart 
818202bfdffSJames Smart 	node_sm_trace();
819202bfdffSJames Smart 
820202bfdffSJames Smart 	switch (evt) {
821202bfdffSJames Smart 	case EFC_EVT_ENTER:
822202bfdffSJames Smart 		/*
823202bfdffSJames Smart 		 * Since we've received a PRLI, we have a port login and will
824202bfdffSJames Smart 		 * just need to wait for the PLOGI response to do the node
825202bfdffSJames Smart 		 * attach and then we can send the LS_ACC for the PRLI. If,
826202bfdffSJames Smart 		 * during this time, we receive FCP_CMNDs (which is possible
827202bfdffSJames Smart 		 * since we've already sent a PRLI and our peer may have
828202bfdffSJames Smart 		 * accepted). At this time, we are not waiting on any other
829202bfdffSJames Smart 		 * unsolicited frames to continue with the login process. Thus,
830202bfdffSJames Smart 		 * it will not hurt to hold frames here.
831202bfdffSJames Smart 		 */
832202bfdffSJames Smart 		efc_node_hold_frames(node);
833202bfdffSJames Smart 		break;
834202bfdffSJames Smart 
835202bfdffSJames Smart 	case EFC_EVT_EXIT:
836202bfdffSJames Smart 		efc_node_accept_frames(node);
837202bfdffSJames Smart 		break;
838202bfdffSJames Smart 
839202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_REQ_OK:	/* PLOGI response received */
840202bfdffSJames Smart 		/* Completion from PLOGI sent */
841202bfdffSJames Smart 		if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
842202bfdffSJames Smart 					   __efc_d_common, __func__))
843202bfdffSJames Smart 			return;
844202bfdffSJames Smart 
845202bfdffSJames Smart 		WARN_ON(!node->els_req_cnt);
846202bfdffSJames Smart 		node->els_req_cnt--;
847202bfdffSJames Smart 		/* sm: / save sparams, efc_node_attach */
848202bfdffSJames Smart 		efc_node_save_sparms(node, cbdata->els_rsp.virt);
849202bfdffSJames Smart 		rc = efc_node_attach(node);
850202bfdffSJames Smart 		efc_node_transition(node, __efc_d_wait_node_attach, NULL);
851202bfdffSJames Smart 		if (rc < 0)
852202bfdffSJames Smart 			efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL,
853202bfdffSJames Smart 					    NULL);
854202bfdffSJames Smart 
855202bfdffSJames Smart 		break;
856202bfdffSJames Smart 
857202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_REQ_FAIL:	/* PLOGI response received */
858202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_REQ_RJT:
859202bfdffSJames Smart 		/* PLOGI failed, shutdown the node */
860202bfdffSJames Smart 		if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
861202bfdffSJames Smart 					   __efc_d_common, __func__))
862202bfdffSJames Smart 			return;
863202bfdffSJames Smart 
864202bfdffSJames Smart 		WARN_ON(!node->els_req_cnt);
865202bfdffSJames Smart 		node->els_req_cnt--;
866202bfdffSJames Smart 		efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
867202bfdffSJames Smart 		break;
868202bfdffSJames Smart 
869202bfdffSJames Smart 	default:
870202bfdffSJames Smart 		__efc_d_common(__func__, ctx, evt, arg);
871202bfdffSJames Smart 	}
872202bfdffSJames Smart }
873202bfdffSJames Smart 
874202bfdffSJames Smart void
__efc_d_wait_domain_attach(struct efc_sm_ctx * ctx,enum efc_sm_event evt,void * arg)875202bfdffSJames Smart __efc_d_wait_domain_attach(struct efc_sm_ctx *ctx,
876202bfdffSJames Smart 			   enum efc_sm_event evt, void *arg)
877202bfdffSJames Smart {
878202bfdffSJames Smart 	int rc;
879202bfdffSJames Smart 	struct efc_node *node = ctx->app;
880202bfdffSJames Smart 
881202bfdffSJames Smart 	efc_node_evt_set(ctx, evt, __func__);
882202bfdffSJames Smart 
883202bfdffSJames Smart 	node_sm_trace();
884202bfdffSJames Smart 
885202bfdffSJames Smart 	switch (evt) {
886202bfdffSJames Smart 	case EFC_EVT_ENTER:
887202bfdffSJames Smart 		efc_node_hold_frames(node);
888202bfdffSJames Smart 		break;
889202bfdffSJames Smart 
890202bfdffSJames Smart 	case EFC_EVT_EXIT:
891202bfdffSJames Smart 		efc_node_accept_frames(node);
892202bfdffSJames Smart 		break;
893202bfdffSJames Smart 
894202bfdffSJames Smart 	case EFC_EVT_DOMAIN_ATTACH_OK:
895202bfdffSJames Smart 		WARN_ON(!node->nport->domain->attached);
896202bfdffSJames Smart 		/* sm: / efc_node_attach */
897202bfdffSJames Smart 		rc = efc_node_attach(node);
898202bfdffSJames Smart 		efc_node_transition(node, __efc_d_wait_node_attach, NULL);
899202bfdffSJames Smart 		if (rc < 0)
900202bfdffSJames Smart 			efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL,
901202bfdffSJames Smart 					    NULL);
902202bfdffSJames Smart 
903202bfdffSJames Smart 		break;
904202bfdffSJames Smart 
905202bfdffSJames Smart 	default:
906202bfdffSJames Smart 		__efc_d_common(__func__, ctx, evt, arg);
907202bfdffSJames Smart 	}
908202bfdffSJames Smart }
909202bfdffSJames Smart 
910202bfdffSJames Smart void
__efc_d_wait_topology_notify(struct efc_sm_ctx * ctx,enum efc_sm_event evt,void * arg)911202bfdffSJames Smart __efc_d_wait_topology_notify(struct efc_sm_ctx *ctx,
912202bfdffSJames Smart 			     enum efc_sm_event evt, void *arg)
913202bfdffSJames Smart {
914202bfdffSJames Smart 	int rc;
915202bfdffSJames Smart 	struct efc_node *node = ctx->app;
916202bfdffSJames Smart 
917202bfdffSJames Smart 	efc_node_evt_set(ctx, evt, __func__);
918202bfdffSJames Smart 
919202bfdffSJames Smart 	node_sm_trace();
920202bfdffSJames Smart 
921202bfdffSJames Smart 	switch (evt) {
922202bfdffSJames Smart 	case EFC_EVT_ENTER:
923202bfdffSJames Smart 		efc_node_hold_frames(node);
924202bfdffSJames Smart 		break;
925202bfdffSJames Smart 
926202bfdffSJames Smart 	case EFC_EVT_EXIT:
927202bfdffSJames Smart 		efc_node_accept_frames(node);
928202bfdffSJames Smart 		break;
929202bfdffSJames Smart 
930202bfdffSJames Smart 	case EFC_EVT_NPORT_TOPOLOGY_NOTIFY: {
931*96fafe7cSJames Smart 		enum efc_nport_topology *topology = arg;
932202bfdffSJames Smart 
933202bfdffSJames Smart 		WARN_ON(node->nport->domain->attached);
934202bfdffSJames Smart 
935202bfdffSJames Smart 		WARN_ON(node->send_ls_acc != EFC_NODE_SEND_LS_ACC_PLOGI);
936202bfdffSJames Smart 
937202bfdffSJames Smart 		node_printf(node, "topology notification, topology=%d\n",
938*96fafe7cSJames Smart 			    *topology);
939202bfdffSJames Smart 
940202bfdffSJames Smart 		/* At the time the PLOGI was received, the topology was unknown,
941202bfdffSJames Smart 		 * so we didn't know which node would perform the domain attach:
942202bfdffSJames Smart 		 * 1. The node from which the PLOGI was sent (p2p) or
943202bfdffSJames Smart 		 * 2. The node to which the FLOGI was sent (fabric).
944202bfdffSJames Smart 		 */
945*96fafe7cSJames Smart 		if (*topology == EFC_NPORT_TOPO_P2P) {
946202bfdffSJames Smart 			/* if this is p2p, need to attach to the domain using
947202bfdffSJames Smart 			 * the d_id from the PLOGI received
948202bfdffSJames Smart 			 */
949202bfdffSJames Smart 			efc_domain_attach(node->nport->domain,
950202bfdffSJames Smart 					  node->ls_acc_did);
951202bfdffSJames Smart 		}
952202bfdffSJames Smart 		/* else, if this is fabric, the domain attach
953202bfdffSJames Smart 		 * should be performed by the fabric node (node sending FLOGI);
954202bfdffSJames Smart 		 * just wait for attach to complete
955202bfdffSJames Smart 		 */
956202bfdffSJames Smart 
957202bfdffSJames Smart 		efc_node_transition(node, __efc_d_wait_domain_attach, NULL);
958202bfdffSJames Smart 		break;
959202bfdffSJames Smart 	}
960202bfdffSJames Smart 	case EFC_EVT_DOMAIN_ATTACH_OK:
961202bfdffSJames Smart 		WARN_ON(!node->nport->domain->attached);
962202bfdffSJames Smart 		node_printf(node, "domain attach ok\n");
963202bfdffSJames Smart 		/* sm: / efc_node_attach */
964202bfdffSJames Smart 		rc = efc_node_attach(node);
965202bfdffSJames Smart 		efc_node_transition(node, __efc_d_wait_node_attach, NULL);
966202bfdffSJames Smart 		if (rc < 0)
967202bfdffSJames Smart 			efc_node_post_event(node,
968202bfdffSJames Smart 					    EFC_EVT_NODE_ATTACH_FAIL, NULL);
969202bfdffSJames Smart 
970202bfdffSJames Smart 		break;
971202bfdffSJames Smart 
972202bfdffSJames Smart 	default:
973202bfdffSJames Smart 		__efc_d_common(__func__, ctx, evt, arg);
974202bfdffSJames Smart 	}
975202bfdffSJames Smart }
976202bfdffSJames Smart 
977202bfdffSJames Smart void
__efc_d_wait_node_attach(struct efc_sm_ctx * ctx,enum efc_sm_event evt,void * arg)978202bfdffSJames Smart __efc_d_wait_node_attach(struct efc_sm_ctx *ctx,
979202bfdffSJames Smart 			 enum efc_sm_event evt, void *arg)
980202bfdffSJames Smart {
981202bfdffSJames Smart 	struct efc_node *node = ctx->app;
982202bfdffSJames Smart 
983202bfdffSJames Smart 	efc_node_evt_set(ctx, evt, __func__);
984202bfdffSJames Smart 
985202bfdffSJames Smart 	node_sm_trace();
986202bfdffSJames Smart 
987202bfdffSJames Smart 	switch (evt) {
988202bfdffSJames Smart 	case EFC_EVT_ENTER:
989202bfdffSJames Smart 		efc_node_hold_frames(node);
990202bfdffSJames Smart 		break;
991202bfdffSJames Smart 
992202bfdffSJames Smart 	case EFC_EVT_EXIT:
993202bfdffSJames Smart 		efc_node_accept_frames(node);
994202bfdffSJames Smart 		break;
995202bfdffSJames Smart 
996202bfdffSJames Smart 	case EFC_EVT_NODE_ATTACH_OK:
997202bfdffSJames Smart 		node->attached = true;
998202bfdffSJames Smart 		switch (node->send_ls_acc) {
999202bfdffSJames Smart 		case EFC_NODE_SEND_LS_ACC_PLOGI: {
1000202bfdffSJames Smart 			/* sm: send_plogi_acc is set / send PLOGI acc */
1001202bfdffSJames Smart 			/* Normal case for T, or I+T */
1002202bfdffSJames Smart 			efc_send_plogi_acc(node, node->ls_acc_oxid);
1003202bfdffSJames Smart 			efc_node_transition(node, __efc_d_wait_plogi_acc_cmpl,
1004202bfdffSJames Smart 					    NULL);
1005202bfdffSJames Smart 			node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE;
1006202bfdffSJames Smart 			node->ls_acc_io = NULL;
1007202bfdffSJames Smart 			break;
1008202bfdffSJames Smart 		}
1009202bfdffSJames Smart 		case EFC_NODE_SEND_LS_ACC_PRLI: {
1010202bfdffSJames Smart 			efc_d_send_prli_rsp(node, node->ls_acc_oxid);
1011202bfdffSJames Smart 			node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE;
1012202bfdffSJames Smart 			node->ls_acc_io = NULL;
1013202bfdffSJames Smart 			break;
1014202bfdffSJames Smart 		}
1015202bfdffSJames Smart 		case EFC_NODE_SEND_LS_ACC_NONE:
1016202bfdffSJames Smart 		default:
1017202bfdffSJames Smart 			/* Normal case for I */
1018202bfdffSJames Smart 			/* sm: send_plogi_acc is not set / send PLOGI acc */
1019202bfdffSJames Smart 			efc_node_transition(node,
1020202bfdffSJames Smart 					    __efc_d_port_logged_in, NULL);
1021202bfdffSJames Smart 			break;
1022202bfdffSJames Smart 		}
1023202bfdffSJames Smart 		break;
1024202bfdffSJames Smart 
1025202bfdffSJames Smart 	case EFC_EVT_NODE_ATTACH_FAIL:
1026202bfdffSJames Smart 		/* node attach failed, shutdown the node */
1027202bfdffSJames Smart 		node->attached = false;
1028202bfdffSJames Smart 		node_printf(node, "node attach failed\n");
1029202bfdffSJames Smart 		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
1030202bfdffSJames Smart 		efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
1031202bfdffSJames Smart 		break;
1032202bfdffSJames Smart 
1033202bfdffSJames Smart 	/* Handle shutdown events */
1034202bfdffSJames Smart 	case EFC_EVT_SHUTDOWN:
1035202bfdffSJames Smart 		node_printf(node, "%s received\n", efc_sm_event_name(evt));
1036202bfdffSJames Smart 		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
1037202bfdffSJames Smart 		efc_node_transition(node, __efc_d_wait_attach_evt_shutdown,
1038202bfdffSJames Smart 				    NULL);
1039202bfdffSJames Smart 		break;
1040202bfdffSJames Smart 	case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
1041202bfdffSJames Smart 		node_printf(node, "%s received\n", efc_sm_event_name(evt));
1042202bfdffSJames Smart 		node->shutdown_reason = EFC_NODE_SHUTDOWN_EXPLICIT_LOGO;
1043202bfdffSJames Smart 		efc_node_transition(node, __efc_d_wait_attach_evt_shutdown,
1044202bfdffSJames Smart 				    NULL);
1045202bfdffSJames Smart 		break;
1046202bfdffSJames Smart 	case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
1047202bfdffSJames Smart 		node_printf(node, "%s received\n", efc_sm_event_name(evt));
1048202bfdffSJames Smart 		node->shutdown_reason = EFC_NODE_SHUTDOWN_IMPLICIT_LOGO;
1049202bfdffSJames Smart 		efc_node_transition(node,
1050202bfdffSJames Smart 				    __efc_d_wait_attach_evt_shutdown, NULL);
1051202bfdffSJames Smart 		break;
1052202bfdffSJames Smart 	default:
1053202bfdffSJames Smart 		__efc_d_common(__func__, ctx, evt, arg);
1054202bfdffSJames Smart 	}
1055202bfdffSJames Smart }
1056202bfdffSJames Smart 
1057202bfdffSJames Smart void
__efc_d_wait_attach_evt_shutdown(struct efc_sm_ctx * ctx,enum efc_sm_event evt,void * arg)1058202bfdffSJames Smart __efc_d_wait_attach_evt_shutdown(struct efc_sm_ctx *ctx,
1059202bfdffSJames Smart 				 enum efc_sm_event evt, void *arg)
1060202bfdffSJames Smart {
1061202bfdffSJames Smart 	struct efc_node *node = ctx->app;
1062202bfdffSJames Smart 
1063202bfdffSJames Smart 	efc_node_evt_set(ctx, evt, __func__);
1064202bfdffSJames Smart 
1065202bfdffSJames Smart 	node_sm_trace();
1066202bfdffSJames Smart 
1067202bfdffSJames Smart 	switch (evt) {
1068202bfdffSJames Smart 	case EFC_EVT_ENTER:
1069202bfdffSJames Smart 		efc_node_hold_frames(node);
1070202bfdffSJames Smart 		break;
1071202bfdffSJames Smart 
1072202bfdffSJames Smart 	case EFC_EVT_EXIT:
1073202bfdffSJames Smart 		efc_node_accept_frames(node);
1074202bfdffSJames Smart 		break;
1075202bfdffSJames Smart 
1076202bfdffSJames Smart 	/* wait for any of these attach events and then shutdown */
1077202bfdffSJames Smart 	case EFC_EVT_NODE_ATTACH_OK:
1078202bfdffSJames Smart 		node->attached = true;
1079202bfdffSJames Smart 		node_printf(node, "Attach evt=%s, proceed to shutdown\n",
1080202bfdffSJames Smart 			    efc_sm_event_name(evt));
1081202bfdffSJames Smart 		efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
1082202bfdffSJames Smart 		break;
1083202bfdffSJames Smart 
1084202bfdffSJames Smart 	case EFC_EVT_NODE_ATTACH_FAIL:
1085202bfdffSJames Smart 		/* node attach failed, shutdown the node */
1086202bfdffSJames Smart 		node->attached = false;
1087202bfdffSJames Smart 		node_printf(node, "Attach evt=%s, proceed to shutdown\n",
1088202bfdffSJames Smart 			    efc_sm_event_name(evt));
1089202bfdffSJames Smart 		efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
1090202bfdffSJames Smart 		break;
1091202bfdffSJames Smart 
1092202bfdffSJames Smart 	/* ignore shutdown events as we're already in shutdown path */
1093202bfdffSJames Smart 	case EFC_EVT_SHUTDOWN:
1094202bfdffSJames Smart 		/* have default shutdown event take precedence */
1095202bfdffSJames Smart 		node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
1096202bfdffSJames Smart 		fallthrough;
1097202bfdffSJames Smart 
1098202bfdffSJames Smart 	case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
1099202bfdffSJames Smart 	case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
1100202bfdffSJames Smart 		node_printf(node, "%s received\n", efc_sm_event_name(evt));
1101202bfdffSJames Smart 		break;
1102202bfdffSJames Smart 
1103202bfdffSJames Smart 	default:
1104202bfdffSJames Smart 		__efc_d_common(__func__, ctx, evt, arg);
1105202bfdffSJames Smart 	}
1106202bfdffSJames Smart }
1107202bfdffSJames Smart 
1108202bfdffSJames Smart void
__efc_d_port_logged_in(struct efc_sm_ctx * ctx,enum efc_sm_event evt,void * arg)1109202bfdffSJames Smart __efc_d_port_logged_in(struct efc_sm_ctx *ctx,
1110202bfdffSJames Smart 		       enum efc_sm_event evt, void *arg)
1111202bfdffSJames Smart {
1112202bfdffSJames Smart 	struct efc_node_cb *cbdata = arg;
1113202bfdffSJames Smart 	struct efc_node *node = ctx->app;
1114202bfdffSJames Smart 
1115202bfdffSJames Smart 	efc_node_evt_set(ctx, evt, __func__);
1116202bfdffSJames Smart 
1117202bfdffSJames Smart 	node_sm_trace();
1118202bfdffSJames Smart 
1119202bfdffSJames Smart 	switch (evt) {
1120202bfdffSJames Smart 	case EFC_EVT_ENTER:
1121202bfdffSJames Smart 		/* Normal case for I or I+T */
1122202bfdffSJames Smart 		if (node->nport->enable_ini &&
1123202bfdffSJames Smart 		    !(node->rnode.fc_id != FC_FID_DOM_MGR)) {
1124202bfdffSJames Smart 			/* sm: if enable_ini / send PRLI */
1125202bfdffSJames Smart 			efc_send_prli(node);
1126202bfdffSJames Smart 			/* can now expect ELS_REQ_OK/FAIL/RJT */
1127202bfdffSJames Smart 		}
1128202bfdffSJames Smart 		break;
1129202bfdffSJames Smart 
1130202bfdffSJames Smart 	case EFC_EVT_FCP_CMD_RCVD: {
1131202bfdffSJames Smart 		break;
1132202bfdffSJames Smart 	}
1133202bfdffSJames Smart 
1134202bfdffSJames Smart 	case EFC_EVT_PRLI_RCVD: {
1135202bfdffSJames Smart 		/* Normal case for T or I+T */
1136202bfdffSJames Smart 		struct fc_frame_header *hdr = cbdata->header->dma.virt;
1137202bfdffSJames Smart 		struct {
1138202bfdffSJames Smart 			struct fc_els_prli prli;
1139202bfdffSJames Smart 			struct fc_els_spp sp;
1140202bfdffSJames Smart 		} *pp;
1141202bfdffSJames Smart 
1142202bfdffSJames Smart 		pp = cbdata->payload->dma.virt;
1143202bfdffSJames Smart 		if (pp->sp.spp_type != FC_TYPE_FCP) {
1144202bfdffSJames Smart 			/*Only FCP is supported*/
1145202bfdffSJames Smart 			efc_send_ls_rjt(node, be16_to_cpu(hdr->fh_ox_id),
1146202bfdffSJames Smart 					ELS_RJT_UNAB, ELS_EXPL_UNSUPR, 0);
1147202bfdffSJames Smart 			break;
1148202bfdffSJames Smart 		}
1149202bfdffSJames Smart 
1150202bfdffSJames Smart 		efc_process_prli_payload(node, cbdata->payload->dma.virt);
1151202bfdffSJames Smart 		efc_d_send_prli_rsp(node, be16_to_cpu(hdr->fh_ox_id));
1152202bfdffSJames Smart 		break;
1153202bfdffSJames Smart 	}
1154202bfdffSJames Smart 
1155202bfdffSJames Smart 	case EFC_EVT_NODE_SESS_REG_OK:
1156202bfdffSJames Smart 		if (node->send_ls_acc == EFC_NODE_SEND_LS_ACC_PRLI)
1157202bfdffSJames Smart 			efc_send_prli_acc(node, node->ls_acc_oxid);
1158202bfdffSJames Smart 
1159202bfdffSJames Smart 		node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE;
1160202bfdffSJames Smart 		efc_node_transition(node, __efc_d_device_ready, NULL);
1161202bfdffSJames Smart 		break;
1162202bfdffSJames Smart 
1163202bfdffSJames Smart 	case EFC_EVT_NODE_SESS_REG_FAIL:
1164202bfdffSJames Smart 		efc_send_ls_rjt(node, node->ls_acc_oxid, ELS_RJT_UNAB,
1165202bfdffSJames Smart 				ELS_EXPL_UNSUPR, 0);
1166202bfdffSJames Smart 		node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE;
1167202bfdffSJames Smart 		break;
1168202bfdffSJames Smart 
1169202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_REQ_OK: {	/* PRLI response */
1170202bfdffSJames Smart 		/* Normal case for I or I+T */
1171202bfdffSJames Smart 		if (efc_node_check_els_req(ctx, evt, arg, ELS_PRLI,
1172202bfdffSJames Smart 					   __efc_d_common, __func__))
1173202bfdffSJames Smart 			return;
1174202bfdffSJames Smart 
1175202bfdffSJames Smart 		WARN_ON(!node->els_req_cnt);
1176202bfdffSJames Smart 		node->els_req_cnt--;
1177202bfdffSJames Smart 		/* sm: / process PRLI payload */
1178202bfdffSJames Smart 		efc_process_prli_payload(node, cbdata->els_rsp.virt);
1179202bfdffSJames Smart 		efc_node_transition(node, __efc_d_device_ready, NULL);
1180202bfdffSJames Smart 		break;
1181202bfdffSJames Smart 	}
1182202bfdffSJames Smart 
1183202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_REQ_FAIL: {	/* PRLI response failed */
1184202bfdffSJames Smart 		/* I, I+T, assume some link failure, shutdown node */
1185202bfdffSJames Smart 		if (efc_node_check_els_req(ctx, evt, arg, ELS_PRLI,
1186202bfdffSJames Smart 					   __efc_d_common, __func__))
1187202bfdffSJames Smart 			return;
1188202bfdffSJames Smart 
1189202bfdffSJames Smart 		WARN_ON(!node->els_req_cnt);
1190202bfdffSJames Smart 		node->els_req_cnt--;
1191202bfdffSJames Smart 		efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
1192202bfdffSJames Smart 		break;
1193202bfdffSJames Smart 	}
1194202bfdffSJames Smart 
1195202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_REQ_RJT: {
1196202bfdffSJames Smart 		/* PRLI rejected by remote
1197202bfdffSJames Smart 		 * Normal for I, I+T (connected to an I)
1198202bfdffSJames Smart 		 * Node doesn't want to be a target, stay here and wait for a
1199202bfdffSJames Smart 		 * PRLI from the remote node
1200202bfdffSJames Smart 		 * if it really wants to connect to us as target
1201202bfdffSJames Smart 		 */
1202202bfdffSJames Smart 		if (efc_node_check_els_req(ctx, evt, arg, ELS_PRLI,
1203202bfdffSJames Smart 					   __efc_d_common, __func__))
1204202bfdffSJames Smart 			return;
1205202bfdffSJames Smart 
1206202bfdffSJames Smart 		WARN_ON(!node->els_req_cnt);
1207202bfdffSJames Smart 		node->els_req_cnt--;
1208202bfdffSJames Smart 		break;
1209202bfdffSJames Smart 	}
1210202bfdffSJames Smart 
1211202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_CMPL_OK: {
1212202bfdffSJames Smart 		/* Normal T, I+T, target-server rejected the process login */
1213202bfdffSJames Smart 		/* This would be received only in the case where we sent
1214202bfdffSJames Smart 		 * LS_RJT for the PRLI, so
1215202bfdffSJames Smart 		 * do nothing.   (note: as T only we could shutdown the node)
1216202bfdffSJames Smart 		 */
1217202bfdffSJames Smart 		WARN_ON(!node->els_cmpl_cnt);
1218202bfdffSJames Smart 		node->els_cmpl_cnt--;
1219202bfdffSJames Smart 		break;
1220202bfdffSJames Smart 	}
1221202bfdffSJames Smart 
1222202bfdffSJames Smart 	case EFC_EVT_PLOGI_RCVD: {
1223202bfdffSJames Smart 		/*sm: / save sparams, set send_plogi_acc,
1224202bfdffSJames Smart 		 *post implicit logout
1225202bfdffSJames Smart 		 * Save plogi parameters
1226202bfdffSJames Smart 		 */
1227202bfdffSJames Smart 		efc_node_save_sparms(node, cbdata->payload->dma.virt);
1228202bfdffSJames Smart 		efc_send_ls_acc_after_attach(node,
1229202bfdffSJames Smart 					     cbdata->header->dma.virt,
1230202bfdffSJames Smart 				EFC_NODE_SEND_LS_ACC_PLOGI);
1231202bfdffSJames Smart 
1232202bfdffSJames Smart 		/* Restart node attach with new service parameters,
1233202bfdffSJames Smart 		 * and send ACC
1234202bfdffSJames Smart 		 */
1235202bfdffSJames Smart 		efc_node_post_event(node, EFC_EVT_SHUTDOWN_IMPLICIT_LOGO,
1236202bfdffSJames Smart 				    NULL);
1237202bfdffSJames Smart 		break;
1238202bfdffSJames Smart 	}
1239202bfdffSJames Smart 
1240202bfdffSJames Smart 	case EFC_EVT_LOGO_RCVD: {
1241202bfdffSJames Smart 		/* I, T, I+T */
1242202bfdffSJames Smart 		struct fc_frame_header *hdr = cbdata->header->dma.virt;
1243202bfdffSJames Smart 
1244202bfdffSJames Smart 		node_printf(node, "%s received attached=%d\n",
1245202bfdffSJames Smart 			    efc_sm_event_name(evt),
1246202bfdffSJames Smart 					node->attached);
1247202bfdffSJames Smart 		/* sm: / send LOGO acc */
1248202bfdffSJames Smart 		efc_send_logo_acc(node, be16_to_cpu(hdr->fh_ox_id));
1249202bfdffSJames Smart 		efc_node_transition(node, __efc_d_wait_logo_acc_cmpl, NULL);
1250202bfdffSJames Smart 		break;
1251202bfdffSJames Smart 	}
1252202bfdffSJames Smart 
1253202bfdffSJames Smart 	default:
1254202bfdffSJames Smart 		__efc_d_common(__func__, ctx, evt, arg);
1255202bfdffSJames Smart 	}
1256202bfdffSJames Smart }
1257202bfdffSJames Smart 
1258202bfdffSJames Smart void
__efc_d_wait_logo_acc_cmpl(struct efc_sm_ctx * ctx,enum efc_sm_event evt,void * arg)1259202bfdffSJames Smart __efc_d_wait_logo_acc_cmpl(struct efc_sm_ctx *ctx,
1260202bfdffSJames Smart 			   enum efc_sm_event evt, void *arg)
1261202bfdffSJames Smart {
1262202bfdffSJames Smart 	struct efc_node *node = ctx->app;
1263202bfdffSJames Smart 
1264202bfdffSJames Smart 	efc_node_evt_set(ctx, evt, __func__);
1265202bfdffSJames Smart 
1266202bfdffSJames Smart 	node_sm_trace();
1267202bfdffSJames Smart 
1268202bfdffSJames Smart 	switch (evt) {
1269202bfdffSJames Smart 	case EFC_EVT_ENTER:
1270202bfdffSJames Smart 		efc_node_hold_frames(node);
1271202bfdffSJames Smart 		break;
1272202bfdffSJames Smart 
1273202bfdffSJames Smart 	case EFC_EVT_EXIT:
1274202bfdffSJames Smart 		efc_node_accept_frames(node);
1275202bfdffSJames Smart 		break;
1276202bfdffSJames Smart 
1277202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_CMPL_OK:
1278202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_CMPL_FAIL:
1279202bfdffSJames Smart 		/* sm: / post explicit logout */
1280202bfdffSJames Smart 		WARN_ON(!node->els_cmpl_cnt);
1281202bfdffSJames Smart 		node->els_cmpl_cnt--;
1282202bfdffSJames Smart 		efc_node_post_event(node,
1283202bfdffSJames Smart 				    EFC_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
1284202bfdffSJames Smart 		break;
1285202bfdffSJames Smart 	default:
1286202bfdffSJames Smart 		__efc_d_common(__func__, ctx, evt, arg);
1287202bfdffSJames Smart 	}
1288202bfdffSJames Smart }
1289202bfdffSJames Smart 
1290202bfdffSJames Smart void
__efc_d_device_ready(struct efc_sm_ctx * ctx,enum efc_sm_event evt,void * arg)1291202bfdffSJames Smart __efc_d_device_ready(struct efc_sm_ctx *ctx,
1292202bfdffSJames Smart 		     enum efc_sm_event evt, void *arg)
1293202bfdffSJames Smart {
1294202bfdffSJames Smart 	struct efc_node_cb *cbdata = arg;
1295202bfdffSJames Smart 	struct efc_node *node = ctx->app;
1296202bfdffSJames Smart 	struct efc *efc = node->efc;
1297202bfdffSJames Smart 
1298202bfdffSJames Smart 	efc_node_evt_set(ctx, evt, __func__);
1299202bfdffSJames Smart 
1300202bfdffSJames Smart 	if (evt != EFC_EVT_FCP_CMD_RCVD)
1301202bfdffSJames Smart 		node_sm_trace();
1302202bfdffSJames Smart 
1303202bfdffSJames Smart 	switch (evt) {
1304202bfdffSJames Smart 	case EFC_EVT_ENTER:
1305202bfdffSJames Smart 		node->fcp_enabled = true;
1306202bfdffSJames Smart 		if (node->targ) {
1307202bfdffSJames Smart 			efc_log_info(efc,
1308202bfdffSJames Smart 				     "[%s] found (target) WWPN %s WWNN %s\n",
1309202bfdffSJames Smart 				node->display_name,
1310202bfdffSJames Smart 				node->wwpn, node->wwnn);
1311202bfdffSJames Smart 			if (node->nport->enable_ini)
1312202bfdffSJames Smart 				efc->tt.scsi_new_node(efc, node);
1313202bfdffSJames Smart 		}
1314202bfdffSJames Smart 		break;
1315202bfdffSJames Smart 
1316202bfdffSJames Smart 	case EFC_EVT_EXIT:
1317202bfdffSJames Smart 		node->fcp_enabled = false;
1318202bfdffSJames Smart 		break;
1319202bfdffSJames Smart 
1320202bfdffSJames Smart 	case EFC_EVT_PLOGI_RCVD: {
1321202bfdffSJames Smart 		/* sm: / save sparams, set send_plogi_acc, post implicit
1322202bfdffSJames Smart 		 * logout
1323202bfdffSJames Smart 		 * Save plogi parameters
1324202bfdffSJames Smart 		 */
1325202bfdffSJames Smart 		efc_node_save_sparms(node, cbdata->payload->dma.virt);
1326202bfdffSJames Smart 		efc_send_ls_acc_after_attach(node,
1327202bfdffSJames Smart 					     cbdata->header->dma.virt,
1328202bfdffSJames Smart 				EFC_NODE_SEND_LS_ACC_PLOGI);
1329202bfdffSJames Smart 
1330202bfdffSJames Smart 		/*
1331202bfdffSJames Smart 		 * Restart node attach with new service parameters,
1332202bfdffSJames Smart 		 * and send ACC
1333202bfdffSJames Smart 		 */
1334202bfdffSJames Smart 		efc_node_post_event(node,
1335202bfdffSJames Smart 				    EFC_EVT_SHUTDOWN_IMPLICIT_LOGO, NULL);
1336202bfdffSJames Smart 		break;
1337202bfdffSJames Smart 	}
1338202bfdffSJames Smart 
1339202bfdffSJames Smart 	case EFC_EVT_PRLI_RCVD: {
1340202bfdffSJames Smart 		/* T, I+T: remote initiator is slow to get started */
1341202bfdffSJames Smart 		struct fc_frame_header *hdr = cbdata->header->dma.virt;
1342202bfdffSJames Smart 		struct {
1343202bfdffSJames Smart 			struct fc_els_prli prli;
1344202bfdffSJames Smart 			struct fc_els_spp sp;
1345202bfdffSJames Smart 		} *pp;
1346202bfdffSJames Smart 
1347202bfdffSJames Smart 		pp = cbdata->payload->dma.virt;
1348202bfdffSJames Smart 		if (pp->sp.spp_type != FC_TYPE_FCP) {
1349202bfdffSJames Smart 			/*Only FCP is supported*/
1350202bfdffSJames Smart 			efc_send_ls_rjt(node, be16_to_cpu(hdr->fh_ox_id),
1351202bfdffSJames Smart 					ELS_RJT_UNAB, ELS_EXPL_UNSUPR, 0);
1352202bfdffSJames Smart 			break;
1353202bfdffSJames Smart 		}
1354202bfdffSJames Smart 
1355202bfdffSJames Smart 		efc_process_prli_payload(node, cbdata->payload->dma.virt);
1356202bfdffSJames Smart 		efc_send_prli_acc(node, be16_to_cpu(hdr->fh_ox_id));
1357202bfdffSJames Smart 		break;
1358202bfdffSJames Smart 	}
1359202bfdffSJames Smart 
1360202bfdffSJames Smart 	case EFC_EVT_PRLO_RCVD: {
1361202bfdffSJames Smart 		struct fc_frame_header *hdr = cbdata->header->dma.virt;
1362202bfdffSJames Smart 		/* sm: / send PRLO acc */
1363202bfdffSJames Smart 		efc_send_prlo_acc(node, be16_to_cpu(hdr->fh_ox_id));
1364202bfdffSJames Smart 		/* need implicit logout? */
1365202bfdffSJames Smart 		break;
1366202bfdffSJames Smart 	}
1367202bfdffSJames Smart 
1368202bfdffSJames Smart 	case EFC_EVT_LOGO_RCVD: {
1369202bfdffSJames Smart 		struct fc_frame_header *hdr = cbdata->header->dma.virt;
1370202bfdffSJames Smart 
1371202bfdffSJames Smart 		node_printf(node, "%s received attached=%d\n",
1372202bfdffSJames Smart 			    efc_sm_event_name(evt), node->attached);
1373202bfdffSJames Smart 		/* sm: / send LOGO acc */
1374202bfdffSJames Smart 		efc_send_logo_acc(node, be16_to_cpu(hdr->fh_ox_id));
1375202bfdffSJames Smart 		efc_node_transition(node, __efc_d_wait_logo_acc_cmpl, NULL);
1376202bfdffSJames Smart 		break;
1377202bfdffSJames Smart 	}
1378202bfdffSJames Smart 
1379202bfdffSJames Smart 	case EFC_EVT_ADISC_RCVD: {
1380202bfdffSJames Smart 		struct fc_frame_header *hdr = cbdata->header->dma.virt;
1381202bfdffSJames Smart 		/* sm: / send ADISC acc */
1382202bfdffSJames Smart 		efc_send_adisc_acc(node, be16_to_cpu(hdr->fh_ox_id));
1383202bfdffSJames Smart 		break;
1384202bfdffSJames Smart 	}
1385202bfdffSJames Smart 
1386202bfdffSJames Smart 	case EFC_EVT_ABTS_RCVD:
1387202bfdffSJames Smart 		/* sm: / process ABTS */
1388202bfdffSJames Smart 		efc_log_err(efc, "Unexpected event:%s\n",
1389202bfdffSJames Smart 			    efc_sm_event_name(evt));
1390202bfdffSJames Smart 		break;
1391202bfdffSJames Smart 
1392202bfdffSJames Smart 	case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
1393202bfdffSJames Smart 		break;
1394202bfdffSJames Smart 
1395202bfdffSJames Smart 	case EFC_EVT_NODE_REFOUND:
1396202bfdffSJames Smart 		break;
1397202bfdffSJames Smart 
1398202bfdffSJames Smart 	case EFC_EVT_NODE_MISSING:
1399202bfdffSJames Smart 		if (node->nport->enable_rscn)
1400202bfdffSJames Smart 			efc_node_transition(node, __efc_d_device_gone, NULL);
1401202bfdffSJames Smart 
1402202bfdffSJames Smart 		break;
1403202bfdffSJames Smart 
1404202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_CMPL_OK:
1405202bfdffSJames Smart 		/* T, or I+T, PRLI accept completed ok */
1406202bfdffSJames Smart 		WARN_ON(!node->els_cmpl_cnt);
1407202bfdffSJames Smart 		node->els_cmpl_cnt--;
1408202bfdffSJames Smart 		break;
1409202bfdffSJames Smart 
1410202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_CMPL_FAIL:
1411202bfdffSJames Smart 		/* T, or I+T, PRLI accept failed to complete */
1412202bfdffSJames Smart 		WARN_ON(!node->els_cmpl_cnt);
1413202bfdffSJames Smart 		node->els_cmpl_cnt--;
1414202bfdffSJames Smart 		node_printf(node, "Failed to send PRLI LS_ACC\n");
1415202bfdffSJames Smart 		break;
1416202bfdffSJames Smart 
1417202bfdffSJames Smart 	default:
1418202bfdffSJames Smart 		__efc_d_common(__func__, ctx, evt, arg);
1419202bfdffSJames Smart 	}
1420202bfdffSJames Smart }
1421202bfdffSJames Smart 
1422202bfdffSJames Smart void
__efc_d_device_gone(struct efc_sm_ctx * ctx,enum efc_sm_event evt,void * arg)1423202bfdffSJames Smart __efc_d_device_gone(struct efc_sm_ctx *ctx,
1424202bfdffSJames Smart 		    enum efc_sm_event evt, void *arg)
1425202bfdffSJames Smart {
1426202bfdffSJames Smart 	struct efc_node_cb *cbdata = arg;
1427202bfdffSJames Smart 	struct efc_node *node = ctx->app;
1428202bfdffSJames Smart 	struct efc *efc = node->efc;
1429202bfdffSJames Smart 
1430202bfdffSJames Smart 	efc_node_evt_set(ctx, evt, __func__);
1431202bfdffSJames Smart 
1432202bfdffSJames Smart 	node_sm_trace();
1433202bfdffSJames Smart 
1434202bfdffSJames Smart 	switch (evt) {
1435202bfdffSJames Smart 	case EFC_EVT_ENTER: {
1436202bfdffSJames Smart 		int rc = EFC_SCSI_CALL_COMPLETE;
1437202bfdffSJames Smart 		int rc_2 = EFC_SCSI_CALL_COMPLETE;
1438202bfdffSJames Smart 		static const char * const labels[] = {
1439202bfdffSJames Smart 			"none", "initiator", "target", "initiator+target"
1440202bfdffSJames Smart 		};
1441202bfdffSJames Smart 
1442202bfdffSJames Smart 		efc_log_info(efc, "[%s] missing (%s)    WWPN %s WWNN %s\n",
1443202bfdffSJames Smart 			     node->display_name,
1444202bfdffSJames Smart 				labels[(node->targ << 1) | (node->init)],
1445202bfdffSJames Smart 						node->wwpn, node->wwnn);
1446202bfdffSJames Smart 
1447202bfdffSJames Smart 		switch (efc_node_get_enable(node)) {
1448202bfdffSJames Smart 		case EFC_NODE_ENABLE_T_TO_T:
1449202bfdffSJames Smart 		case EFC_NODE_ENABLE_I_TO_T:
1450202bfdffSJames Smart 		case EFC_NODE_ENABLE_IT_TO_T:
1451202bfdffSJames Smart 			rc = efc->tt.scsi_del_node(efc, node,
1452202bfdffSJames Smart 				EFC_SCSI_TARGET_MISSING);
1453202bfdffSJames Smart 			break;
1454202bfdffSJames Smart 
1455202bfdffSJames Smart 		case EFC_NODE_ENABLE_T_TO_I:
1456202bfdffSJames Smart 		case EFC_NODE_ENABLE_I_TO_I:
1457202bfdffSJames Smart 		case EFC_NODE_ENABLE_IT_TO_I:
1458202bfdffSJames Smart 			rc = efc->tt.scsi_del_node(efc, node,
1459202bfdffSJames Smart 				EFC_SCSI_INITIATOR_MISSING);
1460202bfdffSJames Smart 			break;
1461202bfdffSJames Smart 
1462202bfdffSJames Smart 		case EFC_NODE_ENABLE_T_TO_IT:
1463202bfdffSJames Smart 			rc = efc->tt.scsi_del_node(efc, node,
1464202bfdffSJames Smart 				EFC_SCSI_INITIATOR_MISSING);
1465202bfdffSJames Smart 			break;
1466202bfdffSJames Smart 
1467202bfdffSJames Smart 		case EFC_NODE_ENABLE_I_TO_IT:
1468202bfdffSJames Smart 			rc = efc->tt.scsi_del_node(efc, node,
1469202bfdffSJames Smart 						  EFC_SCSI_TARGET_MISSING);
1470202bfdffSJames Smart 			break;
1471202bfdffSJames Smart 
1472202bfdffSJames Smart 		case EFC_NODE_ENABLE_IT_TO_IT:
1473202bfdffSJames Smart 			rc = efc->tt.scsi_del_node(efc, node,
1474202bfdffSJames Smart 				EFC_SCSI_INITIATOR_MISSING);
1475202bfdffSJames Smart 			rc_2 = efc->tt.scsi_del_node(efc, node,
1476202bfdffSJames Smart 				EFC_SCSI_TARGET_MISSING);
1477202bfdffSJames Smart 			break;
1478202bfdffSJames Smart 
1479202bfdffSJames Smart 		default:
1480202bfdffSJames Smart 			rc = EFC_SCSI_CALL_COMPLETE;
1481202bfdffSJames Smart 			break;
1482202bfdffSJames Smart 		}
1483202bfdffSJames Smart 
1484202bfdffSJames Smart 		if (rc == EFC_SCSI_CALL_COMPLETE &&
1485202bfdffSJames Smart 		    rc_2 == EFC_SCSI_CALL_COMPLETE)
1486202bfdffSJames Smart 			efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
1487202bfdffSJames Smart 
1488202bfdffSJames Smart 		break;
1489202bfdffSJames Smart 	}
1490202bfdffSJames Smart 	case EFC_EVT_NODE_REFOUND:
1491202bfdffSJames Smart 		/* two approaches, reauthenticate with PLOGI/PRLI, or ADISC */
1492202bfdffSJames Smart 
1493202bfdffSJames Smart 		/* reauthenticate with PLOGI/PRLI */
1494202bfdffSJames Smart 		/* efc_node_transition(node, __efc_d_discovered, NULL); */
1495202bfdffSJames Smart 
1496202bfdffSJames Smart 		/* reauthenticate with ADISC */
1497202bfdffSJames Smart 		/* sm: / send ADISC */
1498202bfdffSJames Smart 		efc_send_adisc(node);
1499202bfdffSJames Smart 		efc_node_transition(node, __efc_d_wait_adisc_rsp, NULL);
1500202bfdffSJames Smart 		break;
1501202bfdffSJames Smart 
1502202bfdffSJames Smart 	case EFC_EVT_PLOGI_RCVD: {
1503202bfdffSJames Smart 		/* sm: / save sparams, set send_plogi_acc, post implicit
1504202bfdffSJames Smart 		 * logout
1505202bfdffSJames Smart 		 * Save plogi parameters
1506202bfdffSJames Smart 		 */
1507202bfdffSJames Smart 		efc_node_save_sparms(node, cbdata->payload->dma.virt);
1508202bfdffSJames Smart 		efc_send_ls_acc_after_attach(node,
1509202bfdffSJames Smart 					     cbdata->header->dma.virt,
1510202bfdffSJames Smart 				EFC_NODE_SEND_LS_ACC_PLOGI);
1511202bfdffSJames Smart 
1512202bfdffSJames Smart 		/*
1513202bfdffSJames Smart 		 * Restart node attach with new service parameters, and send
1514202bfdffSJames Smart 		 * ACC
1515202bfdffSJames Smart 		 */
1516202bfdffSJames Smart 		efc_node_post_event(node, EFC_EVT_SHUTDOWN_IMPLICIT_LOGO,
1517202bfdffSJames Smart 				    NULL);
1518202bfdffSJames Smart 		break;
1519202bfdffSJames Smart 	}
1520202bfdffSJames Smart 
1521202bfdffSJames Smart 	case EFC_EVT_FCP_CMD_RCVD: {
1522202bfdffSJames Smart 		/* most likely a stale frame (received prior to link down),
1523202bfdffSJames Smart 		 * if attempt to send LOGO, will probably timeout and eat
1524202bfdffSJames Smart 		 * up 20s; thus, drop FCP_CMND
1525202bfdffSJames Smart 		 */
1526202bfdffSJames Smart 		node_printf(node, "FCP_CMND received, drop\n");
1527202bfdffSJames Smart 		break;
1528202bfdffSJames Smart 	}
1529202bfdffSJames Smart 	case EFC_EVT_LOGO_RCVD: {
1530202bfdffSJames Smart 		/* I, T, I+T */
1531202bfdffSJames Smart 		struct fc_frame_header *hdr = cbdata->header->dma.virt;
1532202bfdffSJames Smart 
1533202bfdffSJames Smart 		node_printf(node, "%s received attached=%d\n",
1534202bfdffSJames Smart 			    efc_sm_event_name(evt), node->attached);
1535202bfdffSJames Smart 		/* sm: / send LOGO acc */
1536202bfdffSJames Smart 		efc_send_logo_acc(node, be16_to_cpu(hdr->fh_ox_id));
1537202bfdffSJames Smart 		efc_node_transition(node, __efc_d_wait_logo_acc_cmpl, NULL);
1538202bfdffSJames Smart 		break;
1539202bfdffSJames Smart 	}
1540202bfdffSJames Smart 	default:
1541202bfdffSJames Smart 		__efc_d_common(__func__, ctx, evt, arg);
1542202bfdffSJames Smart 	}
1543202bfdffSJames Smart }
1544202bfdffSJames Smart 
1545202bfdffSJames Smart void
__efc_d_wait_adisc_rsp(struct efc_sm_ctx * ctx,enum efc_sm_event evt,void * arg)1546202bfdffSJames Smart __efc_d_wait_adisc_rsp(struct efc_sm_ctx *ctx,
1547202bfdffSJames Smart 		       enum efc_sm_event evt, void *arg)
1548202bfdffSJames Smart {
1549202bfdffSJames Smart 	struct efc_node_cb *cbdata = arg;
1550202bfdffSJames Smart 	struct efc_node *node = ctx->app;
1551202bfdffSJames Smart 
1552202bfdffSJames Smart 	efc_node_evt_set(ctx, evt, __func__);
1553202bfdffSJames Smart 
1554202bfdffSJames Smart 	node_sm_trace();
1555202bfdffSJames Smart 
1556202bfdffSJames Smart 	switch (evt) {
1557202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_REQ_OK:
1558202bfdffSJames Smart 		if (efc_node_check_els_req(ctx, evt, arg, ELS_ADISC,
1559202bfdffSJames Smart 					   __efc_d_common, __func__))
1560202bfdffSJames Smart 			return;
1561202bfdffSJames Smart 
1562202bfdffSJames Smart 		WARN_ON(!node->els_req_cnt);
1563202bfdffSJames Smart 		node->els_req_cnt--;
1564202bfdffSJames Smart 		efc_node_transition(node, __efc_d_device_ready, NULL);
1565202bfdffSJames Smart 		break;
1566202bfdffSJames Smart 
1567202bfdffSJames Smart 	case EFC_EVT_SRRS_ELS_REQ_RJT:
1568202bfdffSJames Smart 		/* received an LS_RJT, in this case, send shutdown
1569202bfdffSJames Smart 		 * (explicit logo) event which will unregister the node,
1570202bfdffSJames Smart 		 * and start over with PLOGI
1571202bfdffSJames Smart 		 */
1572202bfdffSJames Smart 		if (efc_node_check_els_req(ctx, evt, arg, ELS_ADISC,
1573202bfdffSJames Smart 					   __efc_d_common, __func__))
1574202bfdffSJames Smart 			return;
1575202bfdffSJames Smart 
1576202bfdffSJames Smart 		WARN_ON(!node->els_req_cnt);
1577202bfdffSJames Smart 		node->els_req_cnt--;
1578202bfdffSJames Smart 		/* sm: / post explicit logout */
1579202bfdffSJames Smart 		efc_node_post_event(node,
1580202bfdffSJames Smart 				    EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
1581202bfdffSJames Smart 				     NULL);
1582202bfdffSJames Smart 		break;
1583202bfdffSJames Smart 
1584202bfdffSJames Smart 	case EFC_EVT_LOGO_RCVD: {
1585202bfdffSJames Smart 		/* In this case, we have the equivalent of an LS_RJT for
1586202bfdffSJames Smart 		 * the ADISC, so we need to abort the ADISC, and re-login
1587202bfdffSJames Smart 		 * with PLOGI
1588202bfdffSJames Smart 		 */
1589202bfdffSJames Smart 		/* sm: / request abort, send LOGO acc */
1590202bfdffSJames Smart 		struct fc_frame_header *hdr = cbdata->header->dma.virt;
1591202bfdffSJames Smart 
1592202bfdffSJames Smart 		node_printf(node, "%s received attached=%d\n",
1593202bfdffSJames Smart 			    efc_sm_event_name(evt), node->attached);
1594202bfdffSJames Smart 
1595202bfdffSJames Smart 		efc_send_logo_acc(node, be16_to_cpu(hdr->fh_ox_id));
1596202bfdffSJames Smart 		efc_node_transition(node, __efc_d_wait_logo_acc_cmpl, NULL);
1597202bfdffSJames Smart 		break;
1598202bfdffSJames Smart 	}
1599202bfdffSJames Smart 	default:
1600202bfdffSJames Smart 		__efc_d_common(__func__, ctx, evt, arg);
1601202bfdffSJames Smart 	}
1602202bfdffSJames Smart }
1603