xref: /freebsd/sys/dev/ocs_fc/ocs_device.c (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
1ef270ab1SKenneth D. Merry /*-
2ef270ab1SKenneth D. Merry  * Copyright (c) 2017 Broadcom. All rights reserved.
3ef270ab1SKenneth D. Merry  * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
4ef270ab1SKenneth D. Merry  *
5ef270ab1SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
6ef270ab1SKenneth D. Merry  * modification, are permitted provided that the following conditions are met:
7ef270ab1SKenneth D. Merry  *
8ef270ab1SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright notice,
9ef270ab1SKenneth D. Merry  *    this list of conditions and the following disclaimer.
10ef270ab1SKenneth D. Merry  *
11ef270ab1SKenneth D. Merry  * 2. Redistributions in binary form must reproduce the above copyright notice,
12ef270ab1SKenneth D. Merry  *    this list of conditions and the following disclaimer in the documentation
13ef270ab1SKenneth D. Merry  *    and/or other materials provided with the distribution.
14ef270ab1SKenneth D. Merry  *
15ef270ab1SKenneth D. Merry  * 3. Neither the name of the copyright holder nor the names of its contributors
16ef270ab1SKenneth D. Merry  *    may be used to endorse or promote products derived from this software
17ef270ab1SKenneth D. Merry  *    without specific prior written permission.
18ef270ab1SKenneth D. Merry  *
19ef270ab1SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20ef270ab1SKenneth D. Merry  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21ef270ab1SKenneth D. Merry  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22ef270ab1SKenneth D. Merry  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23ef270ab1SKenneth D. Merry  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24ef270ab1SKenneth D. Merry  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25ef270ab1SKenneth D. Merry  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26ef270ab1SKenneth D. Merry  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27ef270ab1SKenneth D. Merry  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28ef270ab1SKenneth D. Merry  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29ef270ab1SKenneth D. Merry  * POSSIBILITY OF SUCH DAMAGE.
30ef270ab1SKenneth D. Merry  */
31ef270ab1SKenneth D. Merry 
32ef270ab1SKenneth D. Merry /**
33ef270ab1SKenneth D. Merry  * @file
34ef270ab1SKenneth D. Merry  * Implement remote device state machine for target and initiator.
35ef270ab1SKenneth D. Merry  */
36ef270ab1SKenneth D. Merry 
37ef270ab1SKenneth D. Merry /*!
38ef270ab1SKenneth D. Merry @defgroup device_sm Node State Machine: Remote Device States
39ef270ab1SKenneth D. Merry */
40ef270ab1SKenneth D. Merry 
41ef270ab1SKenneth D. Merry #include "ocs.h"
42ef270ab1SKenneth D. Merry #include "ocs_device.h"
43ef270ab1SKenneth D. Merry #include "ocs_fabric.h"
44ef270ab1SKenneth D. Merry #include "ocs_els.h"
45ef270ab1SKenneth D. Merry 
46ef270ab1SKenneth D. Merry static void *__ocs_d_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
47ef270ab1SKenneth D. Merry static void *__ocs_d_wait_del_node(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
48ef270ab1SKenneth D. Merry static void *__ocs_d_wait_del_ini_tgt(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
49ef270ab1SKenneth D. Merry static int32_t ocs_process_abts(ocs_io_t *io, fc_header_t *hdr);
50ef270ab1SKenneth D. Merry 
51ef270ab1SKenneth D. Merry /**
52ef270ab1SKenneth D. Merry  * @ingroup device_sm
53ef270ab1SKenneth D. Merry  * @brief Send response to PRLI.
54ef270ab1SKenneth D. Merry  *
55ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
56ef270ab1SKenneth D. Merry  * For device nodes, this function sends a PRLI response.
57ef270ab1SKenneth D. Merry  *
58ef270ab1SKenneth D. Merry  * @param io Pointer to a SCSI IO object.
59ef270ab1SKenneth D. Merry  * @param ox_id OX_ID of PRLI
60ef270ab1SKenneth D. Merry  *
61ef270ab1SKenneth D. Merry  * @return Returns None.
62ef270ab1SKenneth D. Merry  */
63ef270ab1SKenneth D. Merry 
64ef270ab1SKenneth D. Merry void
ocs_d_send_prli_rsp(ocs_io_t * io,uint16_t ox_id)65ef270ab1SKenneth D. Merry ocs_d_send_prli_rsp(ocs_io_t *io, uint16_t ox_id)
66ef270ab1SKenneth D. Merry {
67ef270ab1SKenneth D. Merry 	ocs_t *ocs = io->ocs;
68ef270ab1SKenneth D. Merry 	ocs_node_t *node = io->node;
69ef270ab1SKenneth D. Merry 
70ef270ab1SKenneth D. Merry 	/* If the back-end doesn't support the fc-type, we send an LS_RJT */
71ef270ab1SKenneth D. Merry 	if (ocs->fc_type != node->fc_type) {
72ef270ab1SKenneth D. Merry 		node_printf(node, "PRLI rejected by target-server, fc-type not supported\n");
73ef270ab1SKenneth D. Merry 		ocs_send_ls_rjt(io, ox_id, FC_REASON_UNABLE_TO_PERFORM,
74ef270ab1SKenneth D. Merry 				FC_EXPL_REQUEST_NOT_SUPPORTED, 0, NULL, NULL);
75ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
76ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL);
77ef270ab1SKenneth D. Merry 	}
78ef270ab1SKenneth D. Merry 
79ef270ab1SKenneth D. Merry 	/* If the back-end doesn't want to talk to this initiator, we send an LS_RJT */
80ef270ab1SKenneth D. Merry 	if (node->sport->enable_tgt && (ocs_scsi_validate_initiator(node) == 0)) {
81ef270ab1SKenneth D. Merry 		node_printf(node, "PRLI rejected by target-server\n");
82ef270ab1SKenneth D. Merry 		ocs_send_ls_rjt(io, ox_id, FC_REASON_UNABLE_TO_PERFORM,
83ef270ab1SKenneth D. Merry 				FC_EXPL_NO_ADDITIONAL, 0, NULL, NULL);
84ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
85ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL);
86ef270ab1SKenneth D. Merry 	} else {
87ef270ab1SKenneth D. Merry 		/*sm:  process PRLI payload, send PRLI acc */
88ef270ab1SKenneth D. Merry 		ocs_send_prli_acc(io, ox_id, ocs->fc_type, NULL, NULL);
89ef270ab1SKenneth D. Merry 
90ef270ab1SKenneth D. Merry 		/* Immediately go to ready state to avoid window where we're
91ef270ab1SKenneth D. Merry 		 * waiting for the PRLI LS_ACC to complete while holding FCP_CMNDs
92ef270ab1SKenneth D. Merry 		 */
93ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_device_ready, NULL);
94ef270ab1SKenneth D. Merry 	}
95ef270ab1SKenneth D. Merry }
96ef270ab1SKenneth D. Merry 
97ef270ab1SKenneth D. Merry /**
98ef270ab1SKenneth D. Merry  * @ingroup device_sm
99ef270ab1SKenneth D. Merry  * @brief Device node state machine: Initiate node shutdown
100ef270ab1SKenneth D. Merry  *
101ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
102ef270ab1SKenneth D. Merry  * @param evt Event to process.
103ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
104ef270ab1SKenneth D. Merry  *
105ef270ab1SKenneth D. Merry  * @return Returns NULL.
106ef270ab1SKenneth D. Merry  */
107ef270ab1SKenneth D. Merry 
108ef270ab1SKenneth D. Merry void *
__ocs_d_initiate_shutdown(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)109ef270ab1SKenneth D. Merry __ocs_d_initiate_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
110ef270ab1SKenneth D. Merry {
111ef270ab1SKenneth D. Merry 	std_node_state_decl();
112ef270ab1SKenneth D. Merry 
113ef270ab1SKenneth D. Merry 	node_sm_trace();
114ef270ab1SKenneth D. Merry 
115ef270ab1SKenneth D. Merry 	switch(evt) {
116ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER: {
117ef270ab1SKenneth D. Merry 		int32_t rc = OCS_SCSI_CALL_COMPLETE; /* assume no wait needed */
118ef270ab1SKenneth D. Merry 
119ef270ab1SKenneth D. Merry 		ocs_scsi_io_alloc_disable(node);
120ef270ab1SKenneth D. Merry 
121ef270ab1SKenneth D. Merry 		/* make necessary delete upcall(s) */
122ef270ab1SKenneth D. Merry 		if (node->init && !node->targ) {
123ef270ab1SKenneth D. Merry 			ocs_log_debug(node->ocs,
124ef270ab1SKenneth D. Merry 				"[%s] delete (initiator) WWPN %s WWNN %s\n",
125ef270ab1SKenneth D. Merry 				node->display_name, node->wwpn, node->wwnn);
126ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_d_wait_del_node, NULL);
127ef270ab1SKenneth D. Merry 			if (node->sport->enable_tgt) {
128ef270ab1SKenneth D. Merry 				rc = ocs_scsi_del_initiator(node,
129ef270ab1SKenneth D. Merry 						OCS_SCSI_INITIATOR_DELETED);
130ef270ab1SKenneth D. Merry 			}
131ef270ab1SKenneth D. Merry 			if (rc == OCS_SCSI_CALL_COMPLETE) {
132ef270ab1SKenneth D. Merry 				ocs_node_post_event(node,
133ef270ab1SKenneth D. Merry 					OCS_EVT_NODE_DEL_INI_COMPLETE, NULL);
134ef270ab1SKenneth D. Merry 			}
135ef270ab1SKenneth D. Merry 		} else if (node->targ && !node->init) {
136ef270ab1SKenneth D. Merry 			ocs_log_debug(node->ocs,
137ef270ab1SKenneth D. Merry 				"[%s] delete (target)    WWPN %s WWNN %s\n",
138ef270ab1SKenneth D. Merry 				node->display_name, node->wwpn, node->wwnn);
139ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_d_wait_del_node, NULL);
140ef270ab1SKenneth D. Merry 			if (node->sport->enable_ini) {
141ef270ab1SKenneth D. Merry 				rc = ocs_scsi_del_target(node,
142ef270ab1SKenneth D. Merry 						OCS_SCSI_TARGET_DELETED);
143ef270ab1SKenneth D. Merry 			}
144ef270ab1SKenneth D. Merry 			if (rc == OCS_SCSI_CALL_COMPLETE) {
145ef270ab1SKenneth D. Merry 				ocs_node_post_event(node,
146ef270ab1SKenneth D. Merry 					OCS_EVT_NODE_DEL_TGT_COMPLETE, NULL);
147ef270ab1SKenneth D. Merry 			}
148ef270ab1SKenneth D. Merry 		} else if (node->init && node->targ) {
149ef270ab1SKenneth D. Merry 			ocs_log_debug(node->ocs,
150ef270ab1SKenneth D. Merry 				"[%s] delete (initiator+target) WWPN %s WWNN %s\n",
151ef270ab1SKenneth D. Merry 				node->display_name, node->wwpn, node->wwnn);
152ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_d_wait_del_ini_tgt, NULL);
153ef270ab1SKenneth D. Merry 			if (node->sport->enable_tgt) {
154ef270ab1SKenneth D. Merry 				rc = ocs_scsi_del_initiator(node,
155ef270ab1SKenneth D. Merry 						OCS_SCSI_INITIATOR_DELETED);
156ef270ab1SKenneth D. Merry 			}
157ef270ab1SKenneth D. Merry 			if (rc == OCS_SCSI_CALL_COMPLETE) {
158ef270ab1SKenneth D. Merry 				ocs_node_post_event(node,
159ef270ab1SKenneth D. Merry 					OCS_EVT_NODE_DEL_INI_COMPLETE, NULL);
160ef270ab1SKenneth D. Merry 			}
161ef270ab1SKenneth D. Merry 			rc = OCS_SCSI_CALL_COMPLETE; /* assume no wait needed */
162ef270ab1SKenneth D. Merry 			if (node->sport->enable_ini) {
163ef270ab1SKenneth D. Merry 				rc = ocs_scsi_del_target(node,
164ef270ab1SKenneth D. Merry 						OCS_SCSI_TARGET_DELETED);
165ef270ab1SKenneth D. Merry 			}
166ef270ab1SKenneth D. Merry 			if (rc == OCS_SCSI_CALL_COMPLETE) {
167ef270ab1SKenneth D. Merry 				ocs_node_post_event(node,
168ef270ab1SKenneth D. Merry 					OCS_EVT_NODE_DEL_TGT_COMPLETE, NULL);
169ef270ab1SKenneth D. Merry 			}
170ef270ab1SKenneth D. Merry 		}
171ef270ab1SKenneth D. Merry 
172ef270ab1SKenneth D. Merry 		/* we've initiated the upcalls as needed, now kick off the node
173ef270ab1SKenneth D. Merry 		 * detach to precipitate the aborting of outstanding exchanges
174ef270ab1SKenneth D. Merry 		 * associated with said node
175ef270ab1SKenneth D. Merry 		 *
176ef270ab1SKenneth D. Merry 		 * Beware: if we've made upcall(s), we've already transitioned
177ef270ab1SKenneth D. Merry 		 * to a new state by the time we execute this.
178ef270ab1SKenneth D. Merry 		 * TODO: consider doing this before the upcalls...
179ef270ab1SKenneth D. Merry 		 */
180ef270ab1SKenneth D. Merry 		if (node->attached) {
181ef270ab1SKenneth D. Merry 			/* issue hw node free; don't care if succeeds right away
182ef270ab1SKenneth D. Merry 			 * or sometime later, will check node->attached later in
183ef270ab1SKenneth D. Merry 			 * shutdown process
184ef270ab1SKenneth D. Merry 			 */
185ef270ab1SKenneth D. Merry 			rc = ocs_hw_node_detach(&ocs->hw, &node->rnode);
186ef270ab1SKenneth D. Merry 			if (node->rnode.free_group) {
187ef270ab1SKenneth D. Merry 				ocs_remote_node_group_free(node->node_group);
188ef270ab1SKenneth D. Merry 				node->node_group = NULL;
189ef270ab1SKenneth D. Merry 				node->rnode.free_group = FALSE;
190ef270ab1SKenneth D. Merry 			}
191ef270ab1SKenneth D. Merry 			if (rc != OCS_HW_RTN_SUCCESS &&
192ef270ab1SKenneth D. Merry 				rc != OCS_HW_RTN_SUCCESS_SYNC) {
193ef270ab1SKenneth D. Merry 				node_printf(node,
194ef270ab1SKenneth D. Merry 					"Failed freeing HW node, rc=%d\n", rc);
195ef270ab1SKenneth D. Merry 			}
196ef270ab1SKenneth D. Merry 		}
197ef270ab1SKenneth D. Merry 
198ef270ab1SKenneth D. Merry 		/* if neither initiator nor target, proceed to cleanup */
199ef270ab1SKenneth D. Merry 		if (!node->init && !node->targ){
200ef270ab1SKenneth D. Merry 			/*
201ef270ab1SKenneth D. Merry 			 * node has either been detached or is in the process
202ef270ab1SKenneth D. Merry 			 * of being detached, call common node's initiate
203ef270ab1SKenneth D. Merry 			 * cleanup function.
204ef270ab1SKenneth D. Merry 			 */
205ef270ab1SKenneth D. Merry 			ocs_node_initiate_cleanup(node);
206ef270ab1SKenneth D. Merry 		}
207ef270ab1SKenneth D. Merry 		break;
208ef270ab1SKenneth D. Merry 	}
209ef270ab1SKenneth D. Merry 	case OCS_EVT_ALL_CHILD_NODES_FREE:
210ef270ab1SKenneth D. Merry 		/* Ignore, this can happen if an ELS is aborted,
211ef270ab1SKenneth D. Merry 		 * while in a delay/retry state */
212ef270ab1SKenneth D. Merry 		break;
213ef270ab1SKenneth D. Merry 	default:
214ef270ab1SKenneth D. Merry 		__ocs_d_common(__func__, ctx, evt, arg);
215ef270ab1SKenneth D. Merry 		return NULL;
216ef270ab1SKenneth D. Merry 	}
217ef270ab1SKenneth D. Merry 	return NULL;
218ef270ab1SKenneth D. Merry }
219ef270ab1SKenneth D. Merry 
220ef270ab1SKenneth D. Merry /**
221ef270ab1SKenneth D. Merry  * @ingroup device_sm
222ef270ab1SKenneth D. Merry  * @brief Device node state machine: Common device event handler.
223ef270ab1SKenneth D. Merry  *
224ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
225ef270ab1SKenneth D. Merry  * For device nodes, this event handler manages default and common events.
226ef270ab1SKenneth D. Merry  *
227ef270ab1SKenneth D. Merry  * @param funcname Function name text.
228ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
229ef270ab1SKenneth D. Merry  * @param evt Event to process.
230ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
231ef270ab1SKenneth D. Merry  *
232ef270ab1SKenneth D. Merry  * @return Returns NULL.
233ef270ab1SKenneth D. Merry  */
234ef270ab1SKenneth D. Merry 
235ef270ab1SKenneth D. Merry static void *
__ocs_d_common(const char * funcname,ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)236ef270ab1SKenneth D. Merry __ocs_d_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
237ef270ab1SKenneth D. Merry {
238ef270ab1SKenneth D. Merry 	ocs_node_t *node = NULL;
239ef270ab1SKenneth D. Merry 	ocs_t *ocs = NULL;
240ef270ab1SKenneth D. Merry 	ocs_assert(ctx, NULL);
241ef270ab1SKenneth D. Merry 	node = ctx->app;
242ef270ab1SKenneth D. Merry 	ocs_assert(node, NULL);
243ef270ab1SKenneth D. Merry 	ocs = node->ocs;
244ef270ab1SKenneth D. Merry 	ocs_assert(ocs, NULL);
245ef270ab1SKenneth D. Merry 
246ef270ab1SKenneth D. Merry 	switch(evt) {
247ef270ab1SKenneth D. Merry 	/* Handle shutdown events */
248ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN:
249ef270ab1SKenneth D. Merry 		ocs_log_debug(ocs, "[%s] %-20s %-20s\n", node->display_name, funcname, ocs_sm_event_name(evt));
250ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
251ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL);
252ef270ab1SKenneth D. Merry 		break;
253ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO:
254ef270ab1SKenneth D. Merry 		ocs_log_debug(ocs, "[%s] %-20s %-20s\n", node->display_name, funcname, ocs_sm_event_name(evt));
255ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_EXPLICIT_LOGO;
256ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL);
257ef270ab1SKenneth D. Merry 		break;
258ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO:
259ef270ab1SKenneth D. Merry 		ocs_log_debug(ocs, "[%s] %-20s %-20s\n", node->display_name, funcname, ocs_sm_event_name(evt));
260ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_IMPLICIT_LOGO;
261ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL);
262ef270ab1SKenneth D. Merry 		break;
263ef270ab1SKenneth D. Merry 
264ef270ab1SKenneth D. Merry 	default:
265ef270ab1SKenneth D. Merry 		/* call default event handler common to all nodes */
266ef270ab1SKenneth D. Merry 		__ocs_node_common(funcname, ctx, evt, arg);
267ef270ab1SKenneth D. Merry 		break;
268ef270ab1SKenneth D. Merry 	}
269ef270ab1SKenneth D. Merry 	return NULL;
270ef270ab1SKenneth D. Merry }
271ef270ab1SKenneth D. Merry 
272ef270ab1SKenneth D. Merry /**
273ef270ab1SKenneth D. Merry  * @ingroup device_sm
274ef270ab1SKenneth D. Merry  * @brief Device node state machine: Wait for a domain-attach completion in loop topology.
275ef270ab1SKenneth D. Merry  *
276ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
277ef270ab1SKenneth D. Merry  * State waits for a domain-attached completion while in loop topology.
278ef270ab1SKenneth D. Merry  *
279ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
280ef270ab1SKenneth D. Merry  * @param evt Event to process.
281ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
282ef270ab1SKenneth D. Merry  *
283ef270ab1SKenneth D. Merry  * @return Returns NULL.
284ef270ab1SKenneth D. Merry  */
285ef270ab1SKenneth D. Merry 
286ef270ab1SKenneth D. Merry void *
__ocs_d_wait_loop(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)287ef270ab1SKenneth D. Merry __ocs_d_wait_loop(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
288ef270ab1SKenneth D. Merry {
289ef270ab1SKenneth D. Merry 	std_node_state_decl();
290ef270ab1SKenneth D. Merry 
291ef270ab1SKenneth D. Merry 	node_sm_trace();
292ef270ab1SKenneth D. Merry 
293ef270ab1SKenneth D. Merry 	switch(evt) {
294ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
295ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
296ef270ab1SKenneth D. Merry 		break;
297ef270ab1SKenneth D. Merry 
298ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
299ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
300ef270ab1SKenneth D. Merry 		break;
301ef270ab1SKenneth D. Merry 
302ef270ab1SKenneth D. Merry 	case OCS_EVT_DOMAIN_ATTACH_OK: {
303ef270ab1SKenneth D. Merry 		/* send PLOGI automatically if initiator */
304ef270ab1SKenneth D. Merry 		ocs_node_init_device(node, TRUE);
305ef270ab1SKenneth D. Merry 		break;
306ef270ab1SKenneth D. Merry 	}
307ef270ab1SKenneth D. Merry 	default:
308ef270ab1SKenneth D. Merry 		__ocs_d_common(__func__, ctx, evt, arg);
309ef270ab1SKenneth D. Merry 		return NULL;
310ef270ab1SKenneth D. Merry 	}
311ef270ab1SKenneth D. Merry 
312ef270ab1SKenneth D. Merry 	return NULL;
313ef270ab1SKenneth D. Merry }
314ef270ab1SKenneth D. Merry 
315ef270ab1SKenneth D. Merry /**
316ef270ab1SKenneth D. Merry  * @ingroup device_sm
317ef270ab1SKenneth D. Merry  * @brief state: wait for node resume event
318ef270ab1SKenneth D. Merry  *
319ef270ab1SKenneth D. Merry  * State is entered when a node is in I+T mode and sends a delete initiator/target
320ef270ab1SKenneth D. Merry  * call to the target-server/initiator-client and needs to wait for that work to complete.
321ef270ab1SKenneth D. Merry  *
322ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
323ef270ab1SKenneth D. Merry  * @param evt Event to process.
324ef270ab1SKenneth D. Merry  * @param arg per event optional argument
325ef270ab1SKenneth D. Merry  *
326ef270ab1SKenneth D. Merry  * @return returns NULL
327ef270ab1SKenneth D. Merry  */
328ef270ab1SKenneth D. Merry 
329ef270ab1SKenneth D. Merry void *
__ocs_d_wait_del_ini_tgt(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)330ef270ab1SKenneth D. Merry __ocs_d_wait_del_ini_tgt(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
331ef270ab1SKenneth D. Merry {
332ef270ab1SKenneth D. Merry 	std_node_state_decl();
333ef270ab1SKenneth D. Merry 
334ef270ab1SKenneth D. Merry 	node_sm_trace();
335ef270ab1SKenneth D. Merry 
336ef270ab1SKenneth D. Merry 	switch(evt) {
337ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
338ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
339ef270ab1SKenneth D. Merry 		/* Fall through */
340ef270ab1SKenneth D. Merry 
341ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
342ef270ab1SKenneth D. Merry 	case OCS_EVT_ALL_CHILD_NODES_FREE:
343ef270ab1SKenneth D. Merry 		/* These are expected events. */
344ef270ab1SKenneth D. Merry 		break;
345ef270ab1SKenneth D. Merry 
346ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_DEL_INI_COMPLETE:
347ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_DEL_TGT_COMPLETE:
348ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_wait_del_node, NULL);
349ef270ab1SKenneth D. Merry 		break;
350ef270ab1SKenneth D. Merry 
351ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
352ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
353ef270ab1SKenneth D. Merry 		break;
354ef270ab1SKenneth D. Merry 
355ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_FAIL:
356ef270ab1SKenneth D. Merry 		/* Can happen as ELS IO IO's complete */
357ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
358ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
359ef270ab1SKenneth D. Merry 		break;
360ef270ab1SKenneth D. Merry 
361ef270ab1SKenneth D. Merry 	/* ignore shutdown events as we're already in shutdown path */
362ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN:
363ef270ab1SKenneth D. Merry 		/* have default shutdown event take precedence */
364ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
365ef270ab1SKenneth D. Merry 		/* fall through */
366ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO:
367ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO:
368ef270ab1SKenneth D. Merry 		node_printf(node, "%s received\n", ocs_sm_event_name(evt));
369ef270ab1SKenneth D. Merry 		break;
370ef270ab1SKenneth D. Merry 	case OCS_EVT_DOMAIN_ATTACH_OK:
371ef270ab1SKenneth D. Merry 		/* don't care about domain_attach_ok */
372ef270ab1SKenneth D. Merry 		break;
373ef270ab1SKenneth D. Merry 	default:
374ef270ab1SKenneth D. Merry 		__ocs_d_common(__func__, ctx, evt, arg);
375ef270ab1SKenneth D. Merry 		return NULL;
376ef270ab1SKenneth D. Merry 	}
377ef270ab1SKenneth D. Merry 
378ef270ab1SKenneth D. Merry 	return NULL;
379ef270ab1SKenneth D. Merry }
380ef270ab1SKenneth D. Merry 
381ef270ab1SKenneth D. Merry /**
382ef270ab1SKenneth D. Merry  * @ingroup device_sm
383ef270ab1SKenneth D. Merry  * @brief state: Wait for node resume event.
384ef270ab1SKenneth D. Merry  *
385ef270ab1SKenneth D. Merry  * State is entered when a node sends a delete initiator/target call to the
386ef270ab1SKenneth D. Merry  * target-server/initiator-client and needs to wait for that work to complete.
387ef270ab1SKenneth D. Merry  *
388ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
389ef270ab1SKenneth D. Merry  * @param evt Event to process.
390ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
391ef270ab1SKenneth D. Merry  *
392ef270ab1SKenneth D. Merry  * @return Returns NULL.
393ef270ab1SKenneth D. Merry  */
394ef270ab1SKenneth D. Merry 
395ef270ab1SKenneth D. Merry void *
__ocs_d_wait_del_node(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)396ef270ab1SKenneth D. Merry __ocs_d_wait_del_node(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
397ef270ab1SKenneth D. Merry {
398ef270ab1SKenneth D. Merry 	std_node_state_decl();
399ef270ab1SKenneth D. Merry 
400ef270ab1SKenneth D. Merry 	node_sm_trace();
401ef270ab1SKenneth D. Merry 
402ef270ab1SKenneth D. Merry 	switch(evt) {
403ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
404ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
405ef270ab1SKenneth D. Merry 		/* Fall through */
406ef270ab1SKenneth D. Merry 
407ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
408ef270ab1SKenneth D. Merry 	case OCS_EVT_ALL_CHILD_NODES_FREE:
409ef270ab1SKenneth D. Merry 		/* These are expected events. */
410ef270ab1SKenneth D. Merry 		break;
411ef270ab1SKenneth D. Merry 
412ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_DEL_INI_COMPLETE:
413ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_DEL_TGT_COMPLETE:
414ef270ab1SKenneth D. Merry 		/*
415ef270ab1SKenneth D. Merry 		 * node has either been detached or is in the process of being detached,
416ef270ab1SKenneth D. Merry 		 * call common node's initiate cleanup function
417ef270ab1SKenneth D. Merry 		 */
418ef270ab1SKenneth D. Merry 		ocs_node_initiate_cleanup(node);
419ef270ab1SKenneth D. Merry 		break;
420ef270ab1SKenneth D. Merry 
421ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
422ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
423ef270ab1SKenneth D. Merry 		break;
424ef270ab1SKenneth D. Merry 
425ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_FAIL:
426ef270ab1SKenneth D. Merry 		/* Can happen as ELS IO IO's complete */
427ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
428ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
429ef270ab1SKenneth D. Merry 		break;
430ef270ab1SKenneth D. Merry 
431ef270ab1SKenneth D. Merry 	/* ignore shutdown events as we're already in shutdown path */
432ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN:
433ef270ab1SKenneth D. Merry 		/* have default shutdown event take precedence */
434ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
435ef270ab1SKenneth D. Merry 		/* fall through */
436ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO:
437ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO:
438ef270ab1SKenneth D. Merry 		node_printf(node, "%s received\n", ocs_sm_event_name(evt));
439ef270ab1SKenneth D. Merry 		break;
440ef270ab1SKenneth D. Merry 	case OCS_EVT_DOMAIN_ATTACH_OK:
441ef270ab1SKenneth D. Merry 		/* don't care about domain_attach_ok */
442ef270ab1SKenneth D. Merry 		break;
443ef270ab1SKenneth D. Merry 	default:
444ef270ab1SKenneth D. Merry 		__ocs_d_common(__func__, ctx, evt, arg);
445ef270ab1SKenneth D. Merry 		return NULL;
446ef270ab1SKenneth D. Merry 	}
447ef270ab1SKenneth D. Merry 
448ef270ab1SKenneth D. Merry 	return NULL;
449ef270ab1SKenneth D. Merry }
450ef270ab1SKenneth D. Merry 
451ef270ab1SKenneth D. Merry /**
452ef270ab1SKenneth D. Merry  * @brief Save the OX_ID for sending LS_ACC sometime later.
453ef270ab1SKenneth D. Merry  *
454ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
455ef270ab1SKenneth D. Merry  * When deferring the response to an ELS request, the OX_ID of the request
456ef270ab1SKenneth D. Merry  * is saved using this function.
457ef270ab1SKenneth D. Merry  *
458ef270ab1SKenneth D. Merry  * @param io Pointer to a SCSI IO object.
459ef270ab1SKenneth D. Merry  * @param hdr Pointer to the FC header.
460ef270ab1SKenneth D. Merry  * @param ls Defines the type of ELS to send: LS_ACC, LS_ACC for PLOGI;
461ef270ab1SKenneth D. Merry  * or LSS_ACC for PRLI.
462ef270ab1SKenneth D. Merry  *
463ef270ab1SKenneth D. Merry  * @return None.
464ef270ab1SKenneth D. Merry  */
465ef270ab1SKenneth D. Merry 
466ef270ab1SKenneth D. Merry void
ocs_send_ls_acc_after_attach(ocs_io_t * io,fc_header_t * hdr,ocs_node_send_ls_acc_e ls)467ef270ab1SKenneth D. Merry ocs_send_ls_acc_after_attach(ocs_io_t *io, fc_header_t *hdr, ocs_node_send_ls_acc_e ls)
468ef270ab1SKenneth D. Merry {
469ef270ab1SKenneth D. Merry 	ocs_node_t *node = io->node;
470ef270ab1SKenneth D. Merry 	uint16_t ox_id = ocs_be16toh(hdr->ox_id);
471ef270ab1SKenneth D. Merry 
472ef270ab1SKenneth D. Merry 	ocs_assert(node->send_ls_acc == OCS_NODE_SEND_LS_ACC_NONE);
473ef270ab1SKenneth D. Merry 
474ef270ab1SKenneth D. Merry 	node->ls_acc_oxid = ox_id;
475ef270ab1SKenneth D. Merry 	node->send_ls_acc = ls;
476ef270ab1SKenneth D. Merry 	node->ls_acc_io = io;
477ef270ab1SKenneth D. Merry 	node->ls_acc_did = fc_be24toh(hdr->d_id);
478ef270ab1SKenneth D. Merry }
479ef270ab1SKenneth D. Merry 
480ef270ab1SKenneth D. Merry /**
481ef270ab1SKenneth D. Merry  * @brief Process the PRLI payload.
482ef270ab1SKenneth D. Merry  *
483ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
484ef270ab1SKenneth D. Merry  * The PRLI payload is processed; the initiator/target capabilities of the
485ef270ab1SKenneth D. Merry  * remote node are extracted and saved in the node object.
486ef270ab1SKenneth D. Merry  *
487ef270ab1SKenneth D. Merry  * @param node Pointer to the node object.
488ef270ab1SKenneth D. Merry  * @param prli Pointer to the PRLI payload.
489ef270ab1SKenneth D. Merry  *
490ef270ab1SKenneth D. Merry  * @return None.
491ef270ab1SKenneth D. Merry  */
492ef270ab1SKenneth D. Merry 
493ef270ab1SKenneth D. Merry void
ocs_process_prli_payload(ocs_node_t * node,fc_prli_payload_t * prli)494ef270ab1SKenneth D. Merry ocs_process_prli_payload(ocs_node_t *node, fc_prli_payload_t *prli)
495ef270ab1SKenneth D. Merry {
496ef270ab1SKenneth D. Merry 	node->init = (ocs_be16toh(prli->service_params) & FC_PRLI_INITIATOR_FUNCTION) != 0;
497ef270ab1SKenneth D. Merry 	node->targ = (ocs_be16toh(prli->service_params) & FC_PRLI_TARGET_FUNCTION) != 0;
498ef270ab1SKenneth D. Merry 	node->fcp2device = (ocs_be16toh(prli->service_params) & FC_PRLI_RETRY) != 0;
499ef270ab1SKenneth D. Merry 	node->fc_type = prli->type;
500ef270ab1SKenneth D. Merry }
501ef270ab1SKenneth D. Merry 
502ef270ab1SKenneth D. Merry /**
503ef270ab1SKenneth D. Merry  * @brief Process the ABTS.
504ef270ab1SKenneth D. Merry  *
505ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
506ef270ab1SKenneth D. Merry  * Common code to process a received ABTS. If an active IO can be found
507ef270ab1SKenneth D. Merry  * that matches the OX_ID of the ABTS request, a call is made to the
508ef270ab1SKenneth D. Merry  * backend. Otherwise, a BA_ACC is returned to the initiator.
509ef270ab1SKenneth D. Merry  *
510ef270ab1SKenneth D. Merry  * @param io Pointer to a SCSI IO object.
511ef270ab1SKenneth D. Merry  * @param hdr Pointer to the FC header.
512ef270ab1SKenneth D. Merry  *
513ef270ab1SKenneth D. Merry  * @return Returns 0 on success, or a negative error value on failure.
514ef270ab1SKenneth D. Merry  */
515ef270ab1SKenneth D. Merry 
516ef270ab1SKenneth D. Merry static int32_t
ocs_process_abts(ocs_io_t * io,fc_header_t * hdr)517ef270ab1SKenneth D. Merry ocs_process_abts(ocs_io_t *io, fc_header_t *hdr)
518ef270ab1SKenneth D. Merry {
519ef270ab1SKenneth D. Merry 	ocs_node_t *node = io->node;
520ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
521ef270ab1SKenneth D. Merry 	uint16_t ox_id = ocs_be16toh(hdr->ox_id);
522ef270ab1SKenneth D. Merry 	uint16_t rx_id = ocs_be16toh(hdr->rx_id);
523ef270ab1SKenneth D. Merry 	ocs_io_t *abortio;
524ef270ab1SKenneth D. Merry 
525ef270ab1SKenneth D. Merry 	abortio = ocs_io_find_tgt_io(ocs, node, ox_id, rx_id);
526ef270ab1SKenneth D. Merry 
527ef270ab1SKenneth D. Merry 	/* If an IO was found, attempt to take a reference on it */
528ef270ab1SKenneth D. Merry 	if (abortio != NULL && (ocs_ref_get_unless_zero(&abortio->ref) != 0)) {
529ef270ab1SKenneth D. Merry 		/* Got a reference on the IO. Hold it until backend is notified below */
530ef270ab1SKenneth D. Merry 		node_printf(node, "Abort request: ox_id [%04x] rx_id [%04x]\n",
531ef270ab1SKenneth D. Merry 			    ox_id, rx_id);
532ef270ab1SKenneth D. Merry 
533ef270ab1SKenneth D. Merry 		/*
534ef270ab1SKenneth D. Merry 		 * Save the ox_id for the ABTS as the init_task_tag in our manufactured
535ef270ab1SKenneth D. Merry 		 * TMF IO object
536ef270ab1SKenneth D. Merry 		 */
537ef270ab1SKenneth D. Merry 		io->display_name = "abts";
538ef270ab1SKenneth D. Merry 		io->init_task_tag = ox_id;
539ef270ab1SKenneth D. Merry 		/* don't set tgt_task_tag, don't want to confuse with XRI */
540ef270ab1SKenneth D. Merry 
541ef270ab1SKenneth D. Merry 		/*
542ef270ab1SKenneth D. Merry 		 * Save the rx_id from the ABTS as it is needed for the BLS response,
543ef270ab1SKenneth D. Merry 		 * regardless of the IO context's rx_id
544ef270ab1SKenneth D. Merry 		 */
545ef270ab1SKenneth D. Merry 		io->abort_rx_id = rx_id;
546ef270ab1SKenneth D. Merry 
547ef270ab1SKenneth D. Merry 		/* Call target server command abort */
548ef270ab1SKenneth D. Merry 		io->tmf_cmd = OCS_SCSI_TMF_ABORT_TASK;
549ef270ab1SKenneth D. Merry 		ocs_scsi_recv_tmf(io, abortio->tgt_io.lun, OCS_SCSI_TMF_ABORT_TASK, abortio, 0);
550ef270ab1SKenneth D. Merry 
551ef270ab1SKenneth D. Merry 		/*
552ef270ab1SKenneth D. Merry 		 * Backend will have taken an additional reference on the IO if needed;
553ef270ab1SKenneth D. Merry 		 * done with current reference.
554ef270ab1SKenneth D. Merry 		 */
555ef270ab1SKenneth D. Merry 		ocs_ref_put(&abortio->ref); /* ocs_ref_get(): same function */
556ef270ab1SKenneth D. Merry 	} else {
557ef270ab1SKenneth D. Merry 		/*
558ef270ab1SKenneth D. Merry 		 * Either IO was not found or it has been freed between finding it
559ef270ab1SKenneth D. Merry 		 * and attempting to get the reference,
560ef270ab1SKenneth D. Merry 		 */
561ef270ab1SKenneth D. Merry 		node_printf(node, "Abort request: ox_id [%04x], IO not found (exists=%d)\n",
562ef270ab1SKenneth D. Merry 			    ox_id, (abortio != NULL));
563ef270ab1SKenneth D. Merry 
564ef270ab1SKenneth D. Merry 		/* Send a BA_ACC */
565ef270ab1SKenneth D. Merry 		ocs_bls_send_acc_hdr(io, hdr);
566ef270ab1SKenneth D. Merry 	}
567ef270ab1SKenneth D. Merry 	return 0;
568ef270ab1SKenneth D. Merry }
569ef270ab1SKenneth D. Merry 
570ef270ab1SKenneth D. Merry /**
571ef270ab1SKenneth D. Merry  * @ingroup device_sm
572ef270ab1SKenneth D. Merry  * @brief Device node state machine: Wait for the PLOGI accept to complete.
573ef270ab1SKenneth D. Merry  *
574ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
575ef270ab1SKenneth D. Merry  * @param evt Event to process.
576ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
577ef270ab1SKenneth D. Merry  *
578ef270ab1SKenneth D. Merry  * @return Returns NULL.
579ef270ab1SKenneth D. Merry  */
580ef270ab1SKenneth D. Merry 
581ef270ab1SKenneth D. Merry void *
__ocs_d_wait_plogi_acc_cmpl(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)582ef270ab1SKenneth D. Merry __ocs_d_wait_plogi_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
583ef270ab1SKenneth D. Merry {
584ef270ab1SKenneth D. Merry 	std_node_state_decl();
585ef270ab1SKenneth D. Merry 
586ef270ab1SKenneth D. Merry 	node_sm_trace();
587ef270ab1SKenneth D. Merry 
588ef270ab1SKenneth D. Merry 	switch(evt) {
589ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
590ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
591ef270ab1SKenneth D. Merry 		break;
592ef270ab1SKenneth D. Merry 
593ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
594ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
595ef270ab1SKenneth D. Merry 		break;
596ef270ab1SKenneth D. Merry 
597ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_CMPL_FAIL:
598ef270ab1SKenneth D. Merry 		ocs_assert(node->els_cmpl_cnt, NULL);
599ef270ab1SKenneth D. Merry 		node->els_cmpl_cnt--;
600ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
601ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL);
602ef270ab1SKenneth D. Merry 		break;
603ef270ab1SKenneth D. Merry 
604ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_CMPL_OK:	/* PLOGI ACC completions */
605ef270ab1SKenneth D. Merry 		ocs_assert(node->els_cmpl_cnt, NULL);
606ef270ab1SKenneth D. Merry 		node->els_cmpl_cnt--;
607ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_port_logged_in, NULL);
608ef270ab1SKenneth D. Merry 		break;
609ef270ab1SKenneth D. Merry 
610ef270ab1SKenneth D. Merry 	default:
611ef270ab1SKenneth D. Merry 		__ocs_d_common(__func__, ctx, evt, arg);
612ef270ab1SKenneth D. Merry 		return NULL;
613ef270ab1SKenneth D. Merry 	}
614ef270ab1SKenneth D. Merry 
615ef270ab1SKenneth D. Merry 	return NULL;
616ef270ab1SKenneth D. Merry }
617ef270ab1SKenneth D. Merry 
618ef270ab1SKenneth D. Merry /**
619ef270ab1SKenneth D. Merry  * @ingroup device_sm
620ef270ab1SKenneth D. Merry  * @brief Device node state machine: Wait for the LOGO response.
621ef270ab1SKenneth D. Merry  *
622ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
623ef270ab1SKenneth D. Merry  * @param evt Event to process.
624ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
625ef270ab1SKenneth D. Merry  *
626ef270ab1SKenneth D. Merry  * @return Returns NULL.
627ef270ab1SKenneth D. Merry  */
628ef270ab1SKenneth D. Merry 
629ef270ab1SKenneth D. Merry void *
__ocs_d_wait_logo_rsp(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)630ef270ab1SKenneth D. Merry __ocs_d_wait_logo_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
631ef270ab1SKenneth D. Merry {
632ef270ab1SKenneth D. Merry 	std_node_state_decl();
633ef270ab1SKenneth D. Merry 
634ef270ab1SKenneth D. Merry 	node_sm_trace();
635ef270ab1SKenneth D. Merry 
636ef270ab1SKenneth D. Merry 	switch(evt) {
637ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
638ef270ab1SKenneth D. Merry 		/* TODO: may want to remove this;
639ef270ab1SKenneth D. Merry 		 * if we'll want to know about PLOGI */
640ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
641ef270ab1SKenneth D. Merry 		break;
642ef270ab1SKenneth D. Merry 
643ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
644ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
645ef270ab1SKenneth D. Merry 		break;
646ef270ab1SKenneth D. Merry 
647ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_OK:
648ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_RJT:
649ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_FAIL:
650ef270ab1SKenneth D. Merry 		/* LOGO response received, sent shutdown */
651ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_LOGO, __ocs_d_common, __func__)) {
652ef270ab1SKenneth D. Merry 			return NULL;
653ef270ab1SKenneth D. Merry 		}
654ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
655ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
656ef270ab1SKenneth D. Merry 		node_printf(node, "LOGO sent (evt=%s), shutdown node\n", ocs_sm_event_name(evt));
657ef270ab1SKenneth D. Merry 		/* sm: post explicit logout */
658ef270ab1SKenneth D. Merry 		ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
659ef270ab1SKenneth D. Merry 		break;
660ef270ab1SKenneth D. Merry 
661ef270ab1SKenneth D. Merry 	/* TODO: PLOGI: abort LOGO and process PLOGI? (SHUTDOWN_EXPLICIT/IMPLICIT_LOGO?) */
662ef270ab1SKenneth D. Merry 
663ef270ab1SKenneth D. Merry 	default:
664ef270ab1SKenneth D. Merry 		__ocs_d_common(__func__, ctx, evt, arg);
665ef270ab1SKenneth D. Merry 		return NULL;
666ef270ab1SKenneth D. Merry 	}
667ef270ab1SKenneth D. Merry 	return NULL;
668ef270ab1SKenneth D. Merry }
669ef270ab1SKenneth D. Merry 
670ef270ab1SKenneth D. Merry /**
671ef270ab1SKenneth D. Merry  * @ingroup device_sm
672ef270ab1SKenneth D. Merry  * @brief Device node state machine: Wait for the PRLO response.
673ef270ab1SKenneth D. Merry  *
674ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
675ef270ab1SKenneth D. Merry  * @param evt Event to process.
676ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
677ef270ab1SKenneth D. Merry  *
678ef270ab1SKenneth D. Merry  * @return Returns NULL.
679ef270ab1SKenneth D. Merry  */
680ef270ab1SKenneth D. Merry 
681ef270ab1SKenneth D. Merry void *
__ocs_d_wait_prlo_rsp(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)682ef270ab1SKenneth D. Merry __ocs_d_wait_prlo_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
683ef270ab1SKenneth D. Merry {
684ef270ab1SKenneth D. Merry 	std_node_state_decl();
685ef270ab1SKenneth D. Merry 
686ef270ab1SKenneth D. Merry 	node_sm_trace();
687ef270ab1SKenneth D. Merry 
688ef270ab1SKenneth D. Merry 	switch(evt) {
689ef270ab1SKenneth D. Merry 		case OCS_EVT_ENTER:
690ef270ab1SKenneth D. Merry 			ocs_node_hold_frames(node);
691ef270ab1SKenneth D. Merry 			break;
692ef270ab1SKenneth D. Merry 
693ef270ab1SKenneth D. Merry 		case OCS_EVT_EXIT:
694ef270ab1SKenneth D. Merry 			ocs_node_accept_frames(node);
695ef270ab1SKenneth D. Merry 			break;
696ef270ab1SKenneth D. Merry 
697ef270ab1SKenneth D. Merry 		case OCS_EVT_SRRS_ELS_REQ_OK:
698ef270ab1SKenneth D. Merry 		case OCS_EVT_SRRS_ELS_REQ_RJT:
699ef270ab1SKenneth D. Merry 		case OCS_EVT_SRRS_ELS_REQ_FAIL:
700ef270ab1SKenneth D. Merry 			if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PRLO, __ocs_d_common, __func__)) {
701ef270ab1SKenneth D. Merry 				return NULL;
702ef270ab1SKenneth D. Merry 			}
703ef270ab1SKenneth D. Merry 			ocs_assert(node->els_req_cnt, NULL);
704ef270ab1SKenneth D. Merry 			node->els_req_cnt--;
705ef270ab1SKenneth D. Merry 			node_printf(node, "PRLO sent (evt=%s)\n", ocs_sm_event_name(evt));
706ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_d_port_logged_in, NULL);
707ef270ab1SKenneth D. Merry 			break;
708ef270ab1SKenneth D. Merry 
709ef270ab1SKenneth D. Merry 		default:
710ef270ab1SKenneth D. Merry 			__ocs_node_common(__func__, ctx, evt, arg);
711ef270ab1SKenneth D. Merry 			return NULL;
712ef270ab1SKenneth D. Merry 	}
713ef270ab1SKenneth D. Merry 	return NULL;
714ef270ab1SKenneth D. Merry }
715ef270ab1SKenneth D. Merry 
716ef270ab1SKenneth D. Merry /**
717ef270ab1SKenneth D. Merry  * @brief Initialize device node.
718ef270ab1SKenneth D. Merry  *
719ef270ab1SKenneth D. Merry  * Initialize device node. If a node is an initiator, then send a PLOGI and transition
720ef270ab1SKenneth D. Merry  * to __ocs_d_wait_plogi_rsp, otherwise transition to __ocs_d_init.
721ef270ab1SKenneth D. Merry  *
722ef270ab1SKenneth D. Merry  * @param node Pointer to the node object.
723ef270ab1SKenneth D. Merry  * @param send_plogi Boolean indicating to send PLOGI command or not.
724ef270ab1SKenneth D. Merry  *
725ef270ab1SKenneth D. Merry  * @return none
726ef270ab1SKenneth D. Merry  */
727ef270ab1SKenneth D. Merry 
728ef270ab1SKenneth D. Merry void
ocs_node_init_device(ocs_node_t * node,int send_plogi)729ef270ab1SKenneth D. Merry ocs_node_init_device(ocs_node_t *node, int send_plogi)
730ef270ab1SKenneth D. Merry {
731ef270ab1SKenneth D. Merry 	node->send_plogi = send_plogi;
732ef270ab1SKenneth D. Merry 	if ((node->ocs->nodedb_mask & OCS_NODEDB_PAUSE_NEW_NODES) && !FC_ADDR_IS_DOMAIN_CTRL(node->rnode.fc_id)) {
733ef270ab1SKenneth D. Merry 		node->nodedb_state = __ocs_d_init;
734ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_node_paused, NULL);
735ef270ab1SKenneth D. Merry 	} else {
736ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_init, NULL);
737ef270ab1SKenneth D. Merry 	}
738ef270ab1SKenneth D. Merry }
739ef270ab1SKenneth D. Merry 
740ef270ab1SKenneth D. Merry /**
741ef270ab1SKenneth D. Merry  * @ingroup device_sm
742ef270ab1SKenneth D. Merry  * @brief Device node state machine: Initial node state for an initiator or a target.
743ef270ab1SKenneth D. Merry  *
744ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
745ef270ab1SKenneth D. Merry  * This state is entered when a node is instantiated, either having been
746ef270ab1SKenneth D. Merry  * discovered from a name services query, or having received a PLOGI/FLOGI.
747ef270ab1SKenneth D. Merry  *
748ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
749ef270ab1SKenneth D. Merry  * @param evt Event to process.
750ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
751ef270ab1SKenneth D. Merry  * - OCS_EVT_ENTER: (uint8_t *) - 1 to send a PLOGI on
752ef270ab1SKenneth D. Merry  * entry (initiator-only); 0 indicates a PLOGI is
753ef270ab1SKenneth D. Merry  * not sent on entry (initiator-only). Not applicable for a target.
754ef270ab1SKenneth D. Merry  *
755ef270ab1SKenneth D. Merry  * @return Returns NULL.
756ef270ab1SKenneth D. Merry  */
757ef270ab1SKenneth D. Merry 
758ef270ab1SKenneth D. Merry void *
__ocs_d_init(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)759ef270ab1SKenneth D. Merry __ocs_d_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
760ef270ab1SKenneth D. Merry {
761ef270ab1SKenneth D. Merry 	int32_t rc;
762ef270ab1SKenneth D. Merry 	ocs_node_cb_t *cbdata = arg;
763ef270ab1SKenneth D. Merry 	std_node_state_decl();
764ef270ab1SKenneth D. Merry 
765ef270ab1SKenneth D. Merry 	node_sm_trace();
766ef270ab1SKenneth D. Merry 
767ef270ab1SKenneth D. Merry 	switch(evt) {
768ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
769ef270ab1SKenneth D. Merry 		/* check if we need to send PLOGI */
770ef270ab1SKenneth D. Merry 		if (node->send_plogi) {
771ef270ab1SKenneth D. Merry 			/* only send if we have initiator capability, and domain is attached */
772ef270ab1SKenneth D. Merry 			if (node->sport->enable_ini && node->sport->domain->attached) {
773ef270ab1SKenneth D. Merry 				ocs_send_plogi(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT,
774ef270ab1SKenneth D. Merry 						OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL);
775ef270ab1SKenneth D. Merry 				ocs_node_transition(node, __ocs_d_wait_plogi_rsp, NULL);
776ef270ab1SKenneth D. Merry 			} else {
777ef270ab1SKenneth D. Merry 				node_printf(node, "not sending plogi sport.ini=%d, domain attached=%d\n",
778ef270ab1SKenneth D. Merry 					    node->sport->enable_ini, node->sport->domain->attached);
779ef270ab1SKenneth D. Merry 			}
780ef270ab1SKenneth D. Merry 		}
781ef270ab1SKenneth D. Merry 		break;
782ef270ab1SKenneth D. Merry 	case OCS_EVT_PLOGI_RCVD: {
783ef270ab1SKenneth D. Merry 		/* T, or I+T */
784ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
785ef270ab1SKenneth D. Merry 		uint32_t d_id = fc_be24toh(hdr->d_id);
786ef270ab1SKenneth D. Merry 
787ef270ab1SKenneth D. Merry 		ocs_node_save_sparms(node, cbdata->payload->dma.virt);
788ef270ab1SKenneth D. Merry 		ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PLOGI);
789ef270ab1SKenneth D. Merry 
790ef270ab1SKenneth D. Merry 		/* domain already attached */
791ef270ab1SKenneth D. Merry 		if (node->sport->domain->attached) {
792ef270ab1SKenneth D. Merry 			rc = ocs_node_attach(node);
793ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_d_wait_node_attach, NULL);
794ef270ab1SKenneth D. Merry 			if (rc == OCS_HW_RTN_SUCCESS_SYNC) {
795ef270ab1SKenneth D. Merry 				ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL);
796ef270ab1SKenneth D. Merry 			}
797ef270ab1SKenneth D. Merry 			break;
798ef270ab1SKenneth D. Merry 		}
799ef270ab1SKenneth D. Merry 
800ef270ab1SKenneth D. Merry 		/* domain not attached; several possibilities: */
801ef270ab1SKenneth D. Merry 		switch (node->sport->topology) {
802ef270ab1SKenneth D. Merry 		case OCS_SPORT_TOPOLOGY_P2P:
803ef270ab1SKenneth D. Merry 			/* we're not attached and sport is p2p, need to attach */
804ef270ab1SKenneth D. Merry 			ocs_domain_attach(node->sport->domain, d_id);
805ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_d_wait_domain_attach, NULL);
806ef270ab1SKenneth D. Merry 			break;
807ef270ab1SKenneth D. Merry 		case OCS_SPORT_TOPOLOGY_FABRIC:
808ef270ab1SKenneth D. Merry 			/* we're not attached and sport is fabric, domain attach should have
809ef270ab1SKenneth D. Merry 			 * already been requested as part of the fabric state machine, wait for it
810ef270ab1SKenneth D. Merry 			 */
811ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_d_wait_domain_attach, NULL);
812ef270ab1SKenneth D. Merry 			break;
813ef270ab1SKenneth D. Merry 		case OCS_SPORT_TOPOLOGY_UNKNOWN:
814ef270ab1SKenneth D. Merry 			/* Two possibilities:
815ef270ab1SKenneth D. Merry 			 * 1. received a PLOGI before our FLOGI has completed (possible since
816ef270ab1SKenneth D. Merry 			 *    completion comes in on another CQ), thus we don't know what we're
817ef270ab1SKenneth D. Merry 			 *    connected to yet; transition to a state to wait for the fabric
818ef270ab1SKenneth D. Merry 			 *    node to tell us;
819ef270ab1SKenneth D. Merry 			 * 2. PLOGI received before link went down and we haven't performed
820ef270ab1SKenneth D. Merry 			 *    domain attach yet.
821ef270ab1SKenneth D. Merry 			 * Note: we cannot distinguish between 1. and 2. so have to assume PLOGI
822ef270ab1SKenneth D. Merry 			 * was received after link back up.
823ef270ab1SKenneth D. Merry 			 */
824ef270ab1SKenneth D. Merry 			node_printf(node, "received PLOGI, with unknown topology did=0x%x\n", d_id);
825ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_d_wait_topology_notify, NULL);
826ef270ab1SKenneth D. Merry 			break;
827ef270ab1SKenneth D. Merry 		default:
828ef270ab1SKenneth D. Merry 			node_printf(node, "received PLOGI, with unexpectd topology %d\n",
829ef270ab1SKenneth D. Merry 				    node->sport->topology);
830ef270ab1SKenneth D. Merry 			ocs_assert(FALSE, NULL);
831ef270ab1SKenneth D. Merry 			break;
832ef270ab1SKenneth D. Merry 		}
833ef270ab1SKenneth D. Merry 		break;
834ef270ab1SKenneth D. Merry 	}
835ef270ab1SKenneth D. Merry 
836ef270ab1SKenneth D. Merry 	case OCS_EVT_FDISC_RCVD: {
837ef270ab1SKenneth D. Merry 		__ocs_d_common(__func__, ctx, evt, arg);
838ef270ab1SKenneth D. Merry 		break;
839ef270ab1SKenneth D. Merry 	}
840ef270ab1SKenneth D. Merry 
841ef270ab1SKenneth D. Merry 	case OCS_EVT_FLOGI_RCVD: {
842ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
843ef270ab1SKenneth D. Merry 
844ef270ab1SKenneth D. Merry 		/* this better be coming from an NPort */
845ef270ab1SKenneth D. Merry 		ocs_assert(ocs_rnode_is_nport(cbdata->payload->dma.virt), NULL);
846ef270ab1SKenneth D. Merry 
847ef270ab1SKenneth D. Merry 		/* sm: save sparams, send FLOGI acc */
848ef270ab1SKenneth D. Merry 		ocs_domain_save_sparms(node->sport->domain, cbdata->payload->dma.virt);
849ef270ab1SKenneth D. Merry 
850ef270ab1SKenneth D. Merry 		/* send FC LS_ACC response, override s_id */
851ef270ab1SKenneth D. Merry 		ocs_fabric_set_topology(node, OCS_SPORT_TOPOLOGY_P2P);
852ef270ab1SKenneth D. Merry 		ocs_send_flogi_p2p_acc(cbdata->io, ocs_be16toh(hdr->ox_id), fc_be24toh(hdr->d_id), NULL, NULL);
853ef270ab1SKenneth D. Merry 		if (ocs_p2p_setup(node->sport)) {
854ef270ab1SKenneth D. Merry 			node_printf(node, "p2p setup failed, shutting down node\n");
855ef270ab1SKenneth D. Merry 			ocs_node_post_event(node, OCS_EVT_SHUTDOWN, NULL);
856ef270ab1SKenneth D. Merry 		} else {
857ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_p2p_wait_flogi_acc_cmpl, NULL);
858ef270ab1SKenneth D. Merry 		}
859ef270ab1SKenneth D. Merry 
860ef270ab1SKenneth D. Merry 		break;
861ef270ab1SKenneth D. Merry 	}
862ef270ab1SKenneth D. Merry 
863ef270ab1SKenneth D. Merry 	case OCS_EVT_LOGO_RCVD: {
864ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
865ef270ab1SKenneth D. Merry 
866ef270ab1SKenneth D. Merry 		if (!node->sport->domain->attached) {
867ef270ab1SKenneth D. Merry 			 /* most likely a frame left over from before a link down; drop and
868ef270ab1SKenneth D. Merry 			  * shut node down w/ "explicit logout" so pending frames are processed */
869ef270ab1SKenneth D. Merry 			node_printf(node, "%s domain not attached, dropping\n", ocs_sm_event_name(evt));
870ef270ab1SKenneth D. Merry 			ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
871ef270ab1SKenneth D. Merry 			break;
872ef270ab1SKenneth D. Merry 		}
873ef270ab1SKenneth D. Merry 		ocs_send_logo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
874ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_wait_logo_acc_cmpl, NULL);
875ef270ab1SKenneth D. Merry 		break;
876ef270ab1SKenneth D. Merry 	}
877ef270ab1SKenneth D. Merry 
878ef270ab1SKenneth D. Merry 	case OCS_EVT_PRLI_RCVD:
879ef270ab1SKenneth D. Merry 	case OCS_EVT_PRLO_RCVD:
880ef270ab1SKenneth D. Merry 	case OCS_EVT_PDISC_RCVD:
881ef270ab1SKenneth D. Merry 	case OCS_EVT_ADISC_RCVD:
882ef270ab1SKenneth D. Merry 	case OCS_EVT_RSCN_RCVD: {
883ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
884ef270ab1SKenneth D. Merry 		if (!node->sport->domain->attached) {
885ef270ab1SKenneth D. Merry 			 /* most likely a frame left over from before a link down; drop and
886ef270ab1SKenneth D. Merry 			  * shut node down w/ "explicit logout" so pending frames are processed */
887ef270ab1SKenneth D. Merry 			node_printf(node, "%s domain not attached, dropping\n", ocs_sm_event_name(evt));
888ef270ab1SKenneth D. Merry 			ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
889ef270ab1SKenneth D. Merry 			break;
890ef270ab1SKenneth D. Merry 		}
891ef270ab1SKenneth D. Merry 		node_printf(node, "%s received, sending reject\n", ocs_sm_event_name(evt));
892ef270ab1SKenneth D. Merry 		ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id),
893ef270ab1SKenneth D. Merry 			FC_REASON_UNABLE_TO_PERFORM, FC_EXPL_NPORT_LOGIN_REQUIRED, 0,
894ef270ab1SKenneth D. Merry 			NULL, NULL);
895ef270ab1SKenneth D. Merry 
896ef270ab1SKenneth D. Merry 		break;
897ef270ab1SKenneth D. Merry 	}
898ef270ab1SKenneth D. Merry 
899ef270ab1SKenneth D. Merry 	case OCS_EVT_FCP_CMD_RCVD: {
900ef270ab1SKenneth D. Merry 		/* note: problem, we're now expecting an ELS REQ completion
901ef270ab1SKenneth D. Merry 		 * from both the LOGO and PLOGI */
902ef270ab1SKenneth D. Merry 		if (!node->sport->domain->attached) {
903ef270ab1SKenneth D. Merry 			 /* most likely a frame left over from before a link down; drop and
904ef270ab1SKenneth D. Merry 			  * shut node down w/ "explicit logout" so pending frames are processed */
905ef270ab1SKenneth D. Merry 			node_printf(node, "%s domain not attached, dropping\n", ocs_sm_event_name(evt));
906ef270ab1SKenneth D. Merry 			ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
907ef270ab1SKenneth D. Merry 			break;
908ef270ab1SKenneth D. Merry 		}
909ef270ab1SKenneth D. Merry 
910ef270ab1SKenneth D. Merry 		/* Send LOGO */
911ef270ab1SKenneth D. Merry 		node_printf(node, "FCP_CMND received, send LOGO\n");
912ef270ab1SKenneth D. Merry 		if (ocs_send_logo(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, 0, NULL, NULL) == NULL) {
913ef270ab1SKenneth D. Merry 			/* failed to send LOGO, go ahead and cleanup node anyways */
914ef270ab1SKenneth D. Merry 			node_printf(node, "Failed to send LOGO\n");
915ef270ab1SKenneth D. Merry 			ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
916ef270ab1SKenneth D. Merry 		} else {
917ef270ab1SKenneth D. Merry 			/* sent LOGO, wait for response */
918ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_d_wait_logo_rsp, NULL);
919ef270ab1SKenneth D. Merry 		}
920ef270ab1SKenneth D. Merry 		break;
921ef270ab1SKenneth D. Merry 	}
922ef270ab1SKenneth D. Merry 	case OCS_EVT_DOMAIN_ATTACH_OK:
923ef270ab1SKenneth D. Merry 		/* don't care about domain_attach_ok */
924ef270ab1SKenneth D. Merry 		break;
925ef270ab1SKenneth D. Merry 
926ef270ab1SKenneth D. Merry 	default:
927ef270ab1SKenneth D. Merry 		__ocs_d_common(__func__, ctx, evt, arg);
928ef270ab1SKenneth D. Merry 		return NULL;
929ef270ab1SKenneth D. Merry 	}
930ef270ab1SKenneth D. Merry 
931ef270ab1SKenneth D. Merry 	return NULL;
932ef270ab1SKenneth D. Merry }
933ef270ab1SKenneth D. Merry 
934ef270ab1SKenneth D. Merry /**
935ef270ab1SKenneth D. Merry  * @ingroup device_sm
936ef270ab1SKenneth D. Merry  * @brief Device node state machine: Wait on a response for a sent PLOGI.
937ef270ab1SKenneth D. Merry  *
938ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
939ef270ab1SKenneth D. Merry  * State is entered when an initiator-capable node has sent
940ef270ab1SKenneth D. Merry  * a PLOGI and is waiting for a response.
941ef270ab1SKenneth D. Merry  *
942ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
943ef270ab1SKenneth D. Merry  * @param evt Event to process.
944ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
945ef270ab1SKenneth D. Merry  *
946ef270ab1SKenneth D. Merry  * @return Returns NULL.
947ef270ab1SKenneth D. Merry  */
948ef270ab1SKenneth D. Merry 
949ef270ab1SKenneth D. Merry void *
__ocs_d_wait_plogi_rsp(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)950ef270ab1SKenneth D. Merry __ocs_d_wait_plogi_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
951ef270ab1SKenneth D. Merry {
952ef270ab1SKenneth D. Merry 	int32_t rc;
953ef270ab1SKenneth D. Merry 	ocs_node_cb_t *cbdata = arg;
954ef270ab1SKenneth D. Merry 	std_node_state_decl();
955ef270ab1SKenneth D. Merry 
956ef270ab1SKenneth D. Merry 	node_sm_trace();
957ef270ab1SKenneth D. Merry 
958ef270ab1SKenneth D. Merry 	switch(evt) {
959ef270ab1SKenneth D. Merry 	case OCS_EVT_PLOGI_RCVD: {
960ef270ab1SKenneth D. Merry 		/* T, or I+T */
961ef270ab1SKenneth D. Merry 		/* received PLOGI with svc parms, go ahead and attach node
962ef270ab1SKenneth D. Merry 		 * when PLOGI that was sent ultimately completes, it'll be a no-op
963ef270ab1SKenneth D. Merry 		 */
964ef270ab1SKenneth D. Merry 
965ef270ab1SKenneth D. Merry 		/* TODO: there is an outstanding PLOGI sent, can we set a flag
966ef270ab1SKenneth D. Merry 		 * to indicate that we don't want to retry it if it times out? */
967ef270ab1SKenneth D. Merry 		ocs_node_save_sparms(node, cbdata->payload->dma.virt);
968ef270ab1SKenneth D. Merry 		ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PLOGI);
969ef270ab1SKenneth D. Merry 		/* sm: domain->attached / ocs_node_attach */
970ef270ab1SKenneth D. Merry 		rc = ocs_node_attach(node);
971ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_wait_node_attach, NULL);
972ef270ab1SKenneth D. Merry 		if (rc == OCS_HW_RTN_SUCCESS_SYNC) {
973ef270ab1SKenneth D. Merry 			ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL);
974ef270ab1SKenneth D. Merry 		}
975ef270ab1SKenneth D. Merry 		break;
976ef270ab1SKenneth D. Merry 	}
977ef270ab1SKenneth D. Merry 
978ef270ab1SKenneth D. Merry 	case OCS_EVT_PRLI_RCVD:
979ef270ab1SKenneth D. Merry 		/* I, or I+T */
980ef270ab1SKenneth D. Merry 		/* sent PLOGI and before completion was seen, received the
981ef270ab1SKenneth D. Merry 		 * PRLI from the remote node (WCQEs and RCQEs come in on
982ef270ab1SKenneth D. Merry 		 * different queues and order of processing cannot be assumed)
983ef270ab1SKenneth D. Merry 		 * Save OXID so PRLI can be sent after the attach and continue
984ef270ab1SKenneth D. Merry 		 * to wait for PLOGI response
985ef270ab1SKenneth D. Merry 		 */
986ef270ab1SKenneth D. Merry 		ocs_process_prli_payload(node, cbdata->payload->dma.virt);
987ef270ab1SKenneth D. Merry 		if (ocs->fc_type == node->fc_type) {
988ef270ab1SKenneth D. Merry 			ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PRLI);
989ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_d_wait_plogi_rsp_recvd_prli, NULL);
990ef270ab1SKenneth D. Merry 		} else {
991ef270ab1SKenneth D. Merry 			/* TODO this need to be looked at. What do we do here ? */
992ef270ab1SKenneth D. Merry 		}
993ef270ab1SKenneth D. Merry 		break;
994ef270ab1SKenneth D. Merry 
995ef270ab1SKenneth D. Merry 	/* TODO this need to be looked at. we could very well be logged in */
996ef270ab1SKenneth D. Merry 	case OCS_EVT_LOGO_RCVD: /* why don't we do a shutdown here?? */
997ef270ab1SKenneth D. Merry 	case OCS_EVT_PRLO_RCVD:
998ef270ab1SKenneth D. Merry 	case OCS_EVT_PDISC_RCVD:
999ef270ab1SKenneth D. Merry 	case OCS_EVT_FDISC_RCVD:
1000ef270ab1SKenneth D. Merry 	case OCS_EVT_ADISC_RCVD:
1001ef270ab1SKenneth D. Merry 	case OCS_EVT_RSCN_RCVD:
1002ef270ab1SKenneth D. Merry 	case OCS_EVT_SCR_RCVD: {
1003ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
1004ef270ab1SKenneth D. Merry 		node_printf(node, "%s received, sending reject\n", ocs_sm_event_name(evt));
1005ef270ab1SKenneth D. Merry 		ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id),
1006ef270ab1SKenneth D. Merry 			FC_REASON_UNABLE_TO_PERFORM, FC_EXPL_NPORT_LOGIN_REQUIRED, 0,
1007ef270ab1SKenneth D. Merry 			NULL, NULL);
1008ef270ab1SKenneth D. Merry 
1009ef270ab1SKenneth D. Merry 		break;
1010ef270ab1SKenneth D. Merry 	}
1011ef270ab1SKenneth D. Merry 
1012ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_OK:	/* PLOGI response received */
1013ef270ab1SKenneth D. Merry 		/* Completion from PLOGI sent */
1014ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_d_common, __func__)) {
1015ef270ab1SKenneth D. Merry 			return NULL;
1016ef270ab1SKenneth D. Merry 		}
1017ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
1018ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
1019ef270ab1SKenneth D. Merry 		/* sm:  save sparams, ocs_node_attach */
1020ef270ab1SKenneth D. Merry 		ocs_node_save_sparms(node, cbdata->els->els_rsp.virt);
1021ef270ab1SKenneth D. Merry 		ocs_display_sparams(node->display_name, "plogi rcvd resp", 0, NULL,
1022ef270ab1SKenneth D. Merry 			((uint8_t*)cbdata->els->els_rsp.virt) + 4);
1023ef270ab1SKenneth D. Merry 		rc = ocs_node_attach(node);
1024ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_wait_node_attach, NULL);
1025ef270ab1SKenneth D. Merry 		if (rc == OCS_HW_RTN_SUCCESS_SYNC) {
1026ef270ab1SKenneth D. Merry 			ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL);
1027ef270ab1SKenneth D. Merry 		}
1028ef270ab1SKenneth D. Merry 		break;
1029ef270ab1SKenneth D. Merry 
1030ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_FAIL:	/* PLOGI response received */
1031ef270ab1SKenneth D. Merry 		/* PLOGI failed, shutdown the node */
1032ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_d_common, __func__)) {
1033ef270ab1SKenneth D. Merry 			return NULL;
1034ef270ab1SKenneth D. Merry 		}
1035ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
1036ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
1037ef270ab1SKenneth D. Merry 		ocs_node_post_event(node, OCS_EVT_SHUTDOWN, NULL);
1038ef270ab1SKenneth D. Merry 		break;
1039ef270ab1SKenneth D. Merry 
1040ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_RJT:	/* Our PLOGI was rejected, this is ok in some cases */
1041ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_d_common, __func__)) {
1042ef270ab1SKenneth D. Merry 			return NULL;
1043ef270ab1SKenneth D. Merry 		}
1044ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
1045ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
1046ef270ab1SKenneth D. Merry 		break;
1047ef270ab1SKenneth D. Merry 
1048ef270ab1SKenneth D. Merry 	case OCS_EVT_FCP_CMD_RCVD: {
1049ef270ab1SKenneth D. Merry 		/* not logged in yet and outstanding PLOGI so don't send LOGO,
1050ef270ab1SKenneth D. Merry 		 * just drop
1051ef270ab1SKenneth D. Merry 		 */
1052ef270ab1SKenneth D. Merry 		node_printf(node, "FCP_CMND received, drop\n");
1053ef270ab1SKenneth D. Merry 		break;
1054ef270ab1SKenneth D. Merry 	}
1055ef270ab1SKenneth D. Merry 
1056ef270ab1SKenneth D. Merry 	default:
1057ef270ab1SKenneth D. Merry 		__ocs_d_common(__func__, ctx, evt, arg);
1058ef270ab1SKenneth D. Merry 		return NULL;
1059ef270ab1SKenneth D. Merry 	}
1060ef270ab1SKenneth D. Merry 
1061ef270ab1SKenneth D. Merry 	return NULL;
1062ef270ab1SKenneth D. Merry }
1063ef270ab1SKenneth D. Merry 
1064ef270ab1SKenneth D. Merry /**
1065ef270ab1SKenneth D. Merry  * @ingroup device_sm
1066ef270ab1SKenneth D. Merry  * @brief Device node state machine: Waiting on a response for a
1067ef270ab1SKenneth D. Merry  *	sent PLOGI.
1068ef270ab1SKenneth D. Merry  *
1069ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1070ef270ab1SKenneth D. Merry  * State is entered when an initiator-capable node has sent
1071ef270ab1SKenneth D. Merry  * a PLOGI and is waiting for a response. Before receiving the
1072ef270ab1SKenneth D. Merry  * response, a PRLI was received, implying that the PLOGI was
1073ef270ab1SKenneth D. Merry  * successful.
1074ef270ab1SKenneth D. Merry  *
1075ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1076ef270ab1SKenneth D. Merry  * @param evt Event to process.
1077ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
1078ef270ab1SKenneth D. Merry  *
1079ef270ab1SKenneth D. Merry  * @return Returns NULL.
1080ef270ab1SKenneth D. Merry  */
1081ef270ab1SKenneth D. Merry 
1082ef270ab1SKenneth D. Merry void *
__ocs_d_wait_plogi_rsp_recvd_prli(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)1083ef270ab1SKenneth D. Merry __ocs_d_wait_plogi_rsp_recvd_prli(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1084ef270ab1SKenneth D. Merry {
1085ef270ab1SKenneth D. Merry 	int32_t rc;
1086ef270ab1SKenneth D. Merry 	ocs_node_cb_t *cbdata = arg;
1087ef270ab1SKenneth D. Merry 	std_node_state_decl();
1088ef270ab1SKenneth D. Merry 
1089ef270ab1SKenneth D. Merry 	node_sm_trace();
1090ef270ab1SKenneth D. Merry 
1091ef270ab1SKenneth D. Merry 	switch(evt) {
1092ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
1093ef270ab1SKenneth D. Merry 		/*
1094ef270ab1SKenneth D. Merry 		 * Since we've received a PRLI, we have a port login and will
1095ef270ab1SKenneth D. Merry 		 * just need to wait for the PLOGI response to do the node
1096ef270ab1SKenneth D. Merry 		 * attach and then we can send the LS_ACC for the PRLI. If,
1097ef270ab1SKenneth D. Merry 		 * during this time, we receive FCP_CMNDs (which is possible
1098ef270ab1SKenneth D. Merry 		 * since we've already sent a PRLI and our peer may have accepted).
1099ef270ab1SKenneth D. Merry 		 * At this time, we are not waiting on any other unsolicited
1100ef270ab1SKenneth D. Merry 		 * frames to continue with the login process. Thus, it will not
1101ef270ab1SKenneth D. Merry 		 * hurt to hold frames here.
1102ef270ab1SKenneth D. Merry 		 */
1103ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
1104ef270ab1SKenneth D. Merry 		break;
1105ef270ab1SKenneth D. Merry 
1106ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
1107ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
1108ef270ab1SKenneth D. Merry 		break;
1109ef270ab1SKenneth D. Merry 
1110ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_OK:	/* PLOGI response received */
1111ef270ab1SKenneth D. Merry 		/* Completion from PLOGI sent */
1112ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_d_common, __func__)) {
1113ef270ab1SKenneth D. Merry 			return NULL;
1114ef270ab1SKenneth D. Merry 		}
1115ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
1116ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
1117ef270ab1SKenneth D. Merry 		/* sm:  save sparams, ocs_node_attach */
1118ef270ab1SKenneth D. Merry 		ocs_node_save_sparms(node, cbdata->els->els_rsp.virt);
1119ef270ab1SKenneth D. Merry 		ocs_display_sparams(node->display_name, "plogi rcvd resp", 0, NULL,
1120ef270ab1SKenneth D. Merry 			((uint8_t*)cbdata->els->els_rsp.virt) + 4);
1121ef270ab1SKenneth D. Merry 		rc = ocs_node_attach(node);
1122ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_wait_node_attach, NULL);
1123ef270ab1SKenneth D. Merry 		if (rc == OCS_HW_RTN_SUCCESS_SYNC) {
1124ef270ab1SKenneth D. Merry 			ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL);
1125ef270ab1SKenneth D. Merry 		}
1126ef270ab1SKenneth D. Merry 		break;
1127ef270ab1SKenneth D. Merry 
1128ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_FAIL:	/* PLOGI response received */
1129ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_RJT:
1130ef270ab1SKenneth D. Merry 		/* PLOGI failed, shutdown the node */
1131ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_d_common, __func__)) {
1132ef270ab1SKenneth D. Merry 			return NULL;
1133ef270ab1SKenneth D. Merry 		}
1134ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
1135ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
1136ef270ab1SKenneth D. Merry 		ocs_node_post_event(node, OCS_EVT_SHUTDOWN, NULL);
1137ef270ab1SKenneth D. Merry 		break;
1138ef270ab1SKenneth D. Merry 
1139ef270ab1SKenneth D. Merry 	default:
1140ef270ab1SKenneth D. Merry 		__ocs_d_common(__func__, ctx, evt, arg);
1141ef270ab1SKenneth D. Merry 		return NULL;
1142ef270ab1SKenneth D. Merry 	}
1143ef270ab1SKenneth D. Merry 
1144ef270ab1SKenneth D. Merry 	return NULL;
1145ef270ab1SKenneth D. Merry }
1146ef270ab1SKenneth D. Merry 
1147ef270ab1SKenneth D. Merry /**
1148ef270ab1SKenneth D. Merry  * @ingroup device_sm
1149ef270ab1SKenneth D. Merry  * @brief Device node state machine: Wait for a domain attach.
1150ef270ab1SKenneth D. Merry  *
1151ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1152ef270ab1SKenneth D. Merry  * Waits for a domain-attach complete ok event.
1153ef270ab1SKenneth D. Merry  *
1154ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1155ef270ab1SKenneth D. Merry  * @param evt Event to process.
1156ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
1157ef270ab1SKenneth D. Merry  *
1158ef270ab1SKenneth D. Merry  * @return Returns NULL.
1159ef270ab1SKenneth D. Merry  */
1160ef270ab1SKenneth D. Merry 
1161ef270ab1SKenneth D. Merry void *
__ocs_d_wait_domain_attach(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)1162ef270ab1SKenneth D. Merry __ocs_d_wait_domain_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1163ef270ab1SKenneth D. Merry {
1164ef270ab1SKenneth D. Merry 	int32_t rc;
1165ef270ab1SKenneth D. Merry 	std_node_state_decl();
1166ef270ab1SKenneth D. Merry 
1167ef270ab1SKenneth D. Merry 	node_sm_trace();
1168ef270ab1SKenneth D. Merry 
1169ef270ab1SKenneth D. Merry 	switch(evt) {
1170ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
1171ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
1172ef270ab1SKenneth D. Merry 		break;
1173ef270ab1SKenneth D. Merry 
1174ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
1175ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
1176ef270ab1SKenneth D. Merry 		break;
1177ef270ab1SKenneth D. Merry 
1178ef270ab1SKenneth D. Merry 	case OCS_EVT_DOMAIN_ATTACH_OK:
1179ef270ab1SKenneth D. Merry 		ocs_assert(node->sport->domain->attached, NULL);
1180ef270ab1SKenneth D. Merry 		/* sm: ocs_node_attach */
1181ef270ab1SKenneth D. Merry 		rc = ocs_node_attach(node);
1182ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_wait_node_attach, NULL);
1183ef270ab1SKenneth D. Merry 		if (rc == OCS_HW_RTN_SUCCESS_SYNC) {
1184ef270ab1SKenneth D. Merry 			ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL);
1185ef270ab1SKenneth D. Merry 		}
1186ef270ab1SKenneth D. Merry 		break;
1187ef270ab1SKenneth D. Merry 
1188ef270ab1SKenneth D. Merry 	default:
1189ef270ab1SKenneth D. Merry 		__ocs_d_common(__func__, ctx, evt, arg);
1190ef270ab1SKenneth D. Merry 		return NULL;
1191ef270ab1SKenneth D. Merry 	}
1192ef270ab1SKenneth D. Merry 	return NULL;
1193ef270ab1SKenneth D. Merry }
1194ef270ab1SKenneth D. Merry 
1195ef270ab1SKenneth D. Merry /**
1196ef270ab1SKenneth D. Merry  * @ingroup device_sm
1197ef270ab1SKenneth D. Merry  * @brief Device node state machine: Wait for topology
1198ef270ab1SKenneth D. Merry  *	notification
1199ef270ab1SKenneth D. Merry  *
1200ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1201ef270ab1SKenneth D. Merry  * Waits for topology notification from fabric node, then
1202ef270ab1SKenneth D. Merry  * attaches domain and node.
1203ef270ab1SKenneth D. Merry  *
1204ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1205ef270ab1SKenneth D. Merry  * @param evt Event to process.
1206ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
1207ef270ab1SKenneth D. Merry  *
1208ef270ab1SKenneth D. Merry  * @return Returns NULL.
1209ef270ab1SKenneth D. Merry  */
1210ef270ab1SKenneth D. Merry 
1211ef270ab1SKenneth D. Merry void *
__ocs_d_wait_topology_notify(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)1212ef270ab1SKenneth D. Merry __ocs_d_wait_topology_notify(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1213ef270ab1SKenneth D. Merry {
1214ef270ab1SKenneth D. Merry 	int32_t rc;
1215ef270ab1SKenneth D. Merry 	std_node_state_decl();
1216ef270ab1SKenneth D. Merry 
1217ef270ab1SKenneth D. Merry 	node_sm_trace();
1218ef270ab1SKenneth D. Merry 
1219ef270ab1SKenneth D. Merry 	switch(evt) {
1220ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
1221ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
1222ef270ab1SKenneth D. Merry 		break;
1223ef270ab1SKenneth D. Merry 
1224ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
1225ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
1226ef270ab1SKenneth D. Merry 		break;
1227ef270ab1SKenneth D. Merry 
1228ef270ab1SKenneth D. Merry 	case OCS_EVT_SPORT_TOPOLOGY_NOTIFY: {
1229*6671366aSBrooks Davis 		ocs_sport_topology_e topology = (ocs_sport_topology_e)(uintptr_t)arg;
1230ef270ab1SKenneth D. Merry 		ocs_assert(!node->sport->domain->attached, NULL);
1231ef270ab1SKenneth D. Merry 		ocs_assert(node->send_ls_acc == OCS_NODE_SEND_LS_ACC_PLOGI, NULL);
1232ef270ab1SKenneth D. Merry 		node_printf(node, "topology notification, topology=%d\n", topology);
1233ef270ab1SKenneth D. Merry 
1234ef270ab1SKenneth D. Merry 		/* At the time the PLOGI was received, the topology was unknown,
1235ef270ab1SKenneth D. Merry 		 * so we didn't know which node would perform the domain attach:
1236ef270ab1SKenneth D. Merry 		 * 1. The node from which the PLOGI was sent (p2p) or
1237ef270ab1SKenneth D. Merry 		 * 2. The node to which the FLOGI was sent (fabric).
1238ef270ab1SKenneth D. Merry 		 */
1239ef270ab1SKenneth D. Merry 		if (topology == OCS_SPORT_TOPOLOGY_P2P) {
1240ef270ab1SKenneth D. Merry 			/* if this is p2p, need to attach to the domain using the
1241ef270ab1SKenneth D. Merry 			 * d_id from the PLOGI received
1242ef270ab1SKenneth D. Merry 			 */
1243ef270ab1SKenneth D. Merry 			ocs_domain_attach(node->sport->domain, node->ls_acc_did);
1244ef270ab1SKenneth D. Merry 		}
1245ef270ab1SKenneth D. Merry 		/* else, if this is fabric, the domain attach should be performed
1246ef270ab1SKenneth D. Merry 		 * by the fabric node (node sending FLOGI); just wait for attach
1247ef270ab1SKenneth D. Merry 		 * to complete
1248ef270ab1SKenneth D. Merry 		 */
1249ef270ab1SKenneth D. Merry 
1250ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_wait_domain_attach, NULL);
1251ef270ab1SKenneth D. Merry 		break;
1252ef270ab1SKenneth D. Merry 	}
1253ef270ab1SKenneth D. Merry 	case OCS_EVT_DOMAIN_ATTACH_OK:
1254ef270ab1SKenneth D. Merry 		ocs_assert(node->sport->domain->attached, NULL);
1255ef270ab1SKenneth D. Merry 		node_printf(node, "domain attach ok\n");
1256ef270ab1SKenneth D. Merry 		/*sm:  ocs_node_attach */
1257ef270ab1SKenneth D. Merry 		rc = ocs_node_attach(node);
1258ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_wait_node_attach, NULL);
1259ef270ab1SKenneth D. Merry 		if (rc == OCS_HW_RTN_SUCCESS_SYNC) {
1260ef270ab1SKenneth D. Merry 			ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL);
1261ef270ab1SKenneth D. Merry 		}
1262ef270ab1SKenneth D. Merry 		break;
1263ef270ab1SKenneth D. Merry 
1264ef270ab1SKenneth D. Merry 	default:
1265ef270ab1SKenneth D. Merry 		__ocs_d_common(__func__, ctx, evt, arg);
1266ef270ab1SKenneth D. Merry 		return NULL;
1267ef270ab1SKenneth D. Merry 	}
1268ef270ab1SKenneth D. Merry 	return NULL;
1269ef270ab1SKenneth D. Merry }
1270ef270ab1SKenneth D. Merry 
1271ef270ab1SKenneth D. Merry /**
1272ef270ab1SKenneth D. Merry  * @ingroup device_sm
1273ef270ab1SKenneth D. Merry  * @brief Device node state machine: Wait for a node attach when found by a remote node.
1274ef270ab1SKenneth D. Merry  *
1275ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1276ef270ab1SKenneth D. Merry  * @param evt Event to process.
1277ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
1278ef270ab1SKenneth D. Merry  *
1279ef270ab1SKenneth D. Merry  * @return Returns NULL.
1280ef270ab1SKenneth D. Merry  */
1281ef270ab1SKenneth D. Merry 
1282ef270ab1SKenneth D. Merry void *
__ocs_d_wait_node_attach(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)1283ef270ab1SKenneth D. Merry __ocs_d_wait_node_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1284ef270ab1SKenneth D. Merry {
1285ef270ab1SKenneth D. Merry 	std_node_state_decl();
1286ef270ab1SKenneth D. Merry 
1287ef270ab1SKenneth D. Merry 	node_sm_trace();
1288ef270ab1SKenneth D. Merry 
1289ef270ab1SKenneth D. Merry 	switch(evt) {
1290ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
1291ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
1292ef270ab1SKenneth D. Merry 		break;
1293ef270ab1SKenneth D. Merry 
1294ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
1295ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
1296ef270ab1SKenneth D. Merry 		break;
1297ef270ab1SKenneth D. Merry 
1298ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ATTACH_OK:
1299ef270ab1SKenneth D. Merry 		node->attached = TRUE;
1300ef270ab1SKenneth D. Merry 		switch (node->send_ls_acc) {
1301ef270ab1SKenneth D. Merry 		case OCS_NODE_SEND_LS_ACC_PLOGI: {
1302ef270ab1SKenneth D. Merry 			/* sm: send_plogi_acc is set / send PLOGI acc */
1303ef270ab1SKenneth D. Merry 			/* Normal case for T, or I+T */
1304ef270ab1SKenneth D. Merry 			ocs_send_plogi_acc(node->ls_acc_io, node->ls_acc_oxid, NULL, NULL);
1305ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_d_wait_plogi_acc_cmpl, NULL);
1306ef270ab1SKenneth D. Merry 			node->send_ls_acc = OCS_NODE_SEND_LS_ACC_NONE;
1307ef270ab1SKenneth D. Merry 			node->ls_acc_io = NULL;
1308ef270ab1SKenneth D. Merry 			break;
1309ef270ab1SKenneth D. Merry 		}
1310ef270ab1SKenneth D. Merry 		case OCS_NODE_SEND_LS_ACC_PRLI: {
1311ef270ab1SKenneth D. Merry 			ocs_d_send_prli_rsp(node->ls_acc_io, node->ls_acc_oxid);
1312ef270ab1SKenneth D. Merry 			node->send_ls_acc = OCS_NODE_SEND_LS_ACC_NONE;
1313ef270ab1SKenneth D. Merry 			node->ls_acc_io = NULL;
1314ef270ab1SKenneth D. Merry 			break;
1315ef270ab1SKenneth D. Merry 		}
1316ef270ab1SKenneth D. Merry 		case OCS_NODE_SEND_LS_ACC_NONE:
1317ef270ab1SKenneth D. Merry 		default:
1318ef270ab1SKenneth D. Merry 			/* Normal case for I */
1319ef270ab1SKenneth D. Merry 			/* sm: send_plogi_acc is not set / send PLOGI acc */
1320ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_d_port_logged_in, NULL);
1321ef270ab1SKenneth D. Merry 			break;
1322ef270ab1SKenneth D. Merry 		}
1323ef270ab1SKenneth D. Merry 		break;
1324ef270ab1SKenneth D. Merry 
1325ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ATTACH_FAIL:
1326ef270ab1SKenneth D. Merry 		/* node attach failed, shutdown the node */
1327ef270ab1SKenneth D. Merry 		node->attached = FALSE;
1328ef270ab1SKenneth D. Merry 		node_printf(node, "node attach failed\n");
1329ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1330ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL);
1331ef270ab1SKenneth D. Merry 		break;
1332ef270ab1SKenneth D. Merry 
1333ef270ab1SKenneth D. Merry 	/* Handle shutdown events */
1334ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN:
1335ef270ab1SKenneth D. Merry 		node_printf(node, "%s received\n", ocs_sm_event_name(evt));
1336ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1337ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_wait_attach_evt_shutdown, NULL);
1338ef270ab1SKenneth D. Merry 		break;
1339ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO:
1340ef270ab1SKenneth D. Merry 		node_printf(node, "%s received\n", ocs_sm_event_name(evt));
1341ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_EXPLICIT_LOGO;
1342ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_wait_attach_evt_shutdown, NULL);
1343ef270ab1SKenneth D. Merry 		break;
1344ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO:
1345ef270ab1SKenneth D. Merry 		node_printf(node, "%s received\n", ocs_sm_event_name(evt));
1346ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_IMPLICIT_LOGO;
1347ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_wait_attach_evt_shutdown, NULL);
1348ef270ab1SKenneth D. Merry 		break;
1349ef270ab1SKenneth D. Merry 	default:
1350ef270ab1SKenneth D. Merry 		__ocs_d_common(__func__, ctx, evt, arg);
1351ef270ab1SKenneth D. Merry 		return NULL;
1352ef270ab1SKenneth D. Merry 	}
1353ef270ab1SKenneth D. Merry 
1354ef270ab1SKenneth D. Merry 	return NULL;
1355ef270ab1SKenneth D. Merry }
1356ef270ab1SKenneth D. Merry 
1357ef270ab1SKenneth D. Merry /**
1358ef270ab1SKenneth D. Merry  * @ingroup device_sm
1359ef270ab1SKenneth D. Merry  * @brief Device node state machine: Wait for a node/domain
1360ef270ab1SKenneth D. Merry  * attach then shutdown node.
1361ef270ab1SKenneth D. Merry  *
1362ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1363ef270ab1SKenneth D. Merry  * @param evt Event to process.
1364ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
1365ef270ab1SKenneth D. Merry  *
1366ef270ab1SKenneth D. Merry  * @return Returns NULL.
1367ef270ab1SKenneth D. Merry  */
1368ef270ab1SKenneth D. Merry 
1369ef270ab1SKenneth D. Merry void *
__ocs_d_wait_attach_evt_shutdown(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)1370ef270ab1SKenneth D. Merry __ocs_d_wait_attach_evt_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1371ef270ab1SKenneth D. Merry {
1372ef270ab1SKenneth D. Merry 	std_node_state_decl();
1373ef270ab1SKenneth D. Merry 
1374ef270ab1SKenneth D. Merry 	node_sm_trace();
1375ef270ab1SKenneth D. Merry 
1376ef270ab1SKenneth D. Merry 	switch(evt) {
1377ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
1378ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
1379ef270ab1SKenneth D. Merry 		break;
1380ef270ab1SKenneth D. Merry 
1381ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
1382ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
1383ef270ab1SKenneth D. Merry 		break;
1384ef270ab1SKenneth D. Merry 
1385ef270ab1SKenneth D. Merry 	/* wait for any of these attach events and then shutdown */
1386ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ATTACH_OK:
1387ef270ab1SKenneth D. Merry 		node->attached = TRUE;
1388ef270ab1SKenneth D. Merry 		node_printf(node, "Attach evt=%s, proceed to shutdown\n", ocs_sm_event_name(evt));
1389ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL);
1390ef270ab1SKenneth D. Merry 		break;
1391ef270ab1SKenneth D. Merry 
1392ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ATTACH_FAIL:
1393ef270ab1SKenneth D. Merry 		/* node attach failed, shutdown the node */
1394ef270ab1SKenneth D. Merry 		node->attached = FALSE;
1395ef270ab1SKenneth D. Merry 		node_printf(node, "Attach evt=%s, proceed to shutdown\n", ocs_sm_event_name(evt));
1396ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL);
1397ef270ab1SKenneth D. Merry 		break;
1398ef270ab1SKenneth D. Merry 
1399ef270ab1SKenneth D. Merry 	/* ignore shutdown events as we're already in shutdown path */
1400ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN:
1401ef270ab1SKenneth D. Merry 		/* have default shutdown event take precedence */
1402ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1403ef270ab1SKenneth D. Merry 		/* fall through */
1404ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO:
1405ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO:
1406ef270ab1SKenneth D. Merry 		node_printf(node, "%s received\n", ocs_sm_event_name(evt));
1407ef270ab1SKenneth D. Merry 		break;
1408ef270ab1SKenneth D. Merry 
1409ef270ab1SKenneth D. Merry 	default:
1410ef270ab1SKenneth D. Merry 		__ocs_d_common(__func__, ctx, evt, arg);
1411ef270ab1SKenneth D. Merry 		return NULL;
1412ef270ab1SKenneth D. Merry 	}
1413ef270ab1SKenneth D. Merry 
1414ef270ab1SKenneth D. Merry 	return NULL;
1415ef270ab1SKenneth D. Merry }
1416ef270ab1SKenneth D. Merry 
1417ef270ab1SKenneth D. Merry /**
1418ef270ab1SKenneth D. Merry  * @ingroup device_sm
1419ef270ab1SKenneth D. Merry  * @brief Device node state machine: Port is logged in.
1420ef270ab1SKenneth D. Merry  *
1421ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1422ef270ab1SKenneth D. Merry  * This state is entered when a remote port has completed port login (PLOGI).
1423ef270ab1SKenneth D. Merry  *
1424ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1425ef270ab1SKenneth D. Merry  * @param evt Event to process
1426ef270ab1SKenneth D. Merry  * @param arg Per event optional argument
1427ef270ab1SKenneth D. Merry  *
1428ef270ab1SKenneth D. Merry  * @return Returns NULL.
1429ef270ab1SKenneth D. Merry  */
1430ef270ab1SKenneth D. Merry void *
__ocs_d_port_logged_in(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)1431ef270ab1SKenneth D. Merry __ocs_d_port_logged_in(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1432ef270ab1SKenneth D. Merry {
1433ef270ab1SKenneth D. Merry 	ocs_node_cb_t *cbdata = arg;
1434ef270ab1SKenneth D. Merry 	std_node_state_decl();
1435ef270ab1SKenneth D. Merry 
1436ef270ab1SKenneth D. Merry 	node_sm_trace();
1437ef270ab1SKenneth D. Merry 
1438ef270ab1SKenneth D. Merry 	/* TODO: I+T: what if PLOGI response not yet received ? */
1439ef270ab1SKenneth D. Merry 
1440ef270ab1SKenneth D. Merry 	switch(evt) {
1441ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
1442ef270ab1SKenneth D. Merry 		/* Normal case for I or I+T */
1443ef270ab1SKenneth D. Merry 		if (node->sport->enable_ini && !FC_ADDR_IS_DOMAIN_CTRL(node->rnode.fc_id)
1444ef270ab1SKenneth D. Merry 				&& !node->sent_prli) {
1445ef270ab1SKenneth D. Merry 			/* sm: if enable_ini / send PRLI */
1446ef270ab1SKenneth D. Merry 			ocs_send_prli(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL);
1447ef270ab1SKenneth D. Merry 			node->sent_prli = TRUE;
1448ef270ab1SKenneth D. Merry 			/* can now expect ELS_REQ_OK/FAIL/RJT */
1449ef270ab1SKenneth D. Merry 		}
1450ef270ab1SKenneth D. Merry 		break;
1451ef270ab1SKenneth D. Merry 
1452ef270ab1SKenneth D. Merry 	case OCS_EVT_FCP_CMD_RCVD: {
1453ef270ab1SKenneth D. Merry 		/* For target functionality send PRLO and drop the CMD frame. */
1454ef270ab1SKenneth D. Merry 		if (node->sport->enable_tgt) {
1455ef270ab1SKenneth D. Merry 			if (ocs_send_prlo(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT,
1456ef270ab1SKenneth D. Merry 				OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL)) {
1457ef270ab1SKenneth D. Merry 				ocs_node_transition(node, __ocs_d_wait_prlo_rsp, NULL);
1458ef270ab1SKenneth D. Merry 			}
1459ef270ab1SKenneth D. Merry 		}
1460ef270ab1SKenneth D. Merry 		break;
1461ef270ab1SKenneth D. Merry 	}
1462ef270ab1SKenneth D. Merry 
1463ef270ab1SKenneth D. Merry 	case OCS_EVT_PRLI_RCVD: {
1464ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
1465ef270ab1SKenneth D. Merry 
1466ef270ab1SKenneth D. Merry 		/* Normal for T or I+T */
1467ef270ab1SKenneth D. Merry 
1468ef270ab1SKenneth D. Merry 		ocs_process_prli_payload(node, cbdata->payload->dma.virt);
1469ef270ab1SKenneth D. Merry 		ocs_d_send_prli_rsp(cbdata->io, ocs_be16toh(hdr->ox_id));
1470ef270ab1SKenneth D. Merry 		break;
1471ef270ab1SKenneth D. Merry 	}
1472ef270ab1SKenneth D. Merry 
1473ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_OK: {	/* PRLI response */
1474ef270ab1SKenneth D. Merry 		/* Normal case for I or I+T */
1475ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PRLI, __ocs_d_common, __func__)) {
1476ef270ab1SKenneth D. Merry 			return NULL;
1477ef270ab1SKenneth D. Merry 		}
1478ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
1479ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
1480ef270ab1SKenneth D. Merry 		/* sm: process PRLI payload */
1481ef270ab1SKenneth D. Merry 		ocs_process_prli_payload(node, cbdata->els->els_rsp.virt);
1482ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_device_ready, NULL);
1483ef270ab1SKenneth D. Merry 		break;
1484ef270ab1SKenneth D. Merry 	}
1485ef270ab1SKenneth D. Merry 
1486ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_FAIL: {	/* PRLI response failed */
1487ef270ab1SKenneth D. Merry 		/* I, I+T, assume some link failure, shutdown node */
1488ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PRLI, __ocs_d_common, __func__)) {
1489ef270ab1SKenneth D. Merry 			return NULL;
1490ef270ab1SKenneth D. Merry 		}
1491ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
1492ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
1493ef270ab1SKenneth D. Merry 		ocs_node_post_event(node, OCS_EVT_SHUTDOWN, NULL);
1494ef270ab1SKenneth D. Merry 		break;
1495ef270ab1SKenneth D. Merry 	}
1496ef270ab1SKenneth D. Merry 
1497ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_RJT: {/* PRLI rejected by remote */
1498ef270ab1SKenneth D. Merry 		/* Normal for I, I+T (connected to an I) */
1499ef270ab1SKenneth D. Merry 		/* Node doesn't want to be a target, stay here and wait for a PRLI from the remote node
1500ef270ab1SKenneth D. Merry 		 * if it really wants to connect to us as target */
1501ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PRLI, __ocs_d_common, __func__)) {
1502ef270ab1SKenneth D. Merry 			return NULL;
1503ef270ab1SKenneth D. Merry 		}
1504ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
1505ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
1506ef270ab1SKenneth D. Merry 		break;
1507ef270ab1SKenneth D. Merry 	}
1508ef270ab1SKenneth D. Merry 
1509ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_CMPL_OK: {
1510ef270ab1SKenneth D. Merry 		/* Normal T, I+T, target-server rejected the process login */
1511ef270ab1SKenneth D. Merry 		/* This would be received only in the case where we sent LS_RJT for the PRLI, so
1512ef270ab1SKenneth D. Merry 		 * do nothing.   (note: as T only we could shutdown the node)
1513ef270ab1SKenneth D. Merry 		 */
1514ef270ab1SKenneth D. Merry 		ocs_assert(node->els_cmpl_cnt, NULL);
1515ef270ab1SKenneth D. Merry 		node->els_cmpl_cnt--;
1516ef270ab1SKenneth D. Merry 		break;
1517ef270ab1SKenneth D. Merry 	}
1518ef270ab1SKenneth D. Merry 
1519ef270ab1SKenneth D. Merry 	case OCS_EVT_PLOGI_RCVD: {
1520ef270ab1SKenneth D. Merry 		/* sm: save sparams, set send_plogi_acc, post implicit logout
1521ef270ab1SKenneth D. Merry 		 * Save plogi parameters */
1522ef270ab1SKenneth D. Merry 		ocs_node_save_sparms(node, cbdata->payload->dma.virt);
1523ef270ab1SKenneth D. Merry 		ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PLOGI);
1524ef270ab1SKenneth D. Merry 
1525ef270ab1SKenneth D. Merry 		/* Restart node attach with new service parameters, and send ACC */
1526ef270ab1SKenneth D. Merry 		ocs_node_post_event(node, OCS_EVT_SHUTDOWN_IMPLICIT_LOGO, NULL);
1527ef270ab1SKenneth D. Merry 		break;
1528ef270ab1SKenneth D. Merry 	}
1529ef270ab1SKenneth D. Merry 
1530ef270ab1SKenneth D. Merry 	case OCS_EVT_LOGO_RCVD: {
1531ef270ab1SKenneth D. Merry 		/* I, T, I+T */
1532ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
1533ef270ab1SKenneth D. Merry 		node_printf(node, "%s received attached=%d\n", ocs_sm_event_name(evt), node->attached);
1534ef270ab1SKenneth D. Merry 		ocs_send_logo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1535ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_wait_logo_acc_cmpl, NULL);
1536ef270ab1SKenneth D. Merry 		break;
1537ef270ab1SKenneth D. Merry 	}
1538ef270ab1SKenneth D. Merry 
1539ef270ab1SKenneth D. Merry 	default:
1540ef270ab1SKenneth D. Merry 		__ocs_d_common(__func__, ctx, evt, arg);
1541ef270ab1SKenneth D. Merry 		return NULL;
1542ef270ab1SKenneth D. Merry 	}
1543ef270ab1SKenneth D. Merry 
1544ef270ab1SKenneth D. Merry 	return NULL;
1545ef270ab1SKenneth D. Merry }
1546ef270ab1SKenneth D. Merry 
1547ef270ab1SKenneth D. Merry /**
1548ef270ab1SKenneth D. Merry  * @ingroup device_sm
1549ef270ab1SKenneth D. Merry  * @brief Device node state machine: Wait for a LOGO accept.
1550ef270ab1SKenneth D. Merry  *
1551ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1552ef270ab1SKenneth D. Merry  * Waits for a LOGO accept completion.
1553ef270ab1SKenneth D. Merry  *
1554ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1555ef270ab1SKenneth D. Merry  * @param evt Event to process
1556ef270ab1SKenneth D. Merry  * @param arg Per event optional argument
1557ef270ab1SKenneth D. Merry  *
1558ef270ab1SKenneth D. Merry  * @return Returns NULL.
1559ef270ab1SKenneth D. Merry  */
1560ef270ab1SKenneth D. Merry 
1561ef270ab1SKenneth D. Merry void *
__ocs_d_wait_logo_acc_cmpl(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)1562ef270ab1SKenneth D. Merry __ocs_d_wait_logo_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1563ef270ab1SKenneth D. Merry {
1564ef270ab1SKenneth D. Merry 	std_node_state_decl();
1565ef270ab1SKenneth D. Merry 
1566ef270ab1SKenneth D. Merry 	node_sm_trace();
1567ef270ab1SKenneth D. Merry 
1568ef270ab1SKenneth D. Merry 	switch(evt) {
1569ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
1570ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
1571ef270ab1SKenneth D. Merry 		break;
1572ef270ab1SKenneth D. Merry 
1573ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
1574ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
1575ef270ab1SKenneth D. Merry 		break;
1576ef270ab1SKenneth D. Merry 
1577ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_CMPL_OK:
1578ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_CMPL_FAIL:
1579ef270ab1SKenneth D. Merry 		/* sm: / post explicit logout */
1580ef270ab1SKenneth D. Merry 		ocs_assert(node->els_cmpl_cnt, NULL);
1581ef270ab1SKenneth D. Merry 		node->els_cmpl_cnt--;
1582ef270ab1SKenneth D. Merry 		ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
1583ef270ab1SKenneth D. Merry 		break;
1584ef270ab1SKenneth D. Merry 	default:
1585ef270ab1SKenneth D. Merry 		__ocs_d_common(__func__, ctx, evt, arg);
1586ef270ab1SKenneth D. Merry 		return NULL;
1587ef270ab1SKenneth D. Merry 	}
1588ef270ab1SKenneth D. Merry 
1589ef270ab1SKenneth D. Merry 	return NULL;
1590ef270ab1SKenneth D. Merry }
1591ef270ab1SKenneth D. Merry 
1592ef270ab1SKenneth D. Merry /**
1593ef270ab1SKenneth D. Merry  * @ingroup device_sm
1594ef270ab1SKenneth D. Merry  * @brief Device node state machine: Device is ready.
1595ef270ab1SKenneth D. Merry  *
1596ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1597ef270ab1SKenneth D. Merry  * @param evt Event to process.
1598ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
1599ef270ab1SKenneth D. Merry  *
1600ef270ab1SKenneth D. Merry  * @return Returns NULL.
1601ef270ab1SKenneth D. Merry  */
1602ef270ab1SKenneth D. Merry 
1603ef270ab1SKenneth D. Merry void *
__ocs_d_device_ready(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)1604ef270ab1SKenneth D. Merry __ocs_d_device_ready(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1605ef270ab1SKenneth D. Merry {
1606ef270ab1SKenneth D. Merry 	ocs_node_cb_t *cbdata = arg;
1607ef270ab1SKenneth D. Merry 	std_node_state_decl();
1608ef270ab1SKenneth D. Merry 
1609ef270ab1SKenneth D. Merry 	if (evt != OCS_EVT_FCP_CMD_RCVD) {
1610ef270ab1SKenneth D. Merry 		node_sm_trace();
1611ef270ab1SKenneth D. Merry 	}
1612ef270ab1SKenneth D. Merry 
1613ef270ab1SKenneth D. Merry 	switch(evt) {
1614ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
1615ef270ab1SKenneth D. Merry 		node->fcp_enabled = TRUE;
1616ef270ab1SKenneth D. Merry 		if (node->init) {
1617ef270ab1SKenneth D. Merry 			device_printf(ocs->dev, "[%s] found  (initiator) WWPN %s WWNN %s\n", node->display_name,
1618ef270ab1SKenneth D. Merry 				node->wwpn, node->wwnn);
1619ef270ab1SKenneth D. Merry 			if (node->sport->enable_tgt)
1620ef270ab1SKenneth D. Merry 				ocs_scsi_new_initiator(node);
1621ef270ab1SKenneth D. Merry 		}
1622ef270ab1SKenneth D. Merry 		if (node->targ) {
1623ef270ab1SKenneth D. Merry 			device_printf(ocs->dev, "[%s] found  (target)    WWPN %s WWNN %s\n", node->display_name,
1624ef270ab1SKenneth D. Merry 				node->wwpn, node->wwnn);
1625ef270ab1SKenneth D. Merry 			if (node->sport->enable_ini)
1626ef270ab1SKenneth D. Merry 				ocs_scsi_new_target(node);
1627ef270ab1SKenneth D. Merry 		}
1628ef270ab1SKenneth D. Merry 		break;
1629ef270ab1SKenneth D. Merry 
1630ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
1631ef270ab1SKenneth D. Merry 		node->fcp_enabled = FALSE;
1632ef270ab1SKenneth D. Merry 		break;
1633ef270ab1SKenneth D. Merry 
1634ef270ab1SKenneth D. Merry 	case OCS_EVT_PLOGI_RCVD: {
1635ef270ab1SKenneth D. Merry 		/* sm: save sparams, set send_plogi_acc, post implicit logout
1636ef270ab1SKenneth D. Merry 		 * Save plogi parameters */
1637ef270ab1SKenneth D. Merry 		ocs_node_save_sparms(node, cbdata->payload->dma.virt);
1638ef270ab1SKenneth D. Merry 		ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PLOGI);
1639ef270ab1SKenneth D. Merry 
1640ef270ab1SKenneth D. Merry 		/* Restart node attach with new service parameters, and send ACC */
1641ef270ab1SKenneth D. Merry 		ocs_node_post_event(node, OCS_EVT_SHUTDOWN_IMPLICIT_LOGO, NULL);
1642ef270ab1SKenneth D. Merry 		break;
1643ef270ab1SKenneth D. Merry 	}
1644ef270ab1SKenneth D. Merry 
1645ef270ab1SKenneth D. Merry 	case OCS_EVT_PDISC_RCVD: {
1646ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
1647ef270ab1SKenneth D. Merry 		ocs_send_plogi_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1648ef270ab1SKenneth D. Merry 		break;
1649ef270ab1SKenneth D. Merry 	}
1650ef270ab1SKenneth D. Merry 
1651ef270ab1SKenneth D. Merry 	case OCS_EVT_PRLI_RCVD: {
1652ef270ab1SKenneth D. Merry 		/* T, I+T: remote initiator is slow to get started */
1653ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
1654ef270ab1SKenneth D. Merry 
1655ef270ab1SKenneth D. Merry 		ocs_process_prli_payload(node, cbdata->payload->dma.virt);
1656ef270ab1SKenneth D. Merry 
1657ef270ab1SKenneth D. Merry 		/* sm: send PRLI acc/reject */
1658ef270ab1SKenneth D. Merry 		if (ocs->fc_type == node->fc_type)
1659ef270ab1SKenneth D. Merry 			ocs_send_prli_acc(cbdata->io, ocs_be16toh(hdr->ox_id), ocs->fc_type, NULL, NULL);
1660ef270ab1SKenneth D. Merry 		else
1661ef270ab1SKenneth D. Merry 			ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id), FC_REASON_UNABLE_TO_PERFORM,
1662ef270ab1SKenneth D. Merry 				FC_EXPL_REQUEST_NOT_SUPPORTED, 0, NULL, NULL);
1663ef270ab1SKenneth D. Merry 		break;
1664ef270ab1SKenneth D. Merry 	}
1665ef270ab1SKenneth D. Merry 
1666ef270ab1SKenneth D. Merry 	case OCS_EVT_PRLO_RCVD: {
1667ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
1668ef270ab1SKenneth D. Merry 		fc_prlo_payload_t *prlo = cbdata->payload->dma.virt;
1669ef270ab1SKenneth D. Merry 
1670ef270ab1SKenneth D. Merry 		/* sm: send PRLO acc/reject */
1671ef270ab1SKenneth D. Merry 		if (ocs->fc_type == prlo->type)
1672ef270ab1SKenneth D. Merry 			ocs_send_prlo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), ocs->fc_type, NULL, NULL);
1673ef270ab1SKenneth D. Merry 		else
1674ef270ab1SKenneth D. Merry 			ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id), FC_REASON_UNABLE_TO_PERFORM,
1675ef270ab1SKenneth D. Merry 				FC_EXPL_REQUEST_NOT_SUPPORTED, 0, NULL, NULL);
1676ef270ab1SKenneth D. Merry 		/*TODO: need implicit logout */
1677ef270ab1SKenneth D. Merry 		break;
1678ef270ab1SKenneth D. Merry 	}
1679ef270ab1SKenneth D. Merry 
1680ef270ab1SKenneth D. Merry 	case OCS_EVT_LOGO_RCVD: {
1681ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
1682ef270ab1SKenneth D. Merry 		node_printf(node, "%s received attached=%d\n", ocs_sm_event_name(evt), node->attached);
1683ef270ab1SKenneth D. Merry 		ocs_send_logo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1684ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_wait_logo_acc_cmpl, NULL);
1685ef270ab1SKenneth D. Merry 		break;
1686ef270ab1SKenneth D. Merry 	}
1687ef270ab1SKenneth D. Merry 
1688ef270ab1SKenneth D. Merry 	case OCS_EVT_ADISC_RCVD: {
1689ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
1690ef270ab1SKenneth D. Merry 		ocs_send_adisc_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1691ef270ab1SKenneth D. Merry 		break;
1692ef270ab1SKenneth D. Merry 	}
1693ef270ab1SKenneth D. Merry 
1694ef270ab1SKenneth D. Merry 	case OCS_EVT_RRQ_RCVD: {
1695ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
1696ef270ab1SKenneth D. Merry 		/* Send LS_ACC */
1697ef270ab1SKenneth D. Merry 		ocs_send_ls_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1698ef270ab1SKenneth D. Merry 		break;
1699ef270ab1SKenneth D. Merry 	}
1700ef270ab1SKenneth D. Merry 
1701ef270ab1SKenneth D. Merry 	case OCS_EVT_ABTS_RCVD:
1702ef270ab1SKenneth D. Merry 		ocs_process_abts(cbdata->io, cbdata->header->dma.virt);
1703ef270ab1SKenneth D. Merry 		break;
1704ef270ab1SKenneth D. Merry 
1705ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
1706ef270ab1SKenneth D. Merry 		break;
1707ef270ab1SKenneth D. Merry 
1708ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_REFOUND:
1709ef270ab1SKenneth D. Merry 		break;
1710ef270ab1SKenneth D. Merry 
1711ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_MISSING:
1712ef270ab1SKenneth D. Merry 		if (node->sport->enable_rscn) {
1713ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_d_device_gone, NULL);
1714ef270ab1SKenneth D. Merry 		}
1715ef270ab1SKenneth D. Merry 		break;
1716ef270ab1SKenneth D. Merry 
1717ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_CMPL_OK:
1718ef270ab1SKenneth D. Merry 		/* T, or I+T, PRLI accept completed ok */
1719ef270ab1SKenneth D. Merry 		ocs_assert(node->els_cmpl_cnt, NULL);
1720ef270ab1SKenneth D. Merry 		node->els_cmpl_cnt--;
1721ef270ab1SKenneth D. Merry 		break;
1722ef270ab1SKenneth D. Merry 
1723ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_CMPL_FAIL:
1724ef270ab1SKenneth D. Merry 		/* T, or I+T, PRLI accept failed to complete */
1725ef270ab1SKenneth D. Merry 		ocs_assert(node->els_cmpl_cnt, NULL);
1726ef270ab1SKenneth D. Merry 		node->els_cmpl_cnt--;
1727ef270ab1SKenneth D. Merry 		node_printf(node, "Failed to send PRLI LS_ACC\n");
1728ef270ab1SKenneth D. Merry 		break;
1729ef270ab1SKenneth D. Merry 
1730ef270ab1SKenneth D. Merry 	default:
1731ef270ab1SKenneth D. Merry 		__ocs_d_common(__func__, ctx, evt, arg);
1732ef270ab1SKenneth D. Merry 		return NULL;
1733ef270ab1SKenneth D. Merry 	}
1734ef270ab1SKenneth D. Merry 
1735ef270ab1SKenneth D. Merry 	return NULL;
1736ef270ab1SKenneth D. Merry }
1737ef270ab1SKenneth D. Merry 
1738ef270ab1SKenneth D. Merry /**
1739ef270ab1SKenneth D. Merry  * @ingroup device_sm
1740ef270ab1SKenneth D. Merry  * @brief Device node state machine: Node is gone (absent from GID_PT).
1741ef270ab1SKenneth D. Merry  *
1742ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1743ef270ab1SKenneth D. Merry  * State entered when a node is detected as being gone (absent from GID_PT).
1744ef270ab1SKenneth D. Merry  *
1745ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1746ef270ab1SKenneth D. Merry  * @param evt Event to process
1747ef270ab1SKenneth D. Merry  * @param arg Per event optional argument
1748ef270ab1SKenneth D. Merry  *
1749ef270ab1SKenneth D. Merry  * @return Returns NULL.
1750ef270ab1SKenneth D. Merry  */
1751ef270ab1SKenneth D. Merry 
1752ef270ab1SKenneth D. Merry void *
__ocs_d_device_gone(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)1753ef270ab1SKenneth D. Merry __ocs_d_device_gone(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1754ef270ab1SKenneth D. Merry {
1755ef270ab1SKenneth D. Merry 	int32_t rc = OCS_SCSI_CALL_COMPLETE;
1756ef270ab1SKenneth D. Merry 	int32_t rc_2 = OCS_SCSI_CALL_COMPLETE;
1757ef270ab1SKenneth D. Merry 	ocs_node_cb_t *cbdata = arg;
1758ef270ab1SKenneth D. Merry 	std_node_state_decl();
1759ef270ab1SKenneth D. Merry 
1760ef270ab1SKenneth D. Merry 	node_sm_trace();
1761ef270ab1SKenneth D. Merry 
1762ef270ab1SKenneth D. Merry 	switch(evt) {
1763ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER: {
1764ef270ab1SKenneth D. Merry 		const char *labels[] = {"none", "initiator", "target", "initiator+target"};
1765ef270ab1SKenneth D. Merry 
1766ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "[%s] missing (%s)    WWPN %s WWNN %s\n", node->display_name,
1767ef270ab1SKenneth D. Merry 				labels[(node->targ << 1) | (node->init)], node->wwpn, node->wwnn);
1768ef270ab1SKenneth D. Merry 
1769ef270ab1SKenneth D. Merry 		switch(ocs_node_get_enable(node)) {
1770ef270ab1SKenneth D. Merry 		case OCS_NODE_ENABLE_T_TO_T:
1771ef270ab1SKenneth D. Merry 		case OCS_NODE_ENABLE_I_TO_T:
1772ef270ab1SKenneth D. Merry 		case OCS_NODE_ENABLE_IT_TO_T:
1773ef270ab1SKenneth D. Merry 			rc = ocs_scsi_del_target(node, OCS_SCSI_TARGET_MISSING);
1774ef270ab1SKenneth D. Merry 			break;
1775ef270ab1SKenneth D. Merry 
1776ef270ab1SKenneth D. Merry 		case OCS_NODE_ENABLE_T_TO_I:
1777ef270ab1SKenneth D. Merry 		case OCS_NODE_ENABLE_I_TO_I:
1778ef270ab1SKenneth D. Merry 		case OCS_NODE_ENABLE_IT_TO_I:
1779ef270ab1SKenneth D. Merry 			rc = ocs_scsi_del_initiator(node, OCS_SCSI_INITIATOR_MISSING);
1780ef270ab1SKenneth D. Merry 			break;
1781ef270ab1SKenneth D. Merry 
1782ef270ab1SKenneth D. Merry 		case OCS_NODE_ENABLE_T_TO_IT:
1783ef270ab1SKenneth D. Merry 			rc = ocs_scsi_del_initiator(node, OCS_SCSI_INITIATOR_MISSING);
1784ef270ab1SKenneth D. Merry 			break;
1785ef270ab1SKenneth D. Merry 
1786ef270ab1SKenneth D. Merry 		case OCS_NODE_ENABLE_I_TO_IT:
1787ef270ab1SKenneth D. Merry 			rc = ocs_scsi_del_target(node, OCS_SCSI_TARGET_MISSING);
1788ef270ab1SKenneth D. Merry 			break;
1789ef270ab1SKenneth D. Merry 
1790ef270ab1SKenneth D. Merry 		case OCS_NODE_ENABLE_IT_TO_IT:
1791ef270ab1SKenneth D. Merry 			rc = ocs_scsi_del_initiator(node, OCS_SCSI_INITIATOR_MISSING);
1792ef270ab1SKenneth D. Merry 			rc_2 = ocs_scsi_del_target(node, OCS_SCSI_TARGET_MISSING);
1793ef270ab1SKenneth D. Merry 			break;
1794ef270ab1SKenneth D. Merry 
1795ef270ab1SKenneth D. Merry 		default:
1796ef270ab1SKenneth D. Merry 			rc = OCS_SCSI_CALL_COMPLETE;
1797ef270ab1SKenneth D. Merry 			break;
1798ef270ab1SKenneth D. Merry 		}
1799ef270ab1SKenneth D. Merry 
1800ef270ab1SKenneth D. Merry 		if ((rc == OCS_SCSI_CALL_COMPLETE) && (rc_2 == OCS_SCSI_CALL_COMPLETE)) {
1801ef270ab1SKenneth D. Merry 			ocs_node_post_event(node, OCS_EVT_SHUTDOWN, NULL);
1802ef270ab1SKenneth D. Merry 		}
1803ef270ab1SKenneth D. Merry 
1804ef270ab1SKenneth D. Merry 		break;
1805ef270ab1SKenneth D. Merry 	}
1806ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_REFOUND:
1807ef270ab1SKenneth D. Merry 		/* two approaches, reauthenticate with PLOGI/PRLI, or ADISC */
1808ef270ab1SKenneth D. Merry 
1809ef270ab1SKenneth D. Merry 		/* reauthenticate with PLOGI/PRLI */
1810ef270ab1SKenneth D. Merry 		/* ocs_node_transition(node, __ocs_d_discovered, NULL); */
1811ef270ab1SKenneth D. Merry 
1812ef270ab1SKenneth D. Merry 		/* reauthenticate with ADISC
1813ef270ab1SKenneth D. Merry 		 * sm: send ADISC */
1814ef270ab1SKenneth D. Merry 		ocs_send_adisc(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL);
1815ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_wait_adisc_rsp, NULL);
1816ef270ab1SKenneth D. Merry 		break;
1817ef270ab1SKenneth D. Merry 
1818ef270ab1SKenneth D. Merry 	case OCS_EVT_PLOGI_RCVD: {
1819ef270ab1SKenneth D. Merry 		/* sm: save sparams, set send_plogi_acc, post implicit logout
1820ef270ab1SKenneth D. Merry 		 * Save plogi parameters */
1821ef270ab1SKenneth D. Merry 		ocs_node_save_sparms(node, cbdata->payload->dma.virt);
1822ef270ab1SKenneth D. Merry 		ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PLOGI);
1823ef270ab1SKenneth D. Merry 
1824ef270ab1SKenneth D. Merry 		/* Restart node attach with new service parameters, and send ACC */
1825ef270ab1SKenneth D. Merry 		ocs_node_post_event(node, OCS_EVT_SHUTDOWN_IMPLICIT_LOGO, NULL);
1826ef270ab1SKenneth D. Merry 		break;
1827ef270ab1SKenneth D. Merry 	}
1828ef270ab1SKenneth D. Merry 
1829ef270ab1SKenneth D. Merry 	case OCS_EVT_FCP_CMD_RCVD: {
1830ef270ab1SKenneth D. Merry 		/* most likely a stale frame (received prior to link down), if attempt
1831ef270ab1SKenneth D. Merry 		 * to send LOGO, will probably timeout and eat up 20s; thus, drop FCP_CMND
1832ef270ab1SKenneth D. Merry 		 */
1833ef270ab1SKenneth D. Merry 		node_printf(node, "FCP_CMND received, drop\n");
1834ef270ab1SKenneth D. Merry 		break;
1835ef270ab1SKenneth D. Merry 	}
1836ef270ab1SKenneth D. Merry 	case OCS_EVT_LOGO_RCVD: {
1837ef270ab1SKenneth D. Merry 		/* I, T, I+T */
1838ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
1839ef270ab1SKenneth D. Merry 		node_printf(node, "%s received attached=%d\n", ocs_sm_event_name(evt), node->attached);
1840ef270ab1SKenneth D. Merry 		/* sm: send LOGO acc */
1841ef270ab1SKenneth D. Merry 		ocs_send_logo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1842ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_wait_logo_acc_cmpl, NULL);
1843ef270ab1SKenneth D. Merry 		break;
1844ef270ab1SKenneth D. Merry 	}
1845ef270ab1SKenneth D. Merry 	default:
1846ef270ab1SKenneth D. Merry 		__ocs_d_common(__func__, ctx, evt, arg);
1847ef270ab1SKenneth D. Merry 		return NULL;
1848ef270ab1SKenneth D. Merry 	}
1849ef270ab1SKenneth D. Merry 
1850ef270ab1SKenneth D. Merry 	return NULL;
1851ef270ab1SKenneth D. Merry }
1852ef270ab1SKenneth D. Merry 
1853ef270ab1SKenneth D. Merry /**
1854ef270ab1SKenneth D. Merry  * @ingroup device_sm
1855ef270ab1SKenneth D. Merry  * @brief Device node state machine: Wait for the ADISC response.
1856ef270ab1SKenneth D. Merry  *
1857ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1858ef270ab1SKenneth D. Merry  * Waits for the ADISC response from the remote node.
1859ef270ab1SKenneth D. Merry  *
1860ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1861ef270ab1SKenneth D. Merry  * @param evt Event to process.
1862ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
1863ef270ab1SKenneth D. Merry  *
1864ef270ab1SKenneth D. Merry  * @return Returns NULL.
1865ef270ab1SKenneth D. Merry  */
1866ef270ab1SKenneth D. Merry 
1867ef270ab1SKenneth D. Merry void *
__ocs_d_wait_adisc_rsp(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)1868ef270ab1SKenneth D. Merry __ocs_d_wait_adisc_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1869ef270ab1SKenneth D. Merry {
1870ef270ab1SKenneth D. Merry 	ocs_node_cb_t *cbdata = arg;
1871ef270ab1SKenneth D. Merry 	std_node_state_decl();
1872ef270ab1SKenneth D. Merry 
1873ef270ab1SKenneth D. Merry 	node_sm_trace();
1874ef270ab1SKenneth D. Merry 
1875ef270ab1SKenneth D. Merry 	switch(evt) {
1876ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_OK:
1877ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_ADISC, __ocs_d_common, __func__)) {
1878ef270ab1SKenneth D. Merry 			return NULL;
1879ef270ab1SKenneth D. Merry 		}
1880ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
1881ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
1882ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_device_ready, NULL);
1883ef270ab1SKenneth D. Merry 		break;
1884ef270ab1SKenneth D. Merry 
1885ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_RJT:
1886ef270ab1SKenneth D. Merry 		/* received an LS_RJT, in this case, send shutdown (explicit logo)
1887ef270ab1SKenneth D. Merry 		 * event which will unregister the node, and start over with PLOGI
1888ef270ab1SKenneth D. Merry 		 */
1889ef270ab1SKenneth D. Merry 		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_ADISC, __ocs_d_common, __func__)) {
1890ef270ab1SKenneth D. Merry 			return NULL;
1891ef270ab1SKenneth D. Merry 		}
1892ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
1893ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
1894ef270ab1SKenneth D. Merry 		/*sm: post explicit logout */
1895ef270ab1SKenneth D. Merry 		ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
1896ef270ab1SKenneth D. Merry 		break;
1897ef270ab1SKenneth D. Merry 
1898ef270ab1SKenneth D. Merry 	case OCS_EVT_LOGO_RCVD: {
1899ef270ab1SKenneth D. Merry 		/* In this case, we have the equivalent of an LS_RJT for the ADISC,
1900ef270ab1SKenneth D. Merry 		 * so we need to abort the ADISC, and re-login with PLOGI
1901ef270ab1SKenneth D. Merry 		 */
1902ef270ab1SKenneth D. Merry 		/*sm: request abort, send LOGO acc */
1903ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
1904ef270ab1SKenneth D. Merry 		node_printf(node, "%s received attached=%d\n", ocs_sm_event_name(evt), node->attached);
1905ef270ab1SKenneth D. Merry 		ocs_send_logo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1906ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_d_wait_logo_acc_cmpl, NULL);
1907ef270ab1SKenneth D. Merry 		break;
1908ef270ab1SKenneth D. Merry 	}
1909ef270ab1SKenneth D. Merry 	default:
1910ef270ab1SKenneth D. Merry 		__ocs_d_common(__func__, ctx, evt, arg);
1911ef270ab1SKenneth D. Merry 		return NULL;
1912ef270ab1SKenneth D. Merry 	}
1913ef270ab1SKenneth D. Merry 
1914ef270ab1SKenneth D. Merry 	return NULL;
1915ef270ab1SKenneth D. Merry }
1916