1331766Sken/*-
2331766Sken * Copyright (c) 2017 Broadcom. All rights reserved.
3331766Sken * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
4331766Sken *
5331766Sken * Redistribution and use in source and binary forms, with or without
6331766Sken * modification, are permitted provided that the following conditions are met:
7331766Sken *
8331766Sken * 1. Redistributions of source code must retain the above copyright notice,
9331766Sken *    this list of conditions and the following disclaimer.
10331766Sken *
11331766Sken * 2. Redistributions in binary form must reproduce the above copyright notice,
12331766Sken *    this list of conditions and the following disclaimer in the documentation
13331766Sken *    and/or other materials provided with the distribution.
14331766Sken *
15331766Sken * 3. Neither the name of the copyright holder nor the names of its contributors
16331766Sken *    may be used to endorse or promote products derived from this software
17331766Sken *    without specific prior written permission.
18331766Sken *
19331766Sken * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20331766Sken * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21331766Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22331766Sken * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23331766Sken * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24331766Sken * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25331766Sken * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26331766Sken * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27331766Sken * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28331766Sken * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29331766Sken * POSSIBILITY OF SUCH DAMAGE.
30331766Sken *
31331766Sken * $FreeBSD: stable/11/sys/dev/ocs_fc/ocs_device.c 360415 2020-04-27 23:49:13Z brooks $
32331766Sken */
33331766Sken
34331766Sken/**
35331766Sken * @file
36331766Sken * Implement remote device state machine for target and initiator.
37331766Sken */
38331766Sken
39331766Sken/*!
40331766Sken@defgroup device_sm Node State Machine: Remote Device States
41331766Sken*/
42331766Sken
43331766Sken#include "ocs.h"
44331766Sken#include "ocs_device.h"
45331766Sken#include "ocs_fabric.h"
46331766Sken#include "ocs_els.h"
47331766Sken
48331766Skenstatic void *__ocs_d_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
49331766Skenstatic void *__ocs_d_wait_del_node(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
50331766Skenstatic void *__ocs_d_wait_del_ini_tgt(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
51331766Skenstatic int32_t ocs_process_abts(ocs_io_t *io, fc_header_t *hdr);
52331766Sken
53331766Sken/**
54331766Sken * @ingroup device_sm
55331766Sken * @brief Send response to PRLI.
56331766Sken *
57331766Sken * <h3 class="desc">Description</h3>
58331766Sken * For device nodes, this function sends a PRLI response.
59331766Sken *
60331766Sken * @param io Pointer to a SCSI IO object.
61331766Sken * @param ox_id OX_ID of PRLI
62331766Sken *
63331766Sken * @return Returns None.
64331766Sken */
65331766Sken
66331766Skenvoid
67331766Skenocs_d_send_prli_rsp(ocs_io_t *io, uint16_t ox_id)
68331766Sken{
69331766Sken	ocs_t *ocs = io->ocs;
70331766Sken	ocs_node_t *node = io->node;
71331766Sken
72331766Sken	/* If the back-end doesn't support the fc-type, we send an LS_RJT */
73331766Sken	if (ocs->fc_type != node->fc_type) {
74331766Sken		node_printf(node, "PRLI rejected by target-server, fc-type not supported\n");
75331766Sken		ocs_send_ls_rjt(io, ox_id, FC_REASON_UNABLE_TO_PERFORM,
76331766Sken				FC_EXPL_REQUEST_NOT_SUPPORTED, 0, NULL, NULL);
77331766Sken		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
78331766Sken		ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL);
79331766Sken	}
80331766Sken
81331766Sken	/* If the back-end doesn't want to talk to this initiator, we send an LS_RJT */
82331766Sken	if (node->sport->enable_tgt && (ocs_scsi_validate_initiator(node) == 0)) {
83331766Sken		node_printf(node, "PRLI rejected by target-server\n");
84331766Sken		ocs_send_ls_rjt(io, ox_id, FC_REASON_UNABLE_TO_PERFORM,
85331766Sken				FC_EXPL_NO_ADDITIONAL, 0, NULL, NULL);
86331766Sken		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
87331766Sken		ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL);
88331766Sken	} else {
89331766Sken		/*sm:  process PRLI payload, send PRLI acc */
90331766Sken		ocs_send_prli_acc(io, ox_id, ocs->fc_type, NULL, NULL);
91331766Sken
92331766Sken		/* Immediately go to ready state to avoid window where we're
93331766Sken		 * waiting for the PRLI LS_ACC to complete while holding FCP_CMNDs
94331766Sken		 */
95331766Sken		ocs_node_transition(node, __ocs_d_device_ready, NULL);
96331766Sken	}
97331766Sken}
98331766Sken
99331766Sken/**
100331766Sken * @ingroup device_sm
101331766Sken * @brief Device node state machine: Initiate node shutdown
102331766Sken *
103331766Sken * @param ctx Remote node state machine context.
104331766Sken * @param evt Event to process.
105331766Sken * @param arg Per event optional argument.
106331766Sken *
107331766Sken * @return Returns NULL.
108331766Sken */
109331766Sken
110331766Skenvoid *
111331766Sken__ocs_d_initiate_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
112331766Sken{
113331766Sken	std_node_state_decl();
114331766Sken
115331766Sken	node_sm_trace();
116331766Sken
117331766Sken	switch(evt) {
118331766Sken	case OCS_EVT_ENTER: {
119331766Sken		int32_t rc = OCS_SCSI_CALL_COMPLETE; /* assume no wait needed */
120331766Sken
121331766Sken		ocs_scsi_io_alloc_disable(node);
122331766Sken
123331766Sken		/* make necessary delete upcall(s) */
124331766Sken		if (node->init && !node->targ) {
125331766Sken			ocs_log_debug(node->ocs,
126331766Sken				"[%s] delete (initiator) WWPN %s WWNN %s\n",
127331766Sken				node->display_name, node->wwpn, node->wwnn);
128331766Sken			ocs_node_transition(node, __ocs_d_wait_del_node, NULL);
129331766Sken			if (node->sport->enable_tgt) {
130331766Sken				rc = ocs_scsi_del_initiator(node,
131331766Sken						OCS_SCSI_INITIATOR_DELETED);
132331766Sken			}
133331766Sken			if (rc == OCS_SCSI_CALL_COMPLETE) {
134331766Sken				ocs_node_post_event(node,
135331766Sken					OCS_EVT_NODE_DEL_INI_COMPLETE, NULL);
136331766Sken			}
137331766Sken		} else if (node->targ && !node->init) {
138331766Sken			ocs_log_debug(node->ocs,
139331766Sken				"[%s] delete (target)    WWPN %s WWNN %s\n",
140331766Sken				node->display_name, node->wwpn, node->wwnn);
141331766Sken			ocs_node_transition(node, __ocs_d_wait_del_node, NULL);
142331766Sken			if (node->sport->enable_ini) {
143331766Sken				rc = ocs_scsi_del_target(node,
144331766Sken						OCS_SCSI_TARGET_DELETED);
145331766Sken			}
146331766Sken			if (rc == OCS_SCSI_CALL_COMPLETE) {
147331766Sken				ocs_node_post_event(node,
148331766Sken					OCS_EVT_NODE_DEL_TGT_COMPLETE, NULL);
149331766Sken			}
150331766Sken		} else if (node->init && node->targ) {
151331766Sken			ocs_log_debug(node->ocs,
152331766Sken				"[%s] delete (initiator+target) WWPN %s WWNN %s\n",
153331766Sken				node->display_name, node->wwpn, node->wwnn);
154331766Sken			ocs_node_transition(node, __ocs_d_wait_del_ini_tgt, NULL);
155331766Sken			if (node->sport->enable_tgt) {
156331766Sken				rc = ocs_scsi_del_initiator(node,
157331766Sken						OCS_SCSI_INITIATOR_DELETED);
158331766Sken			}
159331766Sken			if (rc == OCS_SCSI_CALL_COMPLETE) {
160331766Sken				ocs_node_post_event(node,
161331766Sken					OCS_EVT_NODE_DEL_INI_COMPLETE, NULL);
162331766Sken			}
163331766Sken			rc = OCS_SCSI_CALL_COMPLETE; /* assume no wait needed */
164331766Sken			if (node->sport->enable_ini) {
165331766Sken				rc = ocs_scsi_del_target(node,
166331766Sken						OCS_SCSI_TARGET_DELETED);
167331766Sken			}
168331766Sken			if (rc == OCS_SCSI_CALL_COMPLETE) {
169331766Sken				ocs_node_post_event(node,
170331766Sken					OCS_EVT_NODE_DEL_TGT_COMPLETE, NULL);
171331766Sken			}
172331766Sken		}
173331766Sken
174331766Sken		/* we've initiated the upcalls as needed, now kick off the node
175331766Sken		 * detach to precipitate the aborting of outstanding exchanges
176331766Sken		 * associated with said node
177331766Sken		 *
178331766Sken		 * Beware: if we've made upcall(s), we've already transitioned
179331766Sken		 * to a new state by the time we execute this.
180331766Sken		 * TODO: consider doing this before the upcalls...
181331766Sken		 */
182331766Sken		if (node->attached) {
183331766Sken			/* issue hw node free; don't care if succeeds right away
184331766Sken			 * or sometime later, will check node->attached later in
185331766Sken			 * shutdown process
186331766Sken			 */
187331766Sken			rc = ocs_hw_node_detach(&ocs->hw, &node->rnode);
188331766Sken			if (node->rnode.free_group) {
189331766Sken				ocs_remote_node_group_free(node->node_group);
190331766Sken				node->node_group = NULL;
191331766Sken				node->rnode.free_group = FALSE;
192331766Sken			}
193331766Sken			if (rc != OCS_HW_RTN_SUCCESS &&
194331766Sken				rc != OCS_HW_RTN_SUCCESS_SYNC) {
195331766Sken				node_printf(node,
196331766Sken					"Failed freeing HW node, rc=%d\n", rc);
197331766Sken			}
198331766Sken		}
199331766Sken
200331766Sken		/* if neither initiator nor target, proceed to cleanup */
201331766Sken		if (!node->init && !node->targ){
202331766Sken			/*
203331766Sken			 * node has either been detached or is in the process
204331766Sken			 * of being detached, call common node's initiate
205331766Sken			 * cleanup function.
206331766Sken			 */
207331766Sken			ocs_node_initiate_cleanup(node);
208331766Sken		}
209331766Sken		break;
210331766Sken	}
211331766Sken	case OCS_EVT_ALL_CHILD_NODES_FREE:
212331766Sken		/* Ignore, this can happen if an ELS is aborted,
213331766Sken		 * while in a delay/retry state */
214331766Sken		break;
215331766Sken	default:
216331766Sken		__ocs_d_common(__func__, ctx, evt, arg);
217331766Sken		return NULL;
218331766Sken	}
219331766Sken	return NULL;
220331766Sken}
221331766Sken
222331766Sken/**
223331766Sken * @ingroup device_sm
224331766Sken * @brief Device node state machine: Common device event handler.
225331766Sken *
226331766Sken * <h3 class="desc">Description</h3>
227331766Sken * For device nodes, this event handler manages default and common events.
228331766Sken *
229331766Sken * @param funcname Function name text.
230331766Sken * @param ctx Remote node state machine context.
231331766Sken * @param evt Event to process.
232331766Sken * @param arg Per event optional argument.
233331766Sken *
234331766Sken * @return Returns NULL.
235331766Sken */
236331766Sken
237331766Skenstatic void *
238331766Sken__ocs_d_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
239331766Sken{
240331766Sken	ocs_node_t *node = NULL;
241331766Sken	ocs_t *ocs = NULL;
242331766Sken	ocs_assert(ctx, NULL);
243331766Sken	node = ctx->app;
244331766Sken	ocs_assert(node, NULL);
245331766Sken	ocs = node->ocs;
246331766Sken	ocs_assert(ocs, NULL);
247331766Sken
248331766Sken	switch(evt) {
249331766Sken
250331766Sken	/* Handle shutdown events */
251331766Sken	case OCS_EVT_SHUTDOWN:
252331766Sken		ocs_log_debug(ocs, "[%s] %-20s %-20s\n", node->display_name, funcname, ocs_sm_event_name(evt));
253331766Sken		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
254331766Sken		ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL);
255331766Sken		break;
256331766Sken	case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO:
257331766Sken		ocs_log_debug(ocs, "[%s] %-20s %-20s\n", node->display_name, funcname, ocs_sm_event_name(evt));
258331766Sken		node->shutdown_reason = OCS_NODE_SHUTDOWN_EXPLICIT_LOGO;
259331766Sken		ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL);
260331766Sken		break;
261331766Sken	case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO:
262331766Sken		ocs_log_debug(ocs, "[%s] %-20s %-20s\n", node->display_name, funcname, ocs_sm_event_name(evt));
263331766Sken		node->shutdown_reason = OCS_NODE_SHUTDOWN_IMPLICIT_LOGO;
264331766Sken		ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL);
265331766Sken		break;
266331766Sken
267331766Sken	default:
268331766Sken		/* call default event handler common to all nodes */
269331766Sken		__ocs_node_common(funcname, ctx, evt, arg);
270331766Sken		break;
271331766Sken	}
272331766Sken	return NULL;
273331766Sken}
274331766Sken
275331766Sken/**
276331766Sken * @ingroup device_sm
277331766Sken * @brief Device node state machine: Wait for a domain-attach completion in loop topology.
278331766Sken *
279331766Sken * <h3 class="desc">Description</h3>
280331766Sken * State waits for a domain-attached completion while in loop topology.
281331766Sken *
282331766Sken * @param ctx Remote node state machine context.
283331766Sken * @param evt Event to process.
284331766Sken * @param arg Per event optional argument.
285331766Sken *
286331766Sken * @return Returns NULL.
287331766Sken */
288331766Sken
289331766Skenvoid *
290331766Sken__ocs_d_wait_loop(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
291331766Sken{
292331766Sken	std_node_state_decl();
293331766Sken
294331766Sken	node_sm_trace();
295331766Sken
296331766Sken	switch(evt) {
297331766Sken	case OCS_EVT_ENTER:
298331766Sken		ocs_node_hold_frames(node);
299331766Sken		break;
300331766Sken
301331766Sken	case OCS_EVT_EXIT:
302331766Sken		ocs_node_accept_frames(node);
303331766Sken		break;
304331766Sken
305331766Sken	case OCS_EVT_DOMAIN_ATTACH_OK: {
306331766Sken		/* send PLOGI automatically if initiator */
307331766Sken		ocs_node_init_device(node, TRUE);
308331766Sken		break;
309331766Sken	}
310331766Sken	default:
311331766Sken		__ocs_d_common(__func__, ctx, evt, arg);
312331766Sken		return NULL;
313331766Sken	}
314331766Sken
315331766Sken	return NULL;
316331766Sken}
317331766Sken
318331766Sken
319331766Sken
320331766Sken
321331766Sken/**
322331766Sken * @ingroup device_sm
323331766Sken * @brief state: wait for node resume event
324331766Sken *
325331766Sken * State is entered when a node is in I+T mode and sends a delete initiator/target
326331766Sken * call to the target-server/initiator-client and needs to wait for that work to complete.
327331766Sken *
328331766Sken * @param ctx Remote node state machine context.
329331766Sken * @param evt Event to process.
330331766Sken * @param arg per event optional argument
331331766Sken *
332331766Sken * @return returns NULL
333331766Sken */
334331766Sken
335331766Skenvoid *
336331766Sken__ocs_d_wait_del_ini_tgt(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
337331766Sken{
338331766Sken	std_node_state_decl();
339331766Sken
340331766Sken	node_sm_trace();
341331766Sken
342331766Sken	switch(evt) {
343331766Sken	case OCS_EVT_ENTER:
344331766Sken		ocs_node_hold_frames(node);
345331766Sken		/* Fall through */
346331766Sken
347331766Sken	case OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
348331766Sken	case OCS_EVT_ALL_CHILD_NODES_FREE:
349331766Sken		/* These are expected events. */
350331766Sken		break;
351331766Sken
352331766Sken	case OCS_EVT_NODE_DEL_INI_COMPLETE:
353331766Sken	case OCS_EVT_NODE_DEL_TGT_COMPLETE:
354331766Sken		ocs_node_transition(node, __ocs_d_wait_del_node, NULL);
355331766Sken		break;
356331766Sken
357331766Sken	case OCS_EVT_EXIT:
358331766Sken		ocs_node_accept_frames(node);
359331766Sken		break;
360331766Sken
361331766Sken	case OCS_EVT_SRRS_ELS_REQ_FAIL:
362331766Sken		/* Can happen as ELS IO IO's complete */
363331766Sken		ocs_assert(node->els_req_cnt, NULL);
364331766Sken		node->els_req_cnt--;
365331766Sken		break;
366331766Sken
367331766Sken	/* ignore shutdown events as we're already in shutdown path */
368331766Sken	case OCS_EVT_SHUTDOWN:
369331766Sken		/* have default shutdown event take precedence */
370331766Sken		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
371331766Sken		/* fall through */
372331766Sken	case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO:
373331766Sken	case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO:
374331766Sken		node_printf(node, "%s received\n", ocs_sm_event_name(evt));
375331766Sken		break;
376331766Sken	case OCS_EVT_DOMAIN_ATTACH_OK:
377331766Sken		/* don't care about domain_attach_ok */
378331766Sken		break;
379331766Sken	default:
380331766Sken		__ocs_d_common(__func__, ctx, evt, arg);
381331766Sken		return NULL;
382331766Sken	}
383331766Sken
384331766Sken	return NULL;
385331766Sken}
386331766Sken
387331766Sken
388331766Sken/**
389331766Sken * @ingroup device_sm
390331766Sken * @brief state: Wait for node resume event.
391331766Sken *
392331766Sken * State is entered when a node sends a delete initiator/target call to the
393331766Sken * target-server/initiator-client and needs to wait for that work to complete.
394331766Sken *
395331766Sken * @param ctx Remote node state machine context.
396331766Sken * @param evt Event to process.
397331766Sken * @param arg Per event optional argument.
398331766Sken *
399331766Sken * @return Returns NULL.
400331766Sken */
401331766Sken
402331766Skenvoid *
403331766Sken__ocs_d_wait_del_node(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
404331766Sken{
405331766Sken	std_node_state_decl();
406331766Sken
407331766Sken	node_sm_trace();
408331766Sken
409331766Sken	switch(evt) {
410331766Sken	case OCS_EVT_ENTER:
411331766Sken		ocs_node_hold_frames(node);
412331766Sken		/* Fall through */
413331766Sken
414331766Sken	case OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
415331766Sken	case OCS_EVT_ALL_CHILD_NODES_FREE:
416331766Sken		/* These are expected events. */
417331766Sken		break;
418331766Sken
419331766Sken	case OCS_EVT_NODE_DEL_INI_COMPLETE:
420331766Sken	case OCS_EVT_NODE_DEL_TGT_COMPLETE:
421331766Sken		/*
422331766Sken		 * node has either been detached or is in the process of being detached,
423331766Sken		 * call common node's initiate cleanup function
424331766Sken		 */
425331766Sken		ocs_node_initiate_cleanup(node);
426331766Sken		break;
427331766Sken
428331766Sken	case OCS_EVT_EXIT:
429331766Sken		ocs_node_accept_frames(node);
430331766Sken		break;
431331766Sken
432331766Sken	case OCS_EVT_SRRS_ELS_REQ_FAIL:
433331766Sken		/* Can happen as ELS IO IO's complete */
434331766Sken		ocs_assert(node->els_req_cnt, NULL);
435331766Sken		node->els_req_cnt--;
436331766Sken		break;
437331766Sken
438331766Sken	/* ignore shutdown events as we're already in shutdown path */
439331766Sken	case OCS_EVT_SHUTDOWN:
440331766Sken		/* have default shutdown event take precedence */
441331766Sken		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
442331766Sken		/* fall through */
443331766Sken	case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO:
444331766Sken	case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO:
445331766Sken		node_printf(node, "%s received\n", ocs_sm_event_name(evt));
446331766Sken		break;
447331766Sken	case OCS_EVT_DOMAIN_ATTACH_OK:
448331766Sken		/* don't care about domain_attach_ok */
449331766Sken		break;
450331766Sken	default:
451331766Sken		__ocs_d_common(__func__, ctx, evt, arg);
452331766Sken		return NULL;
453331766Sken	}
454331766Sken
455331766Sken	return NULL;
456331766Sken}
457331766Sken
458331766Sken
459331766Sken
460331766Sken/**
461331766Sken * @brief Save the OX_ID for sending LS_ACC sometime later.
462331766Sken *
463331766Sken * <h3 class="desc">Description</h3>
464331766Sken * When deferring the response to an ELS request, the OX_ID of the request
465331766Sken * is saved using this function.
466331766Sken *
467331766Sken * @param io Pointer to a SCSI IO object.
468331766Sken * @param hdr Pointer to the FC header.
469331766Sken * @param ls Defines the type of ELS to send: LS_ACC, LS_ACC for PLOGI;
470331766Sken * or LSS_ACC for PRLI.
471331766Sken *
472331766Sken * @return None.
473331766Sken */
474331766Sken
475331766Skenvoid
476331766Skenocs_send_ls_acc_after_attach(ocs_io_t *io, fc_header_t *hdr, ocs_node_send_ls_acc_e ls)
477331766Sken{
478331766Sken	ocs_node_t *node = io->node;
479331766Sken	uint16_t ox_id = ocs_be16toh(hdr->ox_id);
480331766Sken
481331766Sken	ocs_assert(node->send_ls_acc == OCS_NODE_SEND_LS_ACC_NONE);
482331766Sken
483331766Sken	node->ls_acc_oxid = ox_id;
484331766Sken	node->send_ls_acc = ls;
485331766Sken	node->ls_acc_io = io;
486331766Sken	node->ls_acc_did = fc_be24toh(hdr->d_id);
487331766Sken}
488331766Sken
489331766Sken/**
490331766Sken * @brief Process the PRLI payload.
491331766Sken *
492331766Sken * <h3 class="desc">Description</h3>
493331766Sken * The PRLI payload is processed; the initiator/target capabilities of the
494331766Sken * remote node are extracted and saved in the node object.
495331766Sken *
496331766Sken * @param node Pointer to the node object.
497331766Sken * @param prli Pointer to the PRLI payload.
498331766Sken *
499331766Sken * @return None.
500331766Sken */
501331766Sken
502331766Skenvoid
503331766Skenocs_process_prli_payload(ocs_node_t *node, fc_prli_payload_t *prli)
504331766Sken{
505331766Sken	node->init = (ocs_be16toh(prli->service_params) & FC_PRLI_INITIATOR_FUNCTION) != 0;
506331766Sken	node->targ = (ocs_be16toh(prli->service_params) & FC_PRLI_TARGET_FUNCTION) != 0;
507331766Sken	node->fcp2device = (ocs_be16toh(prli->service_params) & FC_PRLI_RETRY) != 0;
508331766Sken	node->fc_type = prli->type;
509331766Sken}
510331766Sken
511331766Sken/**
512331766Sken * @brief Process the ABTS.
513331766Sken *
514331766Sken * <h3 class="desc">Description</h3>
515331766Sken * Common code to process a received ABTS. If an active IO can be found
516331766Sken * that matches the OX_ID of the ABTS request, a call is made to the
517331766Sken * backend. Otherwise, a BA_ACC is returned to the initiator.
518331766Sken *
519331766Sken * @param io Pointer to a SCSI IO object.
520331766Sken * @param hdr Pointer to the FC header.
521331766Sken *
522331766Sken * @return Returns 0 on success, or a negative error value on failure.
523331766Sken */
524331766Sken
525331766Skenstatic int32_t
526331766Skenocs_process_abts(ocs_io_t *io, fc_header_t *hdr)
527331766Sken{
528331766Sken	ocs_node_t *node = io->node;
529331766Sken	ocs_t *ocs = node->ocs;
530331766Sken	uint16_t ox_id = ocs_be16toh(hdr->ox_id);
531331766Sken	uint16_t rx_id = ocs_be16toh(hdr->rx_id);
532331766Sken	ocs_io_t *abortio;
533331766Sken
534331766Sken	abortio = ocs_io_find_tgt_io(ocs, node, ox_id, rx_id);
535331766Sken
536331766Sken	/* If an IO was found, attempt to take a reference on it */
537331766Sken	if (abortio != NULL && (ocs_ref_get_unless_zero(&abortio->ref) != 0)) {
538331766Sken
539331766Sken		/* Got a reference on the IO. Hold it until backend is notified below */
540331766Sken		node_printf(node, "Abort request: ox_id [%04x] rx_id [%04x]\n",
541331766Sken			    ox_id, rx_id);
542331766Sken
543331766Sken		/*
544331766Sken		 * Save the ox_id for the ABTS as the init_task_tag in our manufactured
545331766Sken		 * TMF IO object
546331766Sken		 */
547331766Sken		io->display_name = "abts";
548331766Sken		io->init_task_tag = ox_id;
549331766Sken		/* don't set tgt_task_tag, don't want to confuse with XRI */
550331766Sken
551331766Sken		/*
552331766Sken		 * Save the rx_id from the ABTS as it is needed for the BLS response,
553331766Sken		 * regardless of the IO context's rx_id
554331766Sken		 */
555331766Sken		io->abort_rx_id = rx_id;
556331766Sken
557331766Sken		/* Call target server command abort */
558331766Sken		io->tmf_cmd = OCS_SCSI_TMF_ABORT_TASK;
559331766Sken		ocs_scsi_recv_tmf(io, abortio->tgt_io.lun, OCS_SCSI_TMF_ABORT_TASK, abortio, 0);
560331766Sken
561331766Sken		/*
562331766Sken		 * Backend will have taken an additional reference on the IO if needed;
563331766Sken		 * done with current reference.
564331766Sken		 */
565331766Sken		ocs_ref_put(&abortio->ref); /* ocs_ref_get(): same function */
566331766Sken	} else {
567331766Sken		/*
568331766Sken		 * Either IO was not found or it has been freed between finding it
569331766Sken		 * and attempting to get the reference,
570331766Sken		 */
571331766Sken		node_printf(node, "Abort request: ox_id [%04x], IO not found (exists=%d)\n",
572331766Sken			    ox_id, (abortio != NULL));
573331766Sken
574331766Sken		/* Send a BA_ACC */
575331766Sken		ocs_bls_send_acc_hdr(io, hdr);
576331766Sken	}
577331766Sken	return 0;
578331766Sken}
579331766Sken
580331766Sken/**
581331766Sken * @ingroup device_sm
582331766Sken * @brief Device node state machine: Wait for the PLOGI accept to complete.
583331766Sken *
584331766Sken * @param ctx Remote node state machine context.
585331766Sken * @param evt Event to process.
586331766Sken * @param arg Per event optional argument.
587331766Sken *
588331766Sken * @return Returns NULL.
589331766Sken */
590331766Sken
591331766Skenvoid *
592331766Sken__ocs_d_wait_plogi_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
593331766Sken{
594331766Sken	std_node_state_decl();
595331766Sken
596331766Sken	node_sm_trace();
597331766Sken
598331766Sken	switch(evt) {
599331766Sken	case OCS_EVT_ENTER:
600331766Sken		ocs_node_hold_frames(node);
601331766Sken		break;
602331766Sken
603331766Sken	case OCS_EVT_EXIT:
604331766Sken		ocs_node_accept_frames(node);
605331766Sken		break;
606331766Sken
607331766Sken	case OCS_EVT_SRRS_ELS_CMPL_FAIL:
608331766Sken		ocs_assert(node->els_cmpl_cnt, NULL);
609331766Sken		node->els_cmpl_cnt--;
610331766Sken		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
611331766Sken		ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL);
612331766Sken		break;
613331766Sken
614331766Sken	case OCS_EVT_SRRS_ELS_CMPL_OK:	/* PLOGI ACC completions */
615331766Sken		ocs_assert(node->els_cmpl_cnt, NULL);
616331766Sken		node->els_cmpl_cnt--;
617331766Sken		ocs_node_transition(node, __ocs_d_port_logged_in, NULL);
618331766Sken		break;
619331766Sken
620331766Sken	default:
621331766Sken		__ocs_d_common(__func__, ctx, evt, arg);
622331766Sken		return NULL;
623331766Sken	}
624331766Sken
625331766Sken	return NULL;
626331766Sken}
627331766Sken
628331766Sken/**
629331766Sken * @ingroup device_sm
630331766Sken * @brief Device node state machine: Wait for the LOGO response.
631331766Sken *
632331766Sken * @param ctx Remote node state machine context.
633331766Sken * @param evt Event to process.
634331766Sken * @param arg Per event optional argument.
635331766Sken *
636331766Sken * @return Returns NULL.
637331766Sken */
638331766Sken
639331766Skenvoid *
640331766Sken__ocs_d_wait_logo_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
641331766Sken{
642331766Sken	std_node_state_decl();
643331766Sken
644331766Sken	node_sm_trace();
645331766Sken
646331766Sken	switch(evt) {
647331766Sken	case OCS_EVT_ENTER:
648331766Sken		/* TODO: may want to remove this;
649331766Sken		 * if we'll want to know about PLOGI */
650331766Sken		ocs_node_hold_frames(node);
651331766Sken		break;
652331766Sken
653331766Sken	case OCS_EVT_EXIT:
654331766Sken		ocs_node_accept_frames(node);
655331766Sken		break;
656331766Sken
657331766Sken	case OCS_EVT_SRRS_ELS_REQ_OK:
658331766Sken	case OCS_EVT_SRRS_ELS_REQ_RJT:
659331766Sken	case OCS_EVT_SRRS_ELS_REQ_FAIL:
660331766Sken		/* LOGO response received, sent shutdown */
661331766Sken		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_LOGO, __ocs_d_common, __func__)) {
662331766Sken			return NULL;
663331766Sken		}
664331766Sken		ocs_assert(node->els_req_cnt, NULL);
665331766Sken		node->els_req_cnt--;
666331766Sken		node_printf(node, "LOGO sent (evt=%s), shutdown node\n", ocs_sm_event_name(evt));
667331766Sken		/* sm: post explicit logout */
668331766Sken		ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
669331766Sken		break;
670331766Sken
671331766Sken	/* TODO: PLOGI: abort LOGO and process PLOGI? (SHUTDOWN_EXPLICIT/IMPLICIT_LOGO?) */
672331766Sken
673331766Sken	default:
674331766Sken		__ocs_d_common(__func__, ctx, evt, arg);
675331766Sken		return NULL;
676331766Sken	}
677331766Sken	return NULL;
678331766Sken}
679331766Sken
680331766Sken
681331766Sken/**
682331766Sken * @ingroup device_sm
683331766Sken * @brief Device node state machine: Wait for the PRLO response.
684331766Sken *
685331766Sken * @param ctx Remote node state machine context.
686331766Sken * @param evt Event to process.
687331766Sken * @param arg Per event optional argument.
688331766Sken *
689331766Sken * @return Returns NULL.
690331766Sken */
691331766Sken
692331766Skenvoid *
693331766Sken__ocs_d_wait_prlo_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
694331766Sken{
695331766Sken	std_node_state_decl();
696331766Sken
697331766Sken	node_sm_trace();
698331766Sken
699331766Sken	switch(evt) {
700331766Sken		case OCS_EVT_ENTER:
701331766Sken			ocs_node_hold_frames(node);
702331766Sken			break;
703331766Sken
704331766Sken		case OCS_EVT_EXIT:
705331766Sken			ocs_node_accept_frames(node);
706331766Sken			break;
707331766Sken
708331766Sken		case OCS_EVT_SRRS_ELS_REQ_OK:
709331766Sken		case OCS_EVT_SRRS_ELS_REQ_RJT:
710331766Sken		case OCS_EVT_SRRS_ELS_REQ_FAIL:
711331766Sken			if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PRLO, __ocs_d_common, __func__)) {
712331766Sken				return NULL;
713331766Sken			}
714331766Sken			ocs_assert(node->els_req_cnt, NULL);
715331766Sken			node->els_req_cnt--;
716331766Sken			node_printf(node, "PRLO sent (evt=%s)\n", ocs_sm_event_name(evt));
717331766Sken			ocs_node_transition(node, __ocs_d_port_logged_in, NULL);
718331766Sken			break;
719331766Sken
720331766Sken		default:
721331766Sken			__ocs_node_common(__func__, ctx, evt, arg);
722331766Sken			return NULL;
723331766Sken	}
724331766Sken	return NULL;
725331766Sken}
726331766Sken
727331766Sken
728331766Sken/**
729331766Sken * @brief Initialize device node.
730331766Sken *
731331766Sken * Initialize device node. If a node is an initiator, then send a PLOGI and transition
732331766Sken * to __ocs_d_wait_plogi_rsp, otherwise transition to __ocs_d_init.
733331766Sken *
734331766Sken * @param node Pointer to the node object.
735331766Sken * @param send_plogi Boolean indicating to send PLOGI command or not.
736331766Sken *
737331766Sken * @return none
738331766Sken */
739331766Sken
740331766Skenvoid
741331766Skenocs_node_init_device(ocs_node_t *node, int send_plogi)
742331766Sken{
743331766Sken	node->send_plogi = send_plogi;
744331766Sken	if ((node->ocs->nodedb_mask & OCS_NODEDB_PAUSE_NEW_NODES) && !FC_ADDR_IS_DOMAIN_CTRL(node->rnode.fc_id)) {
745331766Sken		node->nodedb_state = __ocs_d_init;
746331766Sken		ocs_node_transition(node, __ocs_node_paused, NULL);
747331766Sken	} else {
748331766Sken		ocs_node_transition(node, __ocs_d_init, NULL);
749331766Sken	}
750331766Sken}
751331766Sken
752331766Sken/**
753331766Sken * @ingroup device_sm
754331766Sken * @brief Device node state machine: Initial node state for an initiator or a target.
755331766Sken *
756331766Sken * <h3 class="desc">Description</h3>
757331766Sken * This state is entered when a node is instantiated, either having been
758331766Sken * discovered from a name services query, or having received a PLOGI/FLOGI.
759331766Sken *
760331766Sken * @param ctx Remote node state machine context.
761331766Sken * @param evt Event to process.
762331766Sken * @param arg Per event optional argument.
763331766Sken * - OCS_EVT_ENTER: (uint8_t *) - 1 to send a PLOGI on
764331766Sken * entry (initiator-only); 0 indicates a PLOGI is
765331766Sken * not sent on entry (initiator-only). Not applicable for a target.
766331766Sken *
767331766Sken * @return Returns NULL.
768331766Sken */
769331766Sken
770331766Skenvoid *
771331766Sken__ocs_d_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
772331766Sken{
773331766Sken	int32_t rc;
774331766Sken	ocs_node_cb_t *cbdata = arg;
775331766Sken	std_node_state_decl();
776331766Sken
777331766Sken	node_sm_trace();
778331766Sken
779331766Sken	switch(evt) {
780331766Sken	case OCS_EVT_ENTER:
781331766Sken		/* check if we need to send PLOGI */
782331766Sken		if (node->send_plogi) {
783331766Sken			/* only send if we have initiator capability, and domain is attached */
784331766Sken			if (node->sport->enable_ini && node->sport->domain->attached) {
785331766Sken				ocs_send_plogi(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT,
786331766Sken						OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL);
787331766Sken				ocs_node_transition(node, __ocs_d_wait_plogi_rsp, NULL);
788331766Sken			} else {
789331766Sken				node_printf(node, "not sending plogi sport.ini=%d, domain attached=%d\n",
790331766Sken					    node->sport->enable_ini, node->sport->domain->attached);
791331766Sken			}
792331766Sken		}
793331766Sken		break;
794331766Sken	case OCS_EVT_PLOGI_RCVD: {
795331766Sken		/* T, or I+T */
796331766Sken		fc_header_t *hdr = cbdata->header->dma.virt;
797331766Sken		uint32_t d_id = fc_be24toh(hdr->d_id);
798331766Sken
799331766Sken		ocs_node_save_sparms(node, cbdata->payload->dma.virt);
800331766Sken		ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PLOGI);
801331766Sken
802331766Sken		/* domain already attached */
803331766Sken		if (node->sport->domain->attached) {
804331766Sken			rc = ocs_node_attach(node);
805331766Sken			ocs_node_transition(node, __ocs_d_wait_node_attach, NULL);
806331766Sken			if (rc == OCS_HW_RTN_SUCCESS_SYNC) {
807331766Sken				ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL);
808331766Sken			}
809331766Sken			break;
810331766Sken		}
811331766Sken
812331766Sken		/* domain not attached; several possibilities: */
813331766Sken		switch (node->sport->topology) {
814331766Sken		case OCS_SPORT_TOPOLOGY_P2P:
815331766Sken			/* we're not attached and sport is p2p, need to attach */
816331766Sken			ocs_domain_attach(node->sport->domain, d_id);
817331766Sken			ocs_node_transition(node, __ocs_d_wait_domain_attach, NULL);
818331766Sken			break;
819331766Sken		case OCS_SPORT_TOPOLOGY_FABRIC:
820331766Sken			/* we're not attached and sport is fabric, domain attach should have
821331766Sken			 * already been requested as part of the fabric state machine, wait for it
822331766Sken			 */
823331766Sken			ocs_node_transition(node, __ocs_d_wait_domain_attach, NULL);
824331766Sken			break;
825331766Sken		case OCS_SPORT_TOPOLOGY_UNKNOWN:
826331766Sken			/* Two possibilities:
827331766Sken			 * 1. received a PLOGI before our FLOGI has completed (possible since
828331766Sken			 *    completion comes in on another CQ), thus we don't know what we're
829331766Sken			 *    connected to yet; transition to a state to wait for the fabric
830331766Sken			 *    node to tell us;
831331766Sken			 * 2. PLOGI received before link went down and we haven't performed
832331766Sken			 *    domain attach yet.
833331766Sken			 * Note: we cannot distinguish between 1. and 2. so have to assume PLOGI
834331766Sken			 * was received after link back up.
835331766Sken			 */
836331766Sken			node_printf(node, "received PLOGI, with unknown topology did=0x%x\n", d_id);
837331766Sken			ocs_node_transition(node, __ocs_d_wait_topology_notify, NULL);
838331766Sken			break;
839331766Sken		default:
840331766Sken			node_printf(node, "received PLOGI, with unexpectd topology %d\n",
841331766Sken				    node->sport->topology);
842331766Sken			ocs_assert(FALSE, NULL);
843331766Sken			break;
844331766Sken		}
845331766Sken		break;
846331766Sken	}
847331766Sken
848331766Sken	case OCS_EVT_FDISC_RCVD: {
849331766Sken		__ocs_d_common(__func__, ctx, evt, arg);
850331766Sken		break;
851331766Sken	}
852331766Sken
853331766Sken	case OCS_EVT_FLOGI_RCVD: {
854331766Sken		fc_header_t *hdr = cbdata->header->dma.virt;
855331766Sken
856331766Sken		/* this better be coming from an NPort */
857331766Sken		ocs_assert(ocs_rnode_is_nport(cbdata->payload->dma.virt), NULL);
858331766Sken
859331766Sken		/* sm: save sparams, send FLOGI acc */
860331766Sken		ocs_domain_save_sparms(node->sport->domain, cbdata->payload->dma.virt);
861331766Sken
862331766Sken		/* send FC LS_ACC response, override s_id */
863331766Sken		ocs_fabric_set_topology(node, OCS_SPORT_TOPOLOGY_P2P);
864331766Sken		ocs_send_flogi_p2p_acc(cbdata->io, ocs_be16toh(hdr->ox_id), fc_be24toh(hdr->d_id), NULL, NULL);
865331766Sken		if (ocs_p2p_setup(node->sport)) {
866331766Sken			node_printf(node, "p2p setup failed, shutting down node\n");
867331766Sken			ocs_node_post_event(node, OCS_EVT_SHUTDOWN, NULL);
868331766Sken		} else {
869331766Sken			ocs_node_transition(node, __ocs_p2p_wait_flogi_acc_cmpl, NULL);
870331766Sken		}
871331766Sken
872331766Sken		break;
873331766Sken	}
874331766Sken
875331766Sken	case OCS_EVT_LOGO_RCVD: {
876331766Sken		fc_header_t *hdr = cbdata->header->dma.virt;
877331766Sken
878331766Sken		if (!node->sport->domain->attached) {
879331766Sken			 /* most likely a frame left over from before a link down; drop and
880331766Sken			  * shut node down w/ "explicit logout" so pending frames are processed */
881331766Sken			node_printf(node, "%s domain not attached, dropping\n", ocs_sm_event_name(evt));
882331766Sken			ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
883331766Sken			break;
884331766Sken		}
885331766Sken		ocs_send_logo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
886331766Sken		ocs_node_transition(node, __ocs_d_wait_logo_acc_cmpl, NULL);
887331766Sken		break;
888331766Sken	}
889331766Sken
890331766Sken	case OCS_EVT_PRLI_RCVD:
891331766Sken	case OCS_EVT_PRLO_RCVD:
892331766Sken	case OCS_EVT_PDISC_RCVD:
893331766Sken	case OCS_EVT_ADISC_RCVD:
894331766Sken	case OCS_EVT_RSCN_RCVD: {
895331766Sken		fc_header_t *hdr = cbdata->header->dma.virt;
896331766Sken		if (!node->sport->domain->attached) {
897331766Sken			 /* most likely a frame left over from before a link down; drop and
898331766Sken			  * shut node down w/ "explicit logout" so pending frames are processed */
899331766Sken			node_printf(node, "%s domain not attached, dropping\n", ocs_sm_event_name(evt));
900331766Sken			ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
901331766Sken			break;
902331766Sken		}
903331766Sken		node_printf(node, "%s received, sending reject\n", ocs_sm_event_name(evt));
904331766Sken		ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id),
905331766Sken			FC_REASON_UNABLE_TO_PERFORM, FC_EXPL_NPORT_LOGIN_REQUIRED, 0,
906331766Sken			NULL, NULL);
907331766Sken
908331766Sken		break;
909331766Sken	}
910331766Sken
911331766Sken	case OCS_EVT_FCP_CMD_RCVD: {
912331766Sken		/* note: problem, we're now expecting an ELS REQ completion
913331766Sken		 * from both the LOGO and PLOGI */
914331766Sken		if (!node->sport->domain->attached) {
915331766Sken			 /* most likely a frame left over from before a link down; drop and
916331766Sken			  * shut node down w/ "explicit logout" so pending frames are processed */
917331766Sken			node_printf(node, "%s domain not attached, dropping\n", ocs_sm_event_name(evt));
918331766Sken			ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
919331766Sken			break;
920331766Sken		}
921331766Sken
922331766Sken		/* Send LOGO */
923331766Sken		node_printf(node, "FCP_CMND received, send LOGO\n");
924331766Sken		if (ocs_send_logo(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, 0, NULL, NULL) == NULL) {
925331766Sken			/* failed to send LOGO, go ahead and cleanup node anyways */
926331766Sken			node_printf(node, "Failed to send LOGO\n");
927331766Sken			ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
928331766Sken		} else {
929331766Sken			/* sent LOGO, wait for response */
930331766Sken			ocs_node_transition(node, __ocs_d_wait_logo_rsp, NULL);
931331766Sken		}
932331766Sken		break;
933331766Sken	}
934331766Sken	case OCS_EVT_DOMAIN_ATTACH_OK:
935331766Sken		/* don't care about domain_attach_ok */
936331766Sken		break;
937331766Sken
938331766Sken	default:
939331766Sken		__ocs_d_common(__func__, ctx, evt, arg);
940331766Sken		return NULL;
941331766Sken	}
942331766Sken
943331766Sken	return NULL;
944331766Sken}
945331766Sken
946331766Sken/**
947331766Sken * @ingroup device_sm
948331766Sken * @brief Device node state machine: Wait on a response for a sent PLOGI.
949331766Sken *
950331766Sken * <h3 class="desc">Description</h3>
951331766Sken * State is entered when an initiator-capable node has sent
952331766Sken * a PLOGI and is waiting for a response.
953331766Sken *
954331766Sken * @param ctx Remote node state machine context.
955331766Sken * @param evt Event to process.
956331766Sken * @param arg Per event optional argument.
957331766Sken *
958331766Sken * @return Returns NULL.
959331766Sken */
960331766Sken
961331766Skenvoid *
962331766Sken__ocs_d_wait_plogi_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
963331766Sken{
964331766Sken	int32_t rc;
965331766Sken	ocs_node_cb_t *cbdata = arg;
966331766Sken	std_node_state_decl();
967331766Sken
968331766Sken	node_sm_trace();
969331766Sken
970331766Sken	switch(evt) {
971331766Sken	case OCS_EVT_PLOGI_RCVD: {
972331766Sken		/* T, or I+T */
973331766Sken		/* received PLOGI with svc parms, go ahead and attach node
974331766Sken		 * when PLOGI that was sent ultimately completes, it'll be a no-op
975331766Sken		 */
976331766Sken
977331766Sken		/* TODO: there is an outstanding PLOGI sent, can we set a flag
978331766Sken		 * to indicate that we don't want to retry it if it times out? */
979331766Sken		ocs_node_save_sparms(node, cbdata->payload->dma.virt);
980331766Sken		ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PLOGI);
981331766Sken		/* sm: domain->attached / ocs_node_attach */
982331766Sken		rc = ocs_node_attach(node);
983331766Sken		ocs_node_transition(node, __ocs_d_wait_node_attach, NULL);
984331766Sken		if (rc == OCS_HW_RTN_SUCCESS_SYNC) {
985331766Sken			ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL);
986331766Sken		}
987331766Sken		break;
988331766Sken	}
989331766Sken
990331766Sken	case OCS_EVT_PRLI_RCVD:
991331766Sken		/* I, or I+T */
992331766Sken		/* sent PLOGI and before completion was seen, received the
993331766Sken		 * PRLI from the remote node (WCQEs and RCQEs come in on
994331766Sken		 * different queues and order of processing cannot be assumed)
995331766Sken		 * Save OXID so PRLI can be sent after the attach and continue
996331766Sken		 * to wait for PLOGI response
997331766Sken		 */
998331766Sken		ocs_process_prli_payload(node, cbdata->payload->dma.virt);
999331766Sken		if (ocs->fc_type == node->fc_type) {
1000331766Sken			ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PRLI);
1001331766Sken			ocs_node_transition(node, __ocs_d_wait_plogi_rsp_recvd_prli, NULL);
1002331766Sken		} else {
1003331766Sken			/* TODO this need to be looked at. What do we do here ? */
1004331766Sken		}
1005331766Sken		break;
1006331766Sken
1007331766Sken	/* TODO this need to be looked at. we could very well be logged in */
1008331766Sken	case OCS_EVT_LOGO_RCVD: /* why don't we do a shutdown here?? */
1009331766Sken	case OCS_EVT_PRLO_RCVD:
1010331766Sken	case OCS_EVT_PDISC_RCVD:
1011331766Sken	case OCS_EVT_FDISC_RCVD:
1012331766Sken	case OCS_EVT_ADISC_RCVD:
1013331766Sken	case OCS_EVT_RSCN_RCVD:
1014331766Sken	case OCS_EVT_SCR_RCVD: {
1015331766Sken		fc_header_t *hdr = cbdata->header->dma.virt;
1016331766Sken		node_printf(node, "%s received, sending reject\n", ocs_sm_event_name(evt));
1017331766Sken		ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id),
1018331766Sken			FC_REASON_UNABLE_TO_PERFORM, FC_EXPL_NPORT_LOGIN_REQUIRED, 0,
1019331766Sken			NULL, NULL);
1020331766Sken
1021331766Sken		break;
1022331766Sken	}
1023331766Sken
1024331766Sken	case OCS_EVT_SRRS_ELS_REQ_OK:	/* PLOGI response received */
1025331766Sken		/* Completion from PLOGI sent */
1026331766Sken		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_d_common, __func__)) {
1027331766Sken			return NULL;
1028331766Sken		}
1029331766Sken		ocs_assert(node->els_req_cnt, NULL);
1030331766Sken		node->els_req_cnt--;
1031331766Sken		/* sm:  save sparams, ocs_node_attach */
1032331766Sken		ocs_node_save_sparms(node, cbdata->els->els_rsp.virt);
1033331766Sken		ocs_display_sparams(node->display_name, "plogi rcvd resp", 0, NULL,
1034331766Sken			((uint8_t*)cbdata->els->els_rsp.virt) + 4);
1035331766Sken		rc = ocs_node_attach(node);
1036331766Sken		ocs_node_transition(node, __ocs_d_wait_node_attach, NULL);
1037331766Sken		if (rc == OCS_HW_RTN_SUCCESS_SYNC) {
1038331766Sken			ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL);
1039331766Sken		}
1040331766Sken		break;
1041331766Sken
1042331766Sken	case OCS_EVT_SRRS_ELS_REQ_FAIL:	/* PLOGI response received */
1043331766Sken		/* PLOGI failed, shutdown the node */
1044331766Sken		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_d_common, __func__)) {
1045331766Sken			return NULL;
1046331766Sken		}
1047331766Sken		ocs_assert(node->els_req_cnt, NULL);
1048331766Sken		node->els_req_cnt--;
1049331766Sken		ocs_node_post_event(node, OCS_EVT_SHUTDOWN, NULL);
1050331766Sken		break;
1051331766Sken
1052331766Sken	case OCS_EVT_SRRS_ELS_REQ_RJT:	/* Our PLOGI was rejected, this is ok in some cases */
1053331766Sken		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_d_common, __func__)) {
1054331766Sken			return NULL;
1055331766Sken		}
1056331766Sken		ocs_assert(node->els_req_cnt, NULL);
1057331766Sken		node->els_req_cnt--;
1058331766Sken		break;
1059331766Sken
1060331766Sken	case OCS_EVT_FCP_CMD_RCVD: {
1061331766Sken		/* not logged in yet and outstanding PLOGI so don't send LOGO,
1062331766Sken		 * just drop
1063331766Sken		 */
1064331766Sken		node_printf(node, "FCP_CMND received, drop\n");
1065331766Sken		break;
1066331766Sken	}
1067331766Sken
1068331766Sken	default:
1069331766Sken		__ocs_d_common(__func__, ctx, evt, arg);
1070331766Sken		return NULL;
1071331766Sken	}
1072331766Sken
1073331766Sken	return NULL;
1074331766Sken}
1075331766Sken
1076331766Sken/**
1077331766Sken * @ingroup device_sm
1078331766Sken * @brief Device node state machine: Waiting on a response for a
1079331766Sken *	sent PLOGI.
1080331766Sken *
1081331766Sken * <h3 class="desc">Description</h3>
1082331766Sken * State is entered when an initiator-capable node has sent
1083331766Sken * a PLOGI and is waiting for a response. Before receiving the
1084331766Sken * response, a PRLI was received, implying that the PLOGI was
1085331766Sken * successful.
1086331766Sken *
1087331766Sken * @param ctx Remote node state machine context.
1088331766Sken * @param evt Event to process.
1089331766Sken * @param arg Per event optional argument.
1090331766Sken *
1091331766Sken * @return Returns NULL.
1092331766Sken */
1093331766Sken
1094331766Skenvoid *
1095331766Sken__ocs_d_wait_plogi_rsp_recvd_prli(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1096331766Sken{
1097331766Sken	int32_t rc;
1098331766Sken	ocs_node_cb_t *cbdata = arg;
1099331766Sken	std_node_state_decl();
1100331766Sken
1101331766Sken	node_sm_trace();
1102331766Sken
1103331766Sken	switch(evt) {
1104331766Sken	case OCS_EVT_ENTER:
1105331766Sken		/*
1106331766Sken		 * Since we've received a PRLI, we have a port login and will
1107331766Sken		 * just need to wait for the PLOGI response to do the node
1108331766Sken		 * attach and then we can send the LS_ACC for the PRLI. If,
1109331766Sken		 * during this time, we receive FCP_CMNDs (which is possible
1110331766Sken		 * since we've already sent a PRLI and our peer may have accepted).
1111331766Sken		 * At this time, we are not waiting on any other unsolicited
1112331766Sken		 * frames to continue with the login process. Thus, it will not
1113331766Sken		 * hurt to hold frames here.
1114331766Sken		 */
1115331766Sken		ocs_node_hold_frames(node);
1116331766Sken		break;
1117331766Sken
1118331766Sken	case OCS_EVT_EXIT:
1119331766Sken		ocs_node_accept_frames(node);
1120331766Sken		break;
1121331766Sken
1122331766Sken	case OCS_EVT_SRRS_ELS_REQ_OK:	/* PLOGI response received */
1123331766Sken		/* Completion from PLOGI sent */
1124331766Sken		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_d_common, __func__)) {
1125331766Sken			return NULL;
1126331766Sken		}
1127331766Sken		ocs_assert(node->els_req_cnt, NULL);
1128331766Sken		node->els_req_cnt--;
1129331766Sken		/* sm:  save sparams, ocs_node_attach */
1130331766Sken		ocs_node_save_sparms(node, cbdata->els->els_rsp.virt);
1131331766Sken		ocs_display_sparams(node->display_name, "plogi rcvd resp", 0, NULL,
1132331766Sken			((uint8_t*)cbdata->els->els_rsp.virt) + 4);
1133331766Sken		rc = ocs_node_attach(node);
1134331766Sken		ocs_node_transition(node, __ocs_d_wait_node_attach, NULL);
1135331766Sken		if (rc == OCS_HW_RTN_SUCCESS_SYNC) {
1136331766Sken			ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL);
1137331766Sken		}
1138331766Sken		break;
1139331766Sken
1140331766Sken	case OCS_EVT_SRRS_ELS_REQ_FAIL:	/* PLOGI response received */
1141331766Sken	case OCS_EVT_SRRS_ELS_REQ_RJT:
1142331766Sken		/* PLOGI failed, shutdown the node */
1143331766Sken		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_d_common, __func__)) {
1144331766Sken			return NULL;
1145331766Sken		}
1146331766Sken		ocs_assert(node->els_req_cnt, NULL);
1147331766Sken		node->els_req_cnt--;
1148331766Sken		ocs_node_post_event(node, OCS_EVT_SHUTDOWN, NULL);
1149331766Sken		break;
1150331766Sken
1151331766Sken	default:
1152331766Sken		__ocs_d_common(__func__, ctx, evt, arg);
1153331766Sken		return NULL;
1154331766Sken	}
1155331766Sken
1156331766Sken	return NULL;
1157331766Sken}
1158331766Sken
1159331766Sken/**
1160331766Sken * @ingroup device_sm
1161331766Sken * @brief Device node state machine: Wait for a domain attach.
1162331766Sken *
1163331766Sken * <h3 class="desc">Description</h3>
1164331766Sken * Waits for a domain-attach complete ok event.
1165331766Sken *
1166331766Sken * @param ctx Remote node state machine context.
1167331766Sken * @param evt Event to process.
1168331766Sken * @param arg Per event optional argument.
1169331766Sken *
1170331766Sken * @return Returns NULL.
1171331766Sken */
1172331766Sken
1173331766Skenvoid *
1174331766Sken__ocs_d_wait_domain_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1175331766Sken{
1176331766Sken	int32_t rc;
1177331766Sken	std_node_state_decl();
1178331766Sken
1179331766Sken	node_sm_trace();
1180331766Sken
1181331766Sken	switch(evt) {
1182331766Sken	case OCS_EVT_ENTER:
1183331766Sken		ocs_node_hold_frames(node);
1184331766Sken		break;
1185331766Sken
1186331766Sken	case OCS_EVT_EXIT:
1187331766Sken		ocs_node_accept_frames(node);
1188331766Sken		break;
1189331766Sken
1190331766Sken	case OCS_EVT_DOMAIN_ATTACH_OK:
1191331766Sken		ocs_assert(node->sport->domain->attached, NULL);
1192331766Sken		/* sm: ocs_node_attach */
1193331766Sken		rc = ocs_node_attach(node);
1194331766Sken		ocs_node_transition(node, __ocs_d_wait_node_attach, NULL);
1195331766Sken		if (rc == OCS_HW_RTN_SUCCESS_SYNC) {
1196331766Sken			ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL);
1197331766Sken		}
1198331766Sken		break;
1199331766Sken
1200331766Sken	default:
1201331766Sken		__ocs_d_common(__func__, ctx, evt, arg);
1202331766Sken		return NULL;
1203331766Sken	}
1204331766Sken	return NULL;
1205331766Sken}
1206331766Sken
1207331766Sken/**
1208331766Sken * @ingroup device_sm
1209331766Sken * @brief Device node state machine: Wait for topology
1210331766Sken *	notification
1211331766Sken *
1212331766Sken * <h3 class="desc">Description</h3>
1213331766Sken * Waits for topology notification from fabric node, then
1214331766Sken * attaches domain and node.
1215331766Sken *
1216331766Sken * @param ctx Remote node state machine context.
1217331766Sken * @param evt Event to process.
1218331766Sken * @param arg Per event optional argument.
1219331766Sken *
1220331766Sken * @return Returns NULL.
1221331766Sken */
1222331766Sken
1223331766Skenvoid *
1224331766Sken__ocs_d_wait_topology_notify(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1225331766Sken{
1226331766Sken	int32_t rc;
1227331766Sken	std_node_state_decl();
1228331766Sken
1229331766Sken	node_sm_trace();
1230331766Sken
1231331766Sken	switch(evt) {
1232331766Sken	case OCS_EVT_ENTER:
1233331766Sken		ocs_node_hold_frames(node);
1234331766Sken		break;
1235331766Sken
1236331766Sken	case OCS_EVT_EXIT:
1237331766Sken		ocs_node_accept_frames(node);
1238331766Sken		break;
1239331766Sken
1240331766Sken	case OCS_EVT_SPORT_TOPOLOGY_NOTIFY: {
1241360415Sbrooks		ocs_sport_topology_e topology = (ocs_sport_topology_e)(uintptr_t)arg;
1242331766Sken		ocs_assert(!node->sport->domain->attached, NULL);
1243331766Sken		ocs_assert(node->send_ls_acc == OCS_NODE_SEND_LS_ACC_PLOGI, NULL);
1244331766Sken		node_printf(node, "topology notification, topology=%d\n", topology);
1245331766Sken
1246331766Sken		/* At the time the PLOGI was received, the topology was unknown,
1247331766Sken		 * so we didn't know which node would perform the domain attach:
1248331766Sken		 * 1. The node from which the PLOGI was sent (p2p) or
1249331766Sken		 * 2. The node to which the FLOGI was sent (fabric).
1250331766Sken		 */
1251331766Sken		if (topology == OCS_SPORT_TOPOLOGY_P2P) {
1252331766Sken			/* if this is p2p, need to attach to the domain using the
1253331766Sken			 * d_id from the PLOGI received
1254331766Sken			 */
1255331766Sken			ocs_domain_attach(node->sport->domain, node->ls_acc_did);
1256331766Sken		}
1257331766Sken		/* else, if this is fabric, the domain attach should be performed
1258331766Sken		 * by the fabric node (node sending FLOGI); just wait for attach
1259331766Sken		 * to complete
1260331766Sken		 */
1261331766Sken
1262331766Sken		ocs_node_transition(node, __ocs_d_wait_domain_attach, NULL);
1263331766Sken		break;
1264331766Sken	}
1265331766Sken	case OCS_EVT_DOMAIN_ATTACH_OK:
1266331766Sken		ocs_assert(node->sport->domain->attached, NULL);
1267331766Sken		node_printf(node, "domain attach ok\n");
1268331766Sken		/*sm:  ocs_node_attach */
1269331766Sken		rc = ocs_node_attach(node);
1270331766Sken		ocs_node_transition(node, __ocs_d_wait_node_attach, NULL);
1271331766Sken		if (rc == OCS_HW_RTN_SUCCESS_SYNC) {
1272331766Sken			ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL);
1273331766Sken		}
1274331766Sken		break;
1275331766Sken
1276331766Sken	default:
1277331766Sken		__ocs_d_common(__func__, ctx, evt, arg);
1278331766Sken		return NULL;
1279331766Sken	}
1280331766Sken	return NULL;
1281331766Sken}
1282331766Sken
1283331766Sken/**
1284331766Sken * @ingroup device_sm
1285331766Sken * @brief Device node state machine: Wait for a node attach when found by a remote node.
1286331766Sken *
1287331766Sken * @param ctx Remote node state machine context.
1288331766Sken * @param evt Event to process.
1289331766Sken * @param arg Per event optional argument.
1290331766Sken *
1291331766Sken * @return Returns NULL.
1292331766Sken */
1293331766Sken
1294331766Skenvoid *
1295331766Sken__ocs_d_wait_node_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1296331766Sken{
1297331766Sken	std_node_state_decl();
1298331766Sken
1299331766Sken	node_sm_trace();
1300331766Sken
1301331766Sken	switch(evt) {
1302331766Sken	case OCS_EVT_ENTER:
1303331766Sken		ocs_node_hold_frames(node);
1304331766Sken		break;
1305331766Sken
1306331766Sken	case OCS_EVT_EXIT:
1307331766Sken		ocs_node_accept_frames(node);
1308331766Sken		break;
1309331766Sken
1310331766Sken	case OCS_EVT_NODE_ATTACH_OK:
1311331766Sken		node->attached = TRUE;
1312331766Sken		switch (node->send_ls_acc) {
1313331766Sken		case OCS_NODE_SEND_LS_ACC_PLOGI: {
1314331766Sken			/* sm: send_plogi_acc is set / send PLOGI acc */
1315331766Sken			/* Normal case for T, or I+T */
1316331766Sken			ocs_send_plogi_acc(node->ls_acc_io, node->ls_acc_oxid, NULL, NULL);
1317331766Sken			ocs_node_transition(node, __ocs_d_wait_plogi_acc_cmpl, NULL);
1318331766Sken			node->send_ls_acc = OCS_NODE_SEND_LS_ACC_NONE;
1319331766Sken			node->ls_acc_io = NULL;
1320331766Sken			break;
1321331766Sken		}
1322331766Sken		case OCS_NODE_SEND_LS_ACC_PRLI: {
1323331766Sken			ocs_d_send_prli_rsp(node->ls_acc_io, node->ls_acc_oxid);
1324331766Sken			node->send_ls_acc = OCS_NODE_SEND_LS_ACC_NONE;
1325331766Sken			node->ls_acc_io = NULL;
1326331766Sken			break;
1327331766Sken		}
1328331766Sken		case OCS_NODE_SEND_LS_ACC_NONE:
1329331766Sken		default:
1330331766Sken			/* Normal case for I */
1331331766Sken			/* sm: send_plogi_acc is not set / send PLOGI acc */
1332331766Sken			ocs_node_transition(node, __ocs_d_port_logged_in, NULL);
1333331766Sken			break;
1334331766Sken		}
1335331766Sken		break;
1336331766Sken
1337331766Sken	case OCS_EVT_NODE_ATTACH_FAIL:
1338331766Sken		/* node attach failed, shutdown the node */
1339331766Sken		node->attached = FALSE;
1340331766Sken		node_printf(node, "node attach failed\n");
1341331766Sken		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1342331766Sken		ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL);
1343331766Sken		break;
1344331766Sken
1345331766Sken	/* Handle shutdown events */
1346331766Sken	case OCS_EVT_SHUTDOWN:
1347331766Sken		node_printf(node, "%s received\n", ocs_sm_event_name(evt));
1348331766Sken		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1349331766Sken		ocs_node_transition(node, __ocs_d_wait_attach_evt_shutdown, NULL);
1350331766Sken		break;
1351331766Sken	case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO:
1352331766Sken		node_printf(node, "%s received\n", ocs_sm_event_name(evt));
1353331766Sken		node->shutdown_reason = OCS_NODE_SHUTDOWN_EXPLICIT_LOGO;
1354331766Sken		ocs_node_transition(node, __ocs_d_wait_attach_evt_shutdown, NULL);
1355331766Sken		break;
1356331766Sken	case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO:
1357331766Sken		node_printf(node, "%s received\n", ocs_sm_event_name(evt));
1358331766Sken		node->shutdown_reason = OCS_NODE_SHUTDOWN_IMPLICIT_LOGO;
1359331766Sken		ocs_node_transition(node, __ocs_d_wait_attach_evt_shutdown, NULL);
1360331766Sken		break;
1361331766Sken	default:
1362331766Sken		__ocs_d_common(__func__, ctx, evt, arg);
1363331766Sken		return NULL;
1364331766Sken	}
1365331766Sken
1366331766Sken	return NULL;
1367331766Sken}
1368331766Sken
1369331766Sken/**
1370331766Sken * @ingroup device_sm
1371331766Sken * @brief Device node state machine: Wait for a node/domain
1372331766Sken * attach then shutdown node.
1373331766Sken *
1374331766Sken * @param ctx Remote node state machine context.
1375331766Sken * @param evt Event to process.
1376331766Sken * @param arg Per event optional argument.
1377331766Sken *
1378331766Sken * @return Returns NULL.
1379331766Sken */
1380331766Sken
1381331766Skenvoid *
1382331766Sken__ocs_d_wait_attach_evt_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1383331766Sken{
1384331766Sken	std_node_state_decl();
1385331766Sken
1386331766Sken	node_sm_trace();
1387331766Sken
1388331766Sken	switch(evt) {
1389331766Sken	case OCS_EVT_ENTER:
1390331766Sken		ocs_node_hold_frames(node);
1391331766Sken		break;
1392331766Sken
1393331766Sken	case OCS_EVT_EXIT:
1394331766Sken		ocs_node_accept_frames(node);
1395331766Sken		break;
1396331766Sken
1397331766Sken	/* wait for any of these attach events and then shutdown */
1398331766Sken	case OCS_EVT_NODE_ATTACH_OK:
1399331766Sken		node->attached = TRUE;
1400331766Sken		node_printf(node, "Attach evt=%s, proceed to shutdown\n", ocs_sm_event_name(evt));
1401331766Sken		ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL);
1402331766Sken		break;
1403331766Sken
1404331766Sken	case OCS_EVT_NODE_ATTACH_FAIL:
1405331766Sken		/* node attach failed, shutdown the node */
1406331766Sken		node->attached = FALSE;
1407331766Sken		node_printf(node, "Attach evt=%s, proceed to shutdown\n", ocs_sm_event_name(evt));
1408331766Sken		ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL);
1409331766Sken		break;
1410331766Sken
1411331766Sken	/* ignore shutdown events as we're already in shutdown path */
1412331766Sken	case OCS_EVT_SHUTDOWN:
1413331766Sken		/* have default shutdown event take precedence */
1414331766Sken		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1415331766Sken		/* fall through */
1416331766Sken	case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO:
1417331766Sken	case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO:
1418331766Sken		node_printf(node, "%s received\n", ocs_sm_event_name(evt));
1419331766Sken		break;
1420331766Sken
1421331766Sken	default:
1422331766Sken		__ocs_d_common(__func__, ctx, evt, arg);
1423331766Sken		return NULL;
1424331766Sken	}
1425331766Sken
1426331766Sken	return NULL;
1427331766Sken}
1428331766Sken
1429331766Sken/**
1430331766Sken * @ingroup device_sm
1431331766Sken * @brief Device node state machine: Port is logged in.
1432331766Sken *
1433331766Sken * <h3 class="desc">Description</h3>
1434331766Sken * This state is entered when a remote port has completed port login (PLOGI).
1435331766Sken *
1436331766Sken * @param ctx Remote node state machine context.
1437331766Sken * @param evt Event to process
1438331766Sken * @param arg Per event optional argument
1439331766Sken *
1440331766Sken * @return Returns NULL.
1441331766Sken */
1442331766Skenvoid *
1443331766Sken__ocs_d_port_logged_in(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1444331766Sken{
1445331766Sken	ocs_node_cb_t *cbdata = arg;
1446331766Sken	std_node_state_decl();
1447331766Sken
1448331766Sken	node_sm_trace();
1449331766Sken
1450331766Sken	/* TODO: I+T: what if PLOGI response not yet received ? */
1451331766Sken
1452331766Sken	switch(evt) {
1453331766Sken	case OCS_EVT_ENTER:
1454331766Sken		/* Normal case for I or I+T */
1455331766Sken		if (node->sport->enable_ini && !FC_ADDR_IS_DOMAIN_CTRL(node->rnode.fc_id)
1456331766Sken				&& !node->sent_prli) {
1457331766Sken			/* sm: if enable_ini / send PRLI */
1458331766Sken			ocs_send_prli(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL);
1459331766Sken			node->sent_prli = TRUE;
1460331766Sken			/* can now expect ELS_REQ_OK/FAIL/RJT */
1461331766Sken		}
1462331766Sken		break;
1463331766Sken
1464331766Sken	case OCS_EVT_FCP_CMD_RCVD: {
1465331766Sken		/* For target functionality send PRLO and drop the CMD frame. */
1466331766Sken		if (node->sport->enable_tgt) {
1467331766Sken			if (ocs_send_prlo(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT,
1468331766Sken				OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL)) {
1469331766Sken				ocs_node_transition(node, __ocs_d_wait_prlo_rsp, NULL);
1470331766Sken			}
1471331766Sken		}
1472331766Sken		break;
1473331766Sken	}
1474331766Sken
1475331766Sken	case OCS_EVT_PRLI_RCVD: {
1476331766Sken		fc_header_t *hdr = cbdata->header->dma.virt;
1477331766Sken
1478331766Sken		/* Normal for T or I+T */
1479331766Sken
1480331766Sken		ocs_process_prli_payload(node, cbdata->payload->dma.virt);
1481331766Sken		ocs_d_send_prli_rsp(cbdata->io, ocs_be16toh(hdr->ox_id));
1482331766Sken		break;
1483331766Sken	}
1484331766Sken
1485331766Sken	case OCS_EVT_SRRS_ELS_REQ_OK: {	/* PRLI response */
1486331766Sken		/* Normal case for I or I+T */
1487331766Sken		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PRLI, __ocs_d_common, __func__)) {
1488331766Sken			return NULL;
1489331766Sken		}
1490331766Sken		ocs_assert(node->els_req_cnt, NULL);
1491331766Sken		node->els_req_cnt--;
1492331766Sken		/* sm: process PRLI payload */
1493331766Sken		ocs_process_prli_payload(node, cbdata->els->els_rsp.virt);
1494331766Sken		ocs_node_transition(node, __ocs_d_device_ready, NULL);
1495331766Sken		break;
1496331766Sken	}
1497331766Sken
1498331766Sken	case OCS_EVT_SRRS_ELS_REQ_FAIL: {	/* PRLI response failed */
1499331766Sken		/* I, I+T, assume some link failure, shutdown node */
1500331766Sken		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PRLI, __ocs_d_common, __func__)) {
1501331766Sken			return NULL;
1502331766Sken		}
1503331766Sken		ocs_assert(node->els_req_cnt, NULL);
1504331766Sken		node->els_req_cnt--;
1505331766Sken		ocs_node_post_event(node, OCS_EVT_SHUTDOWN, NULL);
1506331766Sken		break;
1507331766Sken	}
1508331766Sken
1509331766Sken	case OCS_EVT_SRRS_ELS_REQ_RJT: {/* PRLI rejected by remote */
1510331766Sken		/* Normal for I, I+T (connected to an I) */
1511331766Sken		/* Node doesn't want to be a target, stay here and wait for a PRLI from the remote node
1512331766Sken		 * if it really wants to connect to us as target */
1513331766Sken		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PRLI, __ocs_d_common, __func__)) {
1514331766Sken			return NULL;
1515331766Sken		}
1516331766Sken		ocs_assert(node->els_req_cnt, NULL);
1517331766Sken		node->els_req_cnt--;
1518331766Sken		break;
1519331766Sken	}
1520331766Sken
1521331766Sken	case OCS_EVT_SRRS_ELS_CMPL_OK: {
1522331766Sken		/* Normal T, I+T, target-server rejected the process login */
1523331766Sken		/* This would be received only in the case where we sent LS_RJT for the PRLI, so
1524331766Sken		 * do nothing.   (note: as T only we could shutdown the node)
1525331766Sken		 */
1526331766Sken		ocs_assert(node->els_cmpl_cnt, NULL);
1527331766Sken		node->els_cmpl_cnt--;
1528331766Sken		break;
1529331766Sken	}
1530331766Sken
1531331766Sken	case OCS_EVT_PLOGI_RCVD: {
1532331766Sken		/* sm: save sparams, set send_plogi_acc, post implicit logout
1533331766Sken		 * Save plogi parameters */
1534331766Sken		ocs_node_save_sparms(node, cbdata->payload->dma.virt);
1535331766Sken		ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PLOGI);
1536331766Sken
1537331766Sken		/* Restart node attach with new service parameters, and send ACC */
1538331766Sken		ocs_node_post_event(node, OCS_EVT_SHUTDOWN_IMPLICIT_LOGO, NULL);
1539331766Sken		break;
1540331766Sken	}
1541331766Sken
1542331766Sken	case OCS_EVT_LOGO_RCVD: {
1543331766Sken		/* I, T, I+T */
1544331766Sken		fc_header_t *hdr = cbdata->header->dma.virt;
1545331766Sken		node_printf(node, "%s received attached=%d\n", ocs_sm_event_name(evt), node->attached);
1546331766Sken		ocs_send_logo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1547331766Sken		ocs_node_transition(node, __ocs_d_wait_logo_acc_cmpl, NULL);
1548331766Sken		break;
1549331766Sken	}
1550331766Sken
1551331766Sken	default:
1552331766Sken		__ocs_d_common(__func__, ctx, evt, arg);
1553331766Sken		return NULL;
1554331766Sken	}
1555331766Sken
1556331766Sken	return NULL;
1557331766Sken}
1558331766Sken
1559331766Sken/**
1560331766Sken * @ingroup device_sm
1561331766Sken * @brief Device node state machine: Wait for a LOGO accept.
1562331766Sken *
1563331766Sken * <h3 class="desc">Description</h3>
1564331766Sken * Waits for a LOGO accept completion.
1565331766Sken *
1566331766Sken * @param ctx Remote node state machine context.
1567331766Sken * @param evt Event to process
1568331766Sken * @param arg Per event optional argument
1569331766Sken *
1570331766Sken * @return Returns NULL.
1571331766Sken */
1572331766Sken
1573331766Skenvoid *
1574331766Sken__ocs_d_wait_logo_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1575331766Sken{
1576331766Sken	std_node_state_decl();
1577331766Sken
1578331766Sken	node_sm_trace();
1579331766Sken
1580331766Sken	switch(evt) {
1581331766Sken	case OCS_EVT_ENTER:
1582331766Sken		ocs_node_hold_frames(node);
1583331766Sken		break;
1584331766Sken
1585331766Sken	case OCS_EVT_EXIT:
1586331766Sken		ocs_node_accept_frames(node);
1587331766Sken		break;
1588331766Sken
1589331766Sken	case OCS_EVT_SRRS_ELS_CMPL_OK:
1590331766Sken	case OCS_EVT_SRRS_ELS_CMPL_FAIL:
1591331766Sken		/* sm: / post explicit logout */
1592331766Sken		ocs_assert(node->els_cmpl_cnt, NULL);
1593331766Sken		node->els_cmpl_cnt--;
1594331766Sken		ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
1595331766Sken		break;
1596331766Sken	default:
1597331766Sken		__ocs_d_common(__func__, ctx, evt, arg);
1598331766Sken		return NULL;
1599331766Sken	}
1600331766Sken
1601331766Sken	return NULL;
1602331766Sken}
1603331766Sken
1604331766Sken/**
1605331766Sken * @ingroup device_sm
1606331766Sken * @brief Device node state machine: Device is ready.
1607331766Sken *
1608331766Sken * @param ctx Remote node state machine context.
1609331766Sken * @param evt Event to process.
1610331766Sken * @param arg Per event optional argument.
1611331766Sken *
1612331766Sken * @return Returns NULL.
1613331766Sken */
1614331766Sken
1615331766Skenvoid *
1616331766Sken__ocs_d_device_ready(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1617331766Sken{
1618331766Sken	ocs_node_cb_t *cbdata = arg;
1619331766Sken	std_node_state_decl();
1620331766Sken
1621331766Sken	if (evt != OCS_EVT_FCP_CMD_RCVD) {
1622331766Sken		node_sm_trace();
1623331766Sken	}
1624331766Sken
1625331766Sken	switch(evt) {
1626331766Sken	case OCS_EVT_ENTER:
1627331766Sken		node->fcp_enabled = TRUE;
1628331766Sken		if (node->init) {
1629331766Sken			device_printf(ocs->dev, "[%s] found  (initiator) WWPN %s WWNN %s\n", node->display_name,
1630331766Sken				node->wwpn, node->wwnn);
1631331766Sken			if (node->sport->enable_tgt)
1632331766Sken				ocs_scsi_new_initiator(node);
1633331766Sken		}
1634331766Sken		if (node->targ) {
1635331766Sken			device_printf(ocs->dev, "[%s] found  (target)    WWPN %s WWNN %s\n", node->display_name,
1636331766Sken				node->wwpn, node->wwnn);
1637331766Sken			if (node->sport->enable_ini)
1638331766Sken				ocs_scsi_new_target(node);
1639331766Sken		}
1640331766Sken		break;
1641331766Sken
1642331766Sken	case OCS_EVT_EXIT:
1643331766Sken		node->fcp_enabled = FALSE;
1644331766Sken		break;
1645331766Sken
1646331766Sken	case OCS_EVT_PLOGI_RCVD: {
1647331766Sken		/* sm: save sparams, set send_plogi_acc, post implicit logout
1648331766Sken		 * Save plogi parameters */
1649331766Sken		ocs_node_save_sparms(node, cbdata->payload->dma.virt);
1650331766Sken		ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PLOGI);
1651331766Sken
1652331766Sken		/* Restart node attach with new service parameters, and send ACC */
1653331766Sken		ocs_node_post_event(node, OCS_EVT_SHUTDOWN_IMPLICIT_LOGO, NULL);
1654331766Sken		break;
1655331766Sken	}
1656331766Sken
1657331766Sken
1658331766Sken	case OCS_EVT_PDISC_RCVD: {
1659331766Sken		fc_header_t *hdr = cbdata->header->dma.virt;
1660331766Sken		ocs_send_plogi_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1661331766Sken		break;
1662331766Sken	}
1663331766Sken
1664331766Sken	case OCS_EVT_PRLI_RCVD: {
1665331766Sken		/* T, I+T: remote initiator is slow to get started */
1666331766Sken		fc_header_t *hdr = cbdata->header->dma.virt;
1667331766Sken
1668331766Sken		ocs_process_prli_payload(node, cbdata->payload->dma.virt);
1669331766Sken
1670331766Sken		/* sm: send PRLI acc/reject */
1671331766Sken		if (ocs->fc_type == node->fc_type)
1672331766Sken			ocs_send_prli_acc(cbdata->io, ocs_be16toh(hdr->ox_id), ocs->fc_type, NULL, NULL);
1673331766Sken		else
1674331766Sken			ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id), FC_REASON_UNABLE_TO_PERFORM,
1675331766Sken				FC_EXPL_REQUEST_NOT_SUPPORTED, 0, NULL, NULL);
1676331766Sken		break;
1677331766Sken	}
1678331766Sken
1679331766Sken	case OCS_EVT_PRLO_RCVD: {
1680331766Sken		fc_header_t *hdr = cbdata->header->dma.virt;
1681331766Sken		fc_prlo_payload_t *prlo = cbdata->payload->dma.virt;
1682331766Sken
1683331766Sken		/* sm: send PRLO acc/reject */
1684331766Sken		if (ocs->fc_type == prlo->type)
1685331766Sken			ocs_send_prlo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), ocs->fc_type, NULL, NULL);
1686331766Sken		else
1687331766Sken			ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id), FC_REASON_UNABLE_TO_PERFORM,
1688331766Sken				FC_EXPL_REQUEST_NOT_SUPPORTED, 0, NULL, NULL);
1689331766Sken		/*TODO: need implicit logout */
1690331766Sken		break;
1691331766Sken	}
1692331766Sken
1693331766Sken	case OCS_EVT_LOGO_RCVD: {
1694331766Sken		fc_header_t *hdr = cbdata->header->dma.virt;
1695331766Sken		node_printf(node, "%s received attached=%d\n", ocs_sm_event_name(evt), node->attached);
1696331766Sken		ocs_send_logo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1697331766Sken		ocs_node_transition(node, __ocs_d_wait_logo_acc_cmpl, NULL);
1698331766Sken		break;
1699331766Sken	}
1700331766Sken
1701331766Sken	case OCS_EVT_ADISC_RCVD: {
1702331766Sken		fc_header_t *hdr = cbdata->header->dma.virt;
1703331766Sken		ocs_send_adisc_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1704331766Sken		break;
1705331766Sken	}
1706331766Sken
1707331766Sken	case OCS_EVT_RRQ_RCVD: {
1708331766Sken		fc_header_t *hdr = cbdata->header->dma.virt;
1709331766Sken		/* Send LS_ACC */
1710331766Sken		ocs_send_ls_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1711331766Sken		break;
1712331766Sken	}
1713331766Sken
1714331766Sken	case OCS_EVT_ABTS_RCVD:
1715331766Sken		ocs_process_abts(cbdata->io, cbdata->header->dma.virt);
1716331766Sken		break;
1717331766Sken
1718331766Sken	case OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
1719331766Sken		break;
1720331766Sken
1721331766Sken	case OCS_EVT_NODE_REFOUND:
1722331766Sken		break;
1723331766Sken
1724331766Sken	case OCS_EVT_NODE_MISSING:
1725331766Sken		if (node->sport->enable_rscn) {
1726331766Sken			ocs_node_transition(node, __ocs_d_device_gone, NULL);
1727331766Sken		}
1728331766Sken		break;
1729331766Sken
1730331766Sken	case OCS_EVT_SRRS_ELS_CMPL_OK:
1731331766Sken		/* T, or I+T, PRLI accept completed ok */
1732331766Sken		ocs_assert(node->els_cmpl_cnt, NULL);
1733331766Sken		node->els_cmpl_cnt--;
1734331766Sken		break;
1735331766Sken
1736331766Sken	case OCS_EVT_SRRS_ELS_CMPL_FAIL:
1737331766Sken		/* T, or I+T, PRLI accept failed to complete */
1738331766Sken		ocs_assert(node->els_cmpl_cnt, NULL);
1739331766Sken		node->els_cmpl_cnt--;
1740331766Sken		node_printf(node, "Failed to send PRLI LS_ACC\n");
1741331766Sken		break;
1742331766Sken
1743331766Sken	default:
1744331766Sken		__ocs_d_common(__func__, ctx, evt, arg);
1745331766Sken		return NULL;
1746331766Sken	}
1747331766Sken
1748331766Sken	return NULL;
1749331766Sken}
1750331766Sken
1751331766Sken/**
1752331766Sken * @ingroup device_sm
1753331766Sken * @brief Device node state machine: Node is gone (absent from GID_PT).
1754331766Sken *
1755331766Sken * <h3 class="desc">Description</h3>
1756331766Sken * State entered when a node is detected as being gone (absent from GID_PT).
1757331766Sken *
1758331766Sken * @param ctx Remote node state machine context.
1759331766Sken * @param evt Event to process
1760331766Sken * @param arg Per event optional argument
1761331766Sken *
1762331766Sken * @return Returns NULL.
1763331766Sken */
1764331766Sken
1765331766Skenvoid *
1766331766Sken__ocs_d_device_gone(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1767331766Sken{
1768331766Sken	int32_t rc = OCS_SCSI_CALL_COMPLETE;
1769331766Sken	int32_t rc_2 = OCS_SCSI_CALL_COMPLETE;
1770331766Sken	ocs_node_cb_t *cbdata = arg;
1771331766Sken	std_node_state_decl();
1772331766Sken
1773331766Sken	node_sm_trace();
1774331766Sken
1775331766Sken	switch(evt) {
1776331766Sken	case OCS_EVT_ENTER: {
1777331766Sken		const char *labels[] = {"none", "initiator", "target", "initiator+target"};
1778331766Sken
1779331766Sken		device_printf(ocs->dev, "[%s] missing (%s)    WWPN %s WWNN %s\n", node->display_name,
1780331766Sken				labels[(node->targ << 1) | (node->init)], node->wwpn, node->wwnn);
1781331766Sken
1782331766Sken		switch(ocs_node_get_enable(node)) {
1783331766Sken		case OCS_NODE_ENABLE_T_TO_T:
1784331766Sken		case OCS_NODE_ENABLE_I_TO_T:
1785331766Sken		case OCS_NODE_ENABLE_IT_TO_T:
1786331766Sken			rc = ocs_scsi_del_target(node, OCS_SCSI_TARGET_MISSING);
1787331766Sken			break;
1788331766Sken
1789331766Sken		case OCS_NODE_ENABLE_T_TO_I:
1790331766Sken		case OCS_NODE_ENABLE_I_TO_I:
1791331766Sken		case OCS_NODE_ENABLE_IT_TO_I:
1792331766Sken			rc = ocs_scsi_del_initiator(node, OCS_SCSI_INITIATOR_MISSING);
1793331766Sken			break;
1794331766Sken
1795331766Sken		case OCS_NODE_ENABLE_T_TO_IT:
1796331766Sken			rc = ocs_scsi_del_initiator(node, OCS_SCSI_INITIATOR_MISSING);
1797331766Sken			break;
1798331766Sken
1799331766Sken		case OCS_NODE_ENABLE_I_TO_IT:
1800331766Sken			rc = ocs_scsi_del_target(node, OCS_SCSI_TARGET_MISSING);
1801331766Sken			break;
1802331766Sken
1803331766Sken		case OCS_NODE_ENABLE_IT_TO_IT:
1804331766Sken			rc = ocs_scsi_del_initiator(node, OCS_SCSI_INITIATOR_MISSING);
1805331766Sken			rc_2 = ocs_scsi_del_target(node, OCS_SCSI_TARGET_MISSING);
1806331766Sken			break;
1807331766Sken
1808331766Sken		default:
1809331766Sken			rc = OCS_SCSI_CALL_COMPLETE;
1810331766Sken			break;
1811331766Sken
1812331766Sken		}
1813331766Sken
1814331766Sken		if ((rc == OCS_SCSI_CALL_COMPLETE) && (rc_2 == OCS_SCSI_CALL_COMPLETE)) {
1815331766Sken			ocs_node_post_event(node, OCS_EVT_SHUTDOWN, NULL);
1816331766Sken		}
1817331766Sken
1818331766Sken		break;
1819331766Sken	}
1820331766Sken	case OCS_EVT_NODE_REFOUND:
1821331766Sken		/* two approaches, reauthenticate with PLOGI/PRLI, or ADISC */
1822331766Sken
1823331766Sken		/* reauthenticate with PLOGI/PRLI */
1824331766Sken		/* ocs_node_transition(node, __ocs_d_discovered, NULL); */
1825331766Sken
1826331766Sken		/* reauthenticate with ADISC
1827331766Sken		 * sm: send ADISC */
1828331766Sken		ocs_send_adisc(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL);
1829331766Sken		ocs_node_transition(node, __ocs_d_wait_adisc_rsp, NULL);
1830331766Sken		break;
1831331766Sken
1832331766Sken	case OCS_EVT_PLOGI_RCVD: {
1833331766Sken		/* sm: save sparams, set send_plogi_acc, post implicit logout
1834331766Sken		 * Save plogi parameters */
1835331766Sken		ocs_node_save_sparms(node, cbdata->payload->dma.virt);
1836331766Sken		ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PLOGI);
1837331766Sken
1838331766Sken		/* Restart node attach with new service parameters, and send ACC */
1839331766Sken		ocs_node_post_event(node, OCS_EVT_SHUTDOWN_IMPLICIT_LOGO, NULL);
1840331766Sken		break;
1841331766Sken	}
1842331766Sken
1843331766Sken	case OCS_EVT_FCP_CMD_RCVD: {
1844331766Sken		/* most likely a stale frame (received prior to link down), if attempt
1845331766Sken		 * to send LOGO, will probably timeout and eat up 20s; thus, drop FCP_CMND
1846331766Sken		 */
1847331766Sken		node_printf(node, "FCP_CMND received, drop\n");
1848331766Sken		break;
1849331766Sken	}
1850331766Sken	case OCS_EVT_LOGO_RCVD: {
1851331766Sken		/* I, T, I+T */
1852331766Sken		fc_header_t *hdr = cbdata->header->dma.virt;
1853331766Sken		node_printf(node, "%s received attached=%d\n", ocs_sm_event_name(evt), node->attached);
1854331766Sken		/* sm: send LOGO acc */
1855331766Sken		ocs_send_logo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1856331766Sken		ocs_node_transition(node, __ocs_d_wait_logo_acc_cmpl, NULL);
1857331766Sken		break;
1858331766Sken	}
1859331766Sken	default:
1860331766Sken		__ocs_d_common(__func__, ctx, evt, arg);
1861331766Sken		return NULL;
1862331766Sken	}
1863331766Sken
1864331766Sken	return NULL;
1865331766Sken}
1866331766Sken
1867331766Sken/**
1868331766Sken * @ingroup device_sm
1869331766Sken * @brief Device node state machine: Wait for the ADISC response.
1870331766Sken *
1871331766Sken * <h3 class="desc">Description</h3>
1872331766Sken * Waits for the ADISC response from the remote node.
1873331766Sken *
1874331766Sken * @param ctx Remote node state machine context.
1875331766Sken * @param evt Event to process.
1876331766Sken * @param arg Per event optional argument.
1877331766Sken *
1878331766Sken * @return Returns NULL.
1879331766Sken */
1880331766Sken
1881331766Skenvoid *
1882331766Sken__ocs_d_wait_adisc_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1883331766Sken{
1884331766Sken	ocs_node_cb_t *cbdata = arg;
1885331766Sken	std_node_state_decl();
1886331766Sken
1887331766Sken	node_sm_trace();
1888331766Sken
1889331766Sken	switch(evt) {
1890331766Sken	case OCS_EVT_SRRS_ELS_REQ_OK:
1891331766Sken		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_ADISC, __ocs_d_common, __func__)) {
1892331766Sken			return NULL;
1893331766Sken		}
1894331766Sken		ocs_assert(node->els_req_cnt, NULL);
1895331766Sken		node->els_req_cnt--;
1896331766Sken		ocs_node_transition(node, __ocs_d_device_ready, NULL);
1897331766Sken		break;
1898331766Sken
1899331766Sken	case OCS_EVT_SRRS_ELS_REQ_RJT:
1900331766Sken		/* received an LS_RJT, in this case, send shutdown (explicit logo)
1901331766Sken		 * event which will unregister the node, and start over with PLOGI
1902331766Sken		 */
1903331766Sken		if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_ADISC, __ocs_d_common, __func__)) {
1904331766Sken			return NULL;
1905331766Sken		}
1906331766Sken		ocs_assert(node->els_req_cnt, NULL);
1907331766Sken		node->els_req_cnt--;
1908331766Sken		/*sm: post explicit logout */
1909331766Sken		ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
1910331766Sken		break;
1911331766Sken
1912331766Sken	case OCS_EVT_LOGO_RCVD: {
1913331766Sken		/* In this case, we have the equivalent of an LS_RJT for the ADISC,
1914331766Sken		 * so we need to abort the ADISC, and re-login with PLOGI
1915331766Sken		 */
1916331766Sken		/*sm: request abort, send LOGO acc */
1917331766Sken		fc_header_t *hdr = cbdata->header->dma.virt;
1918331766Sken		node_printf(node, "%s received attached=%d\n", ocs_sm_event_name(evt), node->attached);
1919331766Sken		ocs_send_logo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1920331766Sken		ocs_node_transition(node, __ocs_d_wait_logo_acc_cmpl, NULL);
1921331766Sken		break;
1922331766Sken	}
1923331766Sken	default:
1924331766Sken		__ocs_d_common(__func__, ctx, evt, arg);
1925331766Sken		return NULL;
1926331766Sken	}
1927331766Sken
1928331766Sken	return NULL;
1929331766Sken}
1930