xref: /freebsd/sys/dev/ocs_fc/ocs_node.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  * OCS driver remote node handler.  This file contains code that is shared
35ef270ab1SKenneth D. Merry  * between fabric (ocs_fabric.c) and device (ocs_device.c) nodes.
36ef270ab1SKenneth D. Merry  */
37ef270ab1SKenneth D. Merry 
38ef270ab1SKenneth D. Merry /*!
39ef270ab1SKenneth D. Merry  * @defgroup node_common Node common support
40ef270ab1SKenneth D. Merry  * @defgroup node_alloc Node allocation
41ef270ab1SKenneth D. Merry  */
42ef270ab1SKenneth D. Merry 
43ef270ab1SKenneth D. Merry #include "ocs.h"
44ef270ab1SKenneth D. Merry #include "ocs_els.h"
45ef270ab1SKenneth D. Merry #include "ocs_device.h"
46ef270ab1SKenneth D. Merry 
47ef270ab1SKenneth D. Merry #define SCSI_IOFMT "[%04x][i:%0*x t:%0*x h:%04x]"
48ef270ab1SKenneth D. Merry #define SCSI_ITT_SIZE(ocs)	((ocs->ocs_xport == OCS_XPORT_FC) ? 4 : 8)
49ef270ab1SKenneth D. Merry 
50ef270ab1SKenneth D. Merry #define SCSI_IOFMT_ARGS(io) io->instance_index, SCSI_ITT_SIZE(io->ocs), io->init_task_tag, SCSI_ITT_SIZE(io->ocs), io->tgt_task_tag, io->hw_tag
51ef270ab1SKenneth D. Merry 
52ef270ab1SKenneth D. Merry #define scsi_io_printf(io, fmt, ...) ocs_log_debug(io->ocs, "[%s]" SCSI_IOFMT fmt, \
53ef270ab1SKenneth D. Merry 	io->node->display_name, SCSI_IOFMT_ARGS(io), ##__VA_ARGS__)
54ef270ab1SKenneth D. Merry 
55ef270ab1SKenneth D. Merry void ocs_mgmt_node_list(ocs_textbuf_t *textbuf, void *node);
56ef270ab1SKenneth D. Merry void ocs_mgmt_node_get_all(ocs_textbuf_t *textbuf, void *node);
57ef270ab1SKenneth D. Merry int ocs_mgmt_node_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *node);
58ef270ab1SKenneth D. Merry int ocs_mgmt_node_set(char *parent, char *name, char *value, void *node);
59ef270ab1SKenneth D. Merry int ocs_mgmt_node_exec(char *parent, char *action, void *arg_in, uint32_t arg_in_length,
60ef270ab1SKenneth D. Merry 		void *arg_out, uint32_t arg_out_length, void *node);
61ef270ab1SKenneth D. Merry static ocs_mgmt_functions_t node_mgmt_functions = {
62ef270ab1SKenneth D. Merry 	.get_list_handler	=	ocs_mgmt_node_list,
63ef270ab1SKenneth D. Merry 	.get_handler		=	ocs_mgmt_node_get,
64ef270ab1SKenneth D. Merry 	.get_all_handler	=	ocs_mgmt_node_get_all,
65ef270ab1SKenneth D. Merry 	.set_handler		=	ocs_mgmt_node_set,
66ef270ab1SKenneth D. Merry 	.exec_handler		=	ocs_mgmt_node_exec,
67ef270ab1SKenneth D. Merry };
68ef270ab1SKenneth D. Merry 
69ef270ab1SKenneth D. Merry /**
70ef270ab1SKenneth D. Merry  * @ingroup node_common
71ef270ab1SKenneth D. Merry  * @brief Device node state machine wait for all ELS's to
72ef270ab1SKenneth D. Merry  *        complete
73ef270ab1SKenneth D. Merry  *
74ef270ab1SKenneth D. Merry  * Abort all ELS's for given node.
75ef270ab1SKenneth D. Merry  *
76ef270ab1SKenneth D. Merry  * @param node node for which ELS's will be aborted
77ef270ab1SKenneth D. Merry  */
78ef270ab1SKenneth D. Merry 
79ef270ab1SKenneth D. Merry void
ocs_node_abort_all_els(ocs_node_t * node)80ef270ab1SKenneth D. Merry ocs_node_abort_all_els(ocs_node_t *node)
81ef270ab1SKenneth D. Merry {
82ef270ab1SKenneth D. Merry 	ocs_io_t *els;
83ef270ab1SKenneth D. Merry 	ocs_io_t *els_next;
84ef270ab1SKenneth D. Merry 	ocs_node_cb_t cbdata = {0};
85ef270ab1SKenneth D. Merry 
86ef270ab1SKenneth D. Merry 	ocs_node_hold_frames(node);
87ef270ab1SKenneth D. Merry 	ocs_lock(&node->active_ios_lock);
88ef270ab1SKenneth D. Merry 		ocs_list_foreach_safe(&node->els_io_active_list, els, els_next) {
89ef270ab1SKenneth D. Merry 			ocs_log_debug(node->ocs, "[%s] initiate ELS abort %s\n", node->display_name, els->display_name);
90ef270ab1SKenneth D. Merry 			ocs_unlock(&node->active_ios_lock);
91ef270ab1SKenneth D. Merry 			cbdata.els = els;
92ef270ab1SKenneth D. Merry 			ocs_els_post_event(els, OCS_EVT_ABORT_ELS, &cbdata);
93ef270ab1SKenneth D. Merry 			ocs_lock(&node->active_ios_lock);
94ef270ab1SKenneth D. Merry 		}
95ef270ab1SKenneth D. Merry 	ocs_unlock(&node->active_ios_lock);
96ef270ab1SKenneth D. Merry }
97ef270ab1SKenneth D. Merry 
98ef270ab1SKenneth D. Merry /**
99ef270ab1SKenneth D. Merry  * @ingroup node_common
100ef270ab1SKenneth D. Merry  * @brief Handle remote node events from HW
101ef270ab1SKenneth D. Merry  *
102ef270ab1SKenneth D. Merry  * Handle remote node events from HW.   Essentially the HW event is translated into
103ef270ab1SKenneth D. Merry  * a node state machine event that is posted to the affected node.
104ef270ab1SKenneth D. Merry  *
105ef270ab1SKenneth D. Merry  * @param arg pointer to ocs
106ef270ab1SKenneth D. Merry  * @param event HW event to proceoss
107ef270ab1SKenneth D. Merry  * @param data application specific data (pointer to the affected node)
108ef270ab1SKenneth D. Merry  *
109ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
110ef270ab1SKenneth D. Merry  */
111ef270ab1SKenneth D. Merry int32_t
ocs_remote_node_cb(void * arg,ocs_hw_remote_node_event_e event,void * data)112ef270ab1SKenneth D. Merry ocs_remote_node_cb(void *arg, ocs_hw_remote_node_event_e event, void *data)
113ef270ab1SKenneth D. Merry {
114ef270ab1SKenneth D. Merry 	ocs_t *ocs = arg;
115ef270ab1SKenneth D. Merry 	ocs_sm_event_t	sm_event = OCS_EVT_LAST;
116ef270ab1SKenneth D. Merry 	ocs_remote_node_t *rnode = data;
117ef270ab1SKenneth D. Merry 	ocs_node_t *node = rnode->node;
118ef270ab1SKenneth D. Merry 
119ef270ab1SKenneth D. Merry 	switch (event) {
120ef270ab1SKenneth D. Merry 	case OCS_HW_NODE_ATTACH_OK:
121ef270ab1SKenneth D. Merry 		sm_event = OCS_EVT_NODE_ATTACH_OK;
122ef270ab1SKenneth D. Merry 		break;
123ef270ab1SKenneth D. Merry 
124ef270ab1SKenneth D. Merry 	case OCS_HW_NODE_ATTACH_FAIL:
125ef270ab1SKenneth D. Merry 		sm_event = OCS_EVT_NODE_ATTACH_FAIL;
126ef270ab1SKenneth D. Merry 		break;
127ef270ab1SKenneth D. Merry 
128ef270ab1SKenneth D. Merry 	case OCS_HW_NODE_FREE_OK:
129ef270ab1SKenneth D. Merry 		sm_event = OCS_EVT_NODE_FREE_OK;
130ef270ab1SKenneth D. Merry 		break;
131ef270ab1SKenneth D. Merry 
132ef270ab1SKenneth D. Merry 	case OCS_HW_NODE_FREE_FAIL:
133ef270ab1SKenneth D. Merry 		sm_event = OCS_EVT_NODE_FREE_FAIL;
134ef270ab1SKenneth D. Merry 		break;
135ef270ab1SKenneth D. Merry 
136ef270ab1SKenneth D. Merry 	default:
137ef270ab1SKenneth D. Merry 		ocs_log_test(ocs, "unhandled event %#x\n", event);
138ef270ab1SKenneth D. Merry 		return -1;
139ef270ab1SKenneth D. Merry 	}
140ef270ab1SKenneth D. Merry 
141ef270ab1SKenneth D. Merry 	/* If we're using HLM, forward the NODE_ATTACH_OK/FAIL event to all nodes in the node group */
142ef270ab1SKenneth D. Merry 	if ((node->node_group != NULL) &&
143ef270ab1SKenneth D. Merry 			((sm_event == OCS_EVT_NODE_ATTACH_OK) || (sm_event == OCS_EVT_NODE_ATTACH_FAIL))) {
144ef270ab1SKenneth D. Merry 		ocs_node_t *n = NULL;
145ef270ab1SKenneth D. Merry 		uint8_t		attach_ok = sm_event == OCS_EVT_NODE_ATTACH_OK;
146ef270ab1SKenneth D. Merry 
147ef270ab1SKenneth D. Merry 		ocs_sport_lock(node->sport);
148ef270ab1SKenneth D. Merry 		{
149ef270ab1SKenneth D. Merry 			ocs_list_foreach(&node->sport->node_list, n) {
150ef270ab1SKenneth D. Merry 				if (node == n) {
151ef270ab1SKenneth D. Merry 					continue;
152ef270ab1SKenneth D. Merry 				}
153ef270ab1SKenneth D. Merry 				ocs_node_lock(n);
154ef270ab1SKenneth D. Merry 					if ((!n->rnode.attached) && (node->node_group == n->node_group)) {
155ef270ab1SKenneth D. Merry 						n->rnode.attached = attach_ok;
156ef270ab1SKenneth D. Merry 						node_printf(n, "rpi[%d] deferred HLM node attach %s posted\n",
157ef270ab1SKenneth D. Merry 								n->rnode.index, attach_ok ? "ok" : "fail");
158ef270ab1SKenneth D. Merry 						ocs_node_post_event(n, sm_event, NULL);
159ef270ab1SKenneth D. Merry 					}
160ef270ab1SKenneth D. Merry 				ocs_node_unlock(n);
161ef270ab1SKenneth D. Merry 			}
162ef270ab1SKenneth D. Merry 		}
163ef270ab1SKenneth D. Merry 
164ef270ab1SKenneth D. Merry 		ocs_sport_unlock(node->sport);
165ef270ab1SKenneth D. Merry 	}
166ef270ab1SKenneth D. Merry 
167ef270ab1SKenneth D. Merry 	ocs_node_post_event(node, sm_event, NULL);
168ef270ab1SKenneth D. Merry 
169ef270ab1SKenneth D. Merry 	return 0;
170ef270ab1SKenneth D. Merry }
171ef270ab1SKenneth D. Merry 
172ef270ab1SKenneth D. Merry /**
173ef270ab1SKenneth D. Merry  * @ingroup node_alloc
174ef270ab1SKenneth D. Merry  * @brief Find an FC node structure given the FC port ID
175ef270ab1SKenneth D. Merry  *
176ef270ab1SKenneth D. Merry  * @param sport the SPORT to search
177ef270ab1SKenneth D. Merry  * @param port_id FC port ID
178ef270ab1SKenneth D. Merry  *
179ef270ab1SKenneth D. Merry  * @return pointer to the object or NULL if not found
180ef270ab1SKenneth D. Merry  */
181ef270ab1SKenneth D. Merry ocs_node_t *
ocs_node_find(ocs_sport_t * sport,uint32_t port_id)182ef270ab1SKenneth D. Merry ocs_node_find(ocs_sport_t *sport, uint32_t port_id)
183ef270ab1SKenneth D. Merry {
184ef270ab1SKenneth D. Merry 	ocs_node_t *node;
185ef270ab1SKenneth D. Merry 
186ef270ab1SKenneth D. Merry 	ocs_assert(sport->lookup, NULL);
187ef270ab1SKenneth D. Merry 	ocs_sport_lock(sport);
188ef270ab1SKenneth D. Merry 		node = spv_get(sport->lookup, port_id);
189ef270ab1SKenneth D. Merry 	ocs_sport_unlock(sport);
190ef270ab1SKenneth D. Merry 	return node;
191ef270ab1SKenneth D. Merry }
192ef270ab1SKenneth D. Merry 
193ef270ab1SKenneth D. Merry /**
194ef270ab1SKenneth D. Merry  * @ingroup node_alloc
195ef270ab1SKenneth D. Merry  * @brief Find an FC node structure given the WWPN
196ef270ab1SKenneth D. Merry  *
197ef270ab1SKenneth D. Merry  * @param sport the SPORT to search
198ef270ab1SKenneth D. Merry  * @param wwpn the WWPN to search for (host endian)
199ef270ab1SKenneth D. Merry  *
200ef270ab1SKenneth D. Merry  * @return pointer to the object or NULL if not found
201ef270ab1SKenneth D. Merry  */
202ef270ab1SKenneth D. Merry ocs_node_t *
ocs_node_find_wwpn(ocs_sport_t * sport,uint64_t wwpn)203ef270ab1SKenneth D. Merry ocs_node_find_wwpn(ocs_sport_t *sport, uint64_t wwpn)
204ef270ab1SKenneth D. Merry {
205*aeb665b5SEd Maste 	ocs_node_t *node = NULL;
206ef270ab1SKenneth D. Merry 
207ef270ab1SKenneth D. Merry 	ocs_assert(sport, NULL);
208ef270ab1SKenneth D. Merry 
209ef270ab1SKenneth D. Merry 	ocs_sport_lock(sport);
210ef270ab1SKenneth D. Merry 		ocs_list_foreach(&sport->node_list, node) {
211ef270ab1SKenneth D. Merry 			if (ocs_node_get_wwpn(node) == wwpn) {
212ef270ab1SKenneth D. Merry 				ocs_sport_unlock(sport);
213ef270ab1SKenneth D. Merry 				return node;
214ef270ab1SKenneth D. Merry 			}
215ef270ab1SKenneth D. Merry 		}
216ef270ab1SKenneth D. Merry 	ocs_sport_unlock(sport);
217ef270ab1SKenneth D. Merry 	return NULL;
218ef270ab1SKenneth D. Merry }
219ef270ab1SKenneth D. Merry 
220ef270ab1SKenneth D. Merry /**
221ef270ab1SKenneth D. Merry  * @ingroup node_alloc
222ef270ab1SKenneth D. Merry  * @brief allocate node object pool
223ef270ab1SKenneth D. Merry  *
224ef270ab1SKenneth D. Merry  * A pool of ocs_node_t objects is allocated.
225ef270ab1SKenneth D. Merry  *
226ef270ab1SKenneth D. Merry  * @param ocs pointer to driver instance context
227ef270ab1SKenneth D. Merry  * @param node_count count of nodes to allocate
228ef270ab1SKenneth D. Merry  *
229ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
230ef270ab1SKenneth D. Merry  */
231ef270ab1SKenneth D. Merry 
232ef270ab1SKenneth D. Merry int32_t
ocs_node_create_pool(ocs_t * ocs,uint32_t node_count)233ef270ab1SKenneth D. Merry ocs_node_create_pool(ocs_t *ocs, uint32_t node_count)
234ef270ab1SKenneth D. Merry {
235ef270ab1SKenneth D. Merry 	ocs_xport_t *xport = ocs->xport;
236ef270ab1SKenneth D. Merry 	uint32_t i;
237ef270ab1SKenneth D. Merry 	ocs_node_t *node;
238ef270ab1SKenneth D. Merry 	uint32_t max_sge;
239ef270ab1SKenneth D. Merry 	uint32_t num_sgl;
240ef270ab1SKenneth D. Merry 	uint64_t max_xfer_size;
241ef270ab1SKenneth D. Merry 	int32_t rc;
242ef270ab1SKenneth D. Merry 
243ef270ab1SKenneth D. Merry 	xport->nodes_count = node_count;
244ef270ab1SKenneth D. Merry 
245ef270ab1SKenneth D. Merry 	xport->nodes = ocs_malloc(ocs, node_count * sizeof(ocs_node_t *), OCS_M_ZERO | OCS_M_NOWAIT);
246ef270ab1SKenneth D. Merry 	if (xport->nodes == NULL) {
247ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "node ptrs allocation failed");
248ef270ab1SKenneth D. Merry 		return -1;
249ef270ab1SKenneth D. Merry 	}
250ef270ab1SKenneth D. Merry 
251ef270ab1SKenneth D. Merry 	if (0 == ocs_hw_get(&ocs->hw, OCS_HW_MAX_SGE, &max_sge) &&
252ef270ab1SKenneth D. Merry 	    0 == ocs_hw_get(&ocs->hw, OCS_HW_N_SGL, &num_sgl)) {
2534915e5c7SRam Kishore Vegesna 		max_xfer_size = (max_sge * (uint64_t)num_sgl);
254ef270ab1SKenneth D. Merry 	} else {
255ef270ab1SKenneth D. Merry 		max_xfer_size = 65536;
256ef270ab1SKenneth D. Merry 	}
257ef270ab1SKenneth D. Merry 
258ef270ab1SKenneth D. Merry 	if (max_xfer_size > 65536)
259ef270ab1SKenneth D. Merry 		max_xfer_size = 65536;
260ef270ab1SKenneth D. Merry 
261ef270ab1SKenneth D. Merry 	ocs_list_init(&xport->nodes_free_list, ocs_node_t, link);
262ef270ab1SKenneth D. Merry 
263ef270ab1SKenneth D. Merry 	for (i = 0; i < node_count; i ++) {
264ef270ab1SKenneth D. Merry 		node = ocs_malloc(ocs, sizeof(ocs_node_t), OCS_M_ZERO | OCS_M_NOWAIT);
265ef270ab1SKenneth D. Merry 		if (node == NULL) {
266ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "node allocation failed");
267ef270ab1SKenneth D. Merry 			goto error;
268ef270ab1SKenneth D. Merry 		}
269ef270ab1SKenneth D. Merry 
270ef270ab1SKenneth D. Merry 		/* Assign any persistent field values */
271ef270ab1SKenneth D. Merry 		node->instance_index = i;
272ef270ab1SKenneth D. Merry 		node->max_wr_xfer_size = max_xfer_size;
273ef270ab1SKenneth D. Merry 		node->rnode.indicator = UINT32_MAX;
274ef270ab1SKenneth D. Merry 
275ef270ab1SKenneth D. Merry 		rc = ocs_dma_alloc(ocs, &node->sparm_dma_buf, 256, 16);
276ef270ab1SKenneth D. Merry 		if (rc) {
277ef270ab1SKenneth D. Merry 			ocs_free(ocs, node, sizeof(ocs_node_t));
278ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "ocs_dma_alloc failed: %d\n", rc);
279ef270ab1SKenneth D. Merry 			goto error;
280ef270ab1SKenneth D. Merry 		}
281ef270ab1SKenneth D. Merry 
282ef270ab1SKenneth D. Merry 		xport->nodes[i] = node;
283ef270ab1SKenneth D. Merry 		ocs_list_add_tail(&xport->nodes_free_list, node);
284ef270ab1SKenneth D. Merry 	}
285ef270ab1SKenneth D. Merry 	return 0;
286ef270ab1SKenneth D. Merry 
287ef270ab1SKenneth D. Merry error:
288ef270ab1SKenneth D. Merry 	ocs_node_free_pool(ocs);
289ef270ab1SKenneth D. Merry 	return -1;
290ef270ab1SKenneth D. Merry }
291ef270ab1SKenneth D. Merry 
292ef270ab1SKenneth D. Merry /**
293ef270ab1SKenneth D. Merry  * @ingroup node_alloc
294ef270ab1SKenneth D. Merry  * @brief free node object pool
295ef270ab1SKenneth D. Merry  *
296ef270ab1SKenneth D. Merry  * The pool of previously allocated node objects is freed
297ef270ab1SKenneth D. Merry  *
298ef270ab1SKenneth D. Merry  * @param ocs pointer to driver instance context
299ef270ab1SKenneth D. Merry  *
300ef270ab1SKenneth D. Merry  * @return none
301ef270ab1SKenneth D. Merry  */
302ef270ab1SKenneth D. Merry 
303ef270ab1SKenneth D. Merry void
ocs_node_free_pool(ocs_t * ocs)304ef270ab1SKenneth D. Merry ocs_node_free_pool(ocs_t *ocs)
305ef270ab1SKenneth D. Merry {
306ef270ab1SKenneth D. Merry 	ocs_xport_t *xport = ocs->xport;
307ef270ab1SKenneth D. Merry 	ocs_node_t *node;
308ef270ab1SKenneth D. Merry 	uint32_t i;
309ef270ab1SKenneth D. Merry 
310ef270ab1SKenneth D. Merry 	if (!xport->nodes)
311ef270ab1SKenneth D. Merry 		return;
312ef270ab1SKenneth D. Merry 
313ef270ab1SKenneth D. Merry 	ocs_device_lock(ocs);
314ef270ab1SKenneth D. Merry 
315ef270ab1SKenneth D. Merry 	for (i = 0; i < xport->nodes_count; i ++) {
316ef270ab1SKenneth D. Merry 		node = xport->nodes[i];
317ef270ab1SKenneth D. Merry 		if (node) {
318ef270ab1SKenneth D. Merry 			/* free sparam_dma_buf */
319ef270ab1SKenneth D. Merry 			ocs_dma_free(ocs, &node->sparm_dma_buf);
320ef270ab1SKenneth D. Merry 			ocs_free(ocs, node, sizeof(ocs_node_t));
321ef270ab1SKenneth D. Merry 		}
322ef270ab1SKenneth D. Merry 		xport->nodes[i] = NULL;
323ef270ab1SKenneth D. Merry 	}
324ef270ab1SKenneth D. Merry 
325ef270ab1SKenneth D. Merry 	ocs_free(ocs, xport->nodes, (xport->nodes_count * sizeof(ocs_node_t *)));
326ef270ab1SKenneth D. Merry 
327ef270ab1SKenneth D. Merry 	ocs_device_unlock(ocs);
328ef270ab1SKenneth D. Merry }
329ef270ab1SKenneth D. Merry 
330ef270ab1SKenneth D. Merry /**
331ef270ab1SKenneth D. Merry  * @ingroup node_alloc
332ef270ab1SKenneth D. Merry  * @brief return pointer to node object given instance index
333ef270ab1SKenneth D. Merry  *
334ef270ab1SKenneth D. Merry  * A pointer to the node object given by an instance index is returned.
335ef270ab1SKenneth D. Merry  *
336ef270ab1SKenneth D. Merry  * @param ocs pointer to driver instance context
337ef270ab1SKenneth D. Merry  * @param index instance index
338ef270ab1SKenneth D. Merry  *
339ef270ab1SKenneth D. Merry  * @return returns pointer to node object, or NULL
340ef270ab1SKenneth D. Merry  */
341ef270ab1SKenneth D. Merry 
342ef270ab1SKenneth D. Merry ocs_node_t *
ocs_node_get_instance(ocs_t * ocs,uint32_t index)343ef270ab1SKenneth D. Merry ocs_node_get_instance(ocs_t *ocs, uint32_t index)
344ef270ab1SKenneth D. Merry {
345ef270ab1SKenneth D. Merry 	ocs_xport_t *xport = ocs->xport;
346ef270ab1SKenneth D. Merry 	ocs_node_t *node = NULL;
347ef270ab1SKenneth D. Merry 
348ef270ab1SKenneth D. Merry 	if (index >= (xport->nodes_count)) {
349ef270ab1SKenneth D. Merry 		ocs_log_test(ocs, "invalid index: %d\n", index);
350ef270ab1SKenneth D. Merry 		return NULL;
351ef270ab1SKenneth D. Merry 	}
352ef270ab1SKenneth D. Merry 	node = xport->nodes[index];
353ef270ab1SKenneth D. Merry 	return node->attached ? node : NULL;
354ef270ab1SKenneth D. Merry }
355ef270ab1SKenneth D. Merry 
356ef270ab1SKenneth D. Merry /**
357ef270ab1SKenneth D. Merry  * @ingroup node_alloc
358ef270ab1SKenneth D. Merry  * @brief Allocate an fc node structure and add to node list
359ef270ab1SKenneth D. Merry  *
360ef270ab1SKenneth D. Merry  * @param sport pointer to the SPORT from which this node is allocated
361ef270ab1SKenneth D. Merry  * @param port_id FC port ID of new node
362ef270ab1SKenneth D. Merry  * @param init Port is an inititiator (sent a plogi)
363ef270ab1SKenneth D. Merry  * @param targ Port is potentially a target
364ef270ab1SKenneth D. Merry  *
365ef270ab1SKenneth D. Merry  * @return pointer to the object or NULL if none available
366ef270ab1SKenneth D. Merry  */
367ef270ab1SKenneth D. Merry 
368ef270ab1SKenneth D. Merry ocs_node_t *
ocs_node_alloc(ocs_sport_t * sport,uint32_t port_id,uint8_t init,uint8_t targ)369ef270ab1SKenneth D. Merry ocs_node_alloc(ocs_sport_t *sport, uint32_t port_id, uint8_t init, uint8_t targ)
370ef270ab1SKenneth D. Merry {
371ef270ab1SKenneth D. Merry 	int32_t rc;
372ef270ab1SKenneth D. Merry 	ocs_node_t *node = NULL;
373ef270ab1SKenneth D. Merry 	uint32_t instance_index;
374ef270ab1SKenneth D. Merry 	uint32_t max_wr_xfer_size;
375ef270ab1SKenneth D. Merry 	ocs_t *ocs = sport->ocs;
376ef270ab1SKenneth D. Merry 	ocs_xport_t *xport = ocs->xport;
377ef270ab1SKenneth D. Merry 	ocs_dma_t sparm_dma_buf;
378ef270ab1SKenneth D. Merry 
379ef270ab1SKenneth D. Merry 	ocs_assert(sport, NULL);
380ef270ab1SKenneth D. Merry 
381ef270ab1SKenneth D. Merry 	if (sport->shutting_down) {
382ef270ab1SKenneth D. Merry 		ocs_log_debug(ocs, "node allocation when shutting down %06x", port_id);
383ef270ab1SKenneth D. Merry 		return NULL;
384ef270ab1SKenneth D. Merry 	}
385ef270ab1SKenneth D. Merry 
386ef270ab1SKenneth D. Merry 	ocs_device_lock(ocs);
387ef270ab1SKenneth D. Merry 		node = ocs_list_remove_head(&xport->nodes_free_list);
388ef270ab1SKenneth D. Merry 	ocs_device_unlock(ocs);
389ef270ab1SKenneth D. Merry 	if (node == NULL) {
390ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "node allocation failed %06x", port_id);
391ef270ab1SKenneth D. Merry 		return NULL;
392ef270ab1SKenneth D. Merry 	}
393ef270ab1SKenneth D. Merry 
394ef270ab1SKenneth D. Merry 	/* Save persistent values across memset zero */
395ef270ab1SKenneth D. Merry 	instance_index = node->instance_index;
396ef270ab1SKenneth D. Merry 	max_wr_xfer_size = node->max_wr_xfer_size;
397ef270ab1SKenneth D. Merry 	sparm_dma_buf = node->sparm_dma_buf;
398ef270ab1SKenneth D. Merry 
399ef270ab1SKenneth D. Merry 	ocs_memset(node, 0, sizeof(*node));
400ef270ab1SKenneth D. Merry 	node->instance_index = instance_index;
401ef270ab1SKenneth D. Merry 	node->max_wr_xfer_size = max_wr_xfer_size;
402ef270ab1SKenneth D. Merry 	node->sparm_dma_buf = sparm_dma_buf;
403ef270ab1SKenneth D. Merry 	node->rnode.indicator = UINT32_MAX;
404ef270ab1SKenneth D. Merry 
405ef270ab1SKenneth D. Merry 	node->sport = sport;
406ef270ab1SKenneth D. Merry 	ocs_sport_lock(sport);
407ef270ab1SKenneth D. Merry 
408ef270ab1SKenneth D. Merry 		node->ocs = ocs;
409ef270ab1SKenneth D. Merry 		node->init = init;
410ef270ab1SKenneth D. Merry 		node->targ = targ;
411ef270ab1SKenneth D. Merry 
412ef270ab1SKenneth D. Merry 		rc = ocs_hw_node_alloc(&ocs->hw, &node->rnode, port_id, sport);
413ef270ab1SKenneth D. Merry 		if (rc) {
414ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "ocs_hw_node_alloc failed: %d\n", rc);
415ef270ab1SKenneth D. Merry 			ocs_sport_unlock(sport);
416ef270ab1SKenneth D. Merry 
417ef270ab1SKenneth D. Merry 			/* Return back to pool. */
418ef270ab1SKenneth D. Merry 			ocs_device_lock(ocs);
419ef270ab1SKenneth D. Merry 			ocs_list_add_tail(&xport->nodes_free_list, node);
420ef270ab1SKenneth D. Merry 			ocs_device_unlock(ocs);
421ef270ab1SKenneth D. Merry 
422ef270ab1SKenneth D. Merry 			return NULL;
423ef270ab1SKenneth D. Merry 		}
424ef270ab1SKenneth D. Merry 		ocs_list_add_tail(&sport->node_list, node);
425ef270ab1SKenneth D. Merry 
426ef270ab1SKenneth D. Merry 		ocs_node_lock_init(node);
427ef270ab1SKenneth D. Merry 		ocs_lock_init(ocs, &node->pend_frames_lock, "pend_frames_lock[%d]", node->instance_index);
428ef270ab1SKenneth D. Merry 		ocs_list_init(&node->pend_frames, ocs_hw_sequence_t, link);
429ef270ab1SKenneth D. Merry 		ocs_lock_init(ocs, &node->active_ios_lock, "active_ios[%d]", node->instance_index);
430ef270ab1SKenneth D. Merry 		ocs_list_init(&node->active_ios, ocs_io_t, link);
431ef270ab1SKenneth D. Merry 		ocs_list_init(&node->els_io_pend_list, ocs_io_t, link);
432ef270ab1SKenneth D. Merry 		ocs_list_init(&node->els_io_active_list, ocs_io_t, link);
433ef270ab1SKenneth D. Merry 		ocs_scsi_io_alloc_enable(node);
434ef270ab1SKenneth D. Merry 
435ef270ab1SKenneth D. Merry 		/* zero the service parameters */
436ef270ab1SKenneth D. Merry 		ocs_memset(node->sparm_dma_buf.virt, 0, node->sparm_dma_buf.size);
437ef270ab1SKenneth D. Merry 
438ef270ab1SKenneth D. Merry 		node->rnode.node = node;
439ef270ab1SKenneth D. Merry 		node->sm.app = node;
440ef270ab1SKenneth D. Merry 		node->evtdepth = 0;
441ef270ab1SKenneth D. Merry 
442ef270ab1SKenneth D. Merry 		ocs_node_update_display_name(node);
443ef270ab1SKenneth D. Merry 
444ef270ab1SKenneth D. Merry 		spv_set(sport->lookup, port_id, node);
445ef270ab1SKenneth D. Merry 	ocs_sport_unlock(sport);
446ef270ab1SKenneth D. Merry 	node->mgmt_functions = &node_mgmt_functions;
447ef270ab1SKenneth D. Merry 
448ef270ab1SKenneth D. Merry 	return node;
449ef270ab1SKenneth D. Merry }
450ef270ab1SKenneth D. Merry 
451ef270ab1SKenneth D. Merry /**
452ef270ab1SKenneth D. Merry  * @ingroup node_alloc
453ef270ab1SKenneth D. Merry  * @brief free a node structure
454ef270ab1SKenneth D. Merry  *
455ef270ab1SKenneth D. Merry  * The node structure given by 'node' is free'd
456ef270ab1SKenneth D. Merry  *
457ef270ab1SKenneth D. Merry  * @param node the node to free
458ef270ab1SKenneth D. Merry  *
459ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
460ef270ab1SKenneth D. Merry  */
461ef270ab1SKenneth D. Merry 
462ef270ab1SKenneth D. Merry int32_t
ocs_node_free(ocs_node_t * node)463ef270ab1SKenneth D. Merry ocs_node_free(ocs_node_t *node)
464ef270ab1SKenneth D. Merry {
465ef270ab1SKenneth D. Merry 	ocs_sport_t *sport;
466ef270ab1SKenneth D. Merry 	ocs_t *ocs;
467ef270ab1SKenneth D. Merry 	ocs_xport_t *xport;
468ef270ab1SKenneth D. Merry 	ocs_hw_rtn_e rc = 0;
469ef270ab1SKenneth D. Merry 	ocs_node_t *ns = NULL;
470ef270ab1SKenneth D. Merry 	int post_all_free = FALSE;
471ef270ab1SKenneth D. Merry 
472ef270ab1SKenneth D. Merry 	ocs_assert(node, -1);
473ef270ab1SKenneth D. Merry 	ocs_assert(node->sport, -1);
474ef270ab1SKenneth D. Merry 	ocs_assert(node->ocs, -1);
475ef270ab1SKenneth D. Merry 	sport = node->sport;
476ef270ab1SKenneth D. Merry 	ocs_assert(sport, -1);
477ef270ab1SKenneth D. Merry 	ocs = node->ocs;
478ef270ab1SKenneth D. Merry 	ocs_assert(ocs->xport, -1);
479ef270ab1SKenneth D. Merry 	xport = ocs->xport;
480ef270ab1SKenneth D. Merry 
481ef270ab1SKenneth D. Merry 	node_printf(node, "Free'd\n");
482ef270ab1SKenneth D. Merry 
483ef270ab1SKenneth D. Merry 	if(node->refound) {
484ef270ab1SKenneth D. Merry 		/*
485ef270ab1SKenneth D. Merry 		 * Save the name server node. We will send fake RSCN event at
486ef270ab1SKenneth D. Merry 		 * the end to handle ignored RSCN event during node deletion
487ef270ab1SKenneth D. Merry 		 */
488ef270ab1SKenneth D. Merry 		ns = ocs_node_find(node->sport, FC_ADDR_NAMESERVER);
489ef270ab1SKenneth D. Merry 	}
490ef270ab1SKenneth D. Merry 
491ef270ab1SKenneth D. Merry 	/* Remove from node list */
492ef270ab1SKenneth D. Merry 	ocs_sport_lock(sport);
493ef270ab1SKenneth D. Merry 		ocs_list_remove(&sport->node_list, node);
494ef270ab1SKenneth D. Merry 
495ef270ab1SKenneth D. Merry 		/* Free HW resources */
496ef270ab1SKenneth D. Merry 		if (OCS_HW_RTN_IS_ERROR((rc = ocs_hw_node_free_resources(&ocs->hw, &node->rnode)))) {
497ef270ab1SKenneth D. Merry 			ocs_log_test(ocs, "ocs_hw_node_free failed: %d\n", rc);
498ef270ab1SKenneth D. Merry 			rc = -1;
499ef270ab1SKenneth D. Merry 		}
500ef270ab1SKenneth D. Merry 
501ef270ab1SKenneth D. Merry 		/* if the gidpt_delay_timer is still running, then delete it */
502ef270ab1SKenneth D. Merry 		if (ocs_timer_pending(&node->gidpt_delay_timer)) {
503ef270ab1SKenneth D. Merry 			ocs_del_timer(&node->gidpt_delay_timer);
504ef270ab1SKenneth D. Merry 		}
505ef270ab1SKenneth D. Merry 
506ef270ab1SKenneth D. Merry 		if (node->fcp2device) {
507ef270ab1SKenneth D. Merry 			ocs_del_crn(node);
508ef270ab1SKenneth D. Merry 		}
509ef270ab1SKenneth D. Merry 
510ef270ab1SKenneth D. Merry 		/* remove entry from sparse vector list */
511ef270ab1SKenneth D. Merry 		if (sport->lookup == NULL) {
512ef270ab1SKenneth D. Merry 			ocs_log_test(node->ocs, "assertion failed: sport lookup is NULL\n");
513ef270ab1SKenneth D. Merry 			ocs_sport_unlock(sport);
514ef270ab1SKenneth D. Merry 			return -1;
515ef270ab1SKenneth D. Merry 		}
516ef270ab1SKenneth D. Merry 
517ef270ab1SKenneth D. Merry 		spv_set(sport->lookup, node->rnode.fc_id, NULL);
518ef270ab1SKenneth D. Merry 
519ef270ab1SKenneth D. Merry 		/*
520ef270ab1SKenneth D. Merry 		 * If the node_list is empty, then post a ALL_CHILD_NODES_FREE event to the sport,
521ef270ab1SKenneth D. Merry 		 * after the lock is released.  The sport may be free'd as a result of the event.
522ef270ab1SKenneth D. Merry 		 */
523ef270ab1SKenneth D. Merry 		if (ocs_list_empty(&sport->node_list)) {
524ef270ab1SKenneth D. Merry 			post_all_free = TRUE;
525ef270ab1SKenneth D. Merry 		}
526ef270ab1SKenneth D. Merry 
527ef270ab1SKenneth D. Merry 	ocs_sport_unlock(sport);
528ef270ab1SKenneth D. Merry 
529ef270ab1SKenneth D. Merry 	if (post_all_free) {
530ef270ab1SKenneth D. Merry 		ocs_sm_post_event(&sport->sm, OCS_EVT_ALL_CHILD_NODES_FREE, NULL);
531ef270ab1SKenneth D. Merry 	}
532ef270ab1SKenneth D. Merry 
533ef270ab1SKenneth D. Merry 	node->sport = NULL;
534ef270ab1SKenneth D. Merry 	node->sm.current_state = NULL;
535ef270ab1SKenneth D. Merry 
536ef270ab1SKenneth D. Merry 	ocs_node_lock_free(node);
537ef270ab1SKenneth D. Merry 	ocs_lock_free(&node->pend_frames_lock);
538ef270ab1SKenneth D. Merry 	ocs_lock_free(&node->active_ios_lock);
539ef270ab1SKenneth D. Merry 
540ef270ab1SKenneth D. Merry 	/* return to free list */
541ef270ab1SKenneth D. Merry 	ocs_device_lock(ocs);
542ef270ab1SKenneth D. Merry 		ocs_list_add_tail(&xport->nodes_free_list, node);
543ef270ab1SKenneth D. Merry 	ocs_device_unlock(ocs);
544ef270ab1SKenneth D. Merry 
545ef270ab1SKenneth D. Merry 	if(ns != NULL) {
546ef270ab1SKenneth D. Merry 		/* sending fake RSCN event to name server node */
547ef270ab1SKenneth D. Merry 		ocs_node_post_event(ns, OCS_EVT_RSCN_RCVD, NULL);
548ef270ab1SKenneth D. Merry 	}
549ef270ab1SKenneth D. Merry 
550ef270ab1SKenneth D. Merry 	return rc;
551ef270ab1SKenneth D. Merry }
552ef270ab1SKenneth D. Merry 
553ef270ab1SKenneth D. Merry /**
554ef270ab1SKenneth D. Merry  * @brief free memory resources of a node object
555ef270ab1SKenneth D. Merry  *
556ef270ab1SKenneth D. Merry  * The node object's child objects are freed after which the
557ef270ab1SKenneth D. Merry  * node object is freed.
558ef270ab1SKenneth D. Merry  *
559ef270ab1SKenneth D. Merry  * @param node pointer to a node object
560ef270ab1SKenneth D. Merry  *
561ef270ab1SKenneth D. Merry  * @return none
562ef270ab1SKenneth D. Merry  */
563ef270ab1SKenneth D. Merry 
564ef270ab1SKenneth D. Merry void
ocs_node_force_free(ocs_node_t * node)565ef270ab1SKenneth D. Merry ocs_node_force_free(ocs_node_t *node)
566ef270ab1SKenneth D. Merry {
567ef270ab1SKenneth D. Merry 	ocs_io_t *io;
568ef270ab1SKenneth D. Merry 	ocs_io_t *next;
569ef270ab1SKenneth D. Merry 	ocs_io_t *els;
570ef270ab1SKenneth D. Merry 	ocs_io_t *els_next;
571ef270ab1SKenneth D. Merry 
572ef270ab1SKenneth D. Merry 	/* shutdown sm processing */
573ef270ab1SKenneth D. Merry 	ocs_sm_disable(&node->sm);
574ef270ab1SKenneth D. Merry 	ocs_strncpy(node->prev_state_name, node->current_state_name, sizeof(node->prev_state_name));
575ef270ab1SKenneth D. Merry 	ocs_strncpy(node->current_state_name, "disabled", sizeof(node->current_state_name));
576ef270ab1SKenneth D. Merry 
577ef270ab1SKenneth D. Merry 	/* Let the backend cleanup if needed */
578ef270ab1SKenneth D. Merry 	ocs_scsi_notify_node_force_free(node);
579ef270ab1SKenneth D. Merry 
580ef270ab1SKenneth D. Merry 	ocs_lock(&node->active_ios_lock);
581ef270ab1SKenneth D. Merry 		ocs_list_foreach_safe(&node->active_ios, io, next) {
582ef270ab1SKenneth D. Merry 			ocs_list_remove(&io->node->active_ios, io);
583ef270ab1SKenneth D. Merry 			ocs_io_free(node->ocs, io);
584ef270ab1SKenneth D. Merry 		}
585ef270ab1SKenneth D. Merry 	ocs_unlock(&node->active_ios_lock);
586ef270ab1SKenneth D. Merry 
587ef270ab1SKenneth D. Merry 	/* free all pending ELS IOs */
588ef270ab1SKenneth D. Merry 	ocs_lock(&node->active_ios_lock);
589ef270ab1SKenneth D. Merry 		ocs_list_foreach_safe(&node->els_io_pend_list, els, els_next) {
590ef270ab1SKenneth D. Merry 			/* can't call ocs_els_io_free() because lock is held; cleanup manually */
591ef270ab1SKenneth D. Merry 			ocs_list_remove(&node->els_io_pend_list, els);
592ef270ab1SKenneth D. Merry 
593ef270ab1SKenneth D. Merry 			ocs_io_free(node->ocs, els);
594ef270ab1SKenneth D. Merry 		}
595ef270ab1SKenneth D. Merry 	ocs_unlock(&node->active_ios_lock);
596ef270ab1SKenneth D. Merry 
597ef270ab1SKenneth D. Merry 	/* free all active ELS IOs */
598ef270ab1SKenneth D. Merry 	ocs_lock(&node->active_ios_lock);
599ef270ab1SKenneth D. Merry 		ocs_list_foreach_safe(&node->els_io_active_list, els, els_next) {
600ef270ab1SKenneth D. Merry 			/* can't call ocs_els_io_free() because lock is held; cleanup manually */
601ef270ab1SKenneth D. Merry 			ocs_list_remove(&node->els_io_active_list, els);
602ef270ab1SKenneth D. Merry 
603ef270ab1SKenneth D. Merry 			ocs_io_free(node->ocs, els);
604ef270ab1SKenneth D. Merry 		}
605ef270ab1SKenneth D. Merry 	ocs_unlock(&node->active_ios_lock);
606ef270ab1SKenneth D. Merry 
607ef270ab1SKenneth D. Merry 	/* manually purge pending frames (if any) */
608ef270ab1SKenneth D. Merry 	ocs_node_purge_pending(node);
609ef270ab1SKenneth D. Merry 
610ef270ab1SKenneth D. Merry 	ocs_node_free(node);
611ef270ab1SKenneth D. Merry }
612ef270ab1SKenneth D. Merry 
613ef270ab1SKenneth D. Merry /**
614ef270ab1SKenneth D. Merry  * @ingroup node_common
615ef270ab1SKenneth D. Merry  * @brief Perform HW call to attach a remote node
616ef270ab1SKenneth D. Merry  *
617ef270ab1SKenneth D. Merry  * @param node pointer to node object
618ef270ab1SKenneth D. Merry  *
619ef270ab1SKenneth D. Merry  * @return 0 on success, non-zero otherwise
620ef270ab1SKenneth D. Merry  */
621ef270ab1SKenneth D. Merry int32_t
ocs_node_attach(ocs_node_t * node)622ef270ab1SKenneth D. Merry ocs_node_attach(ocs_node_t *node)
623ef270ab1SKenneth D. Merry {
624ef270ab1SKenneth D. Merry 	int32_t rc = 0;
625ef270ab1SKenneth D. Merry 	ocs_sport_t *sport = node->sport;
626ef270ab1SKenneth D. Merry 	ocs_domain_t *domain = sport->domain;
627ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
628ef270ab1SKenneth D. Merry 
629ef270ab1SKenneth D. Merry 	if (!domain->attached) {
630ef270ab1SKenneth D. Merry 		ocs_log_test(ocs, "Warning: ocs_node_attach with unattached domain\n");
631ef270ab1SKenneth D. Merry 		return -1;
632ef270ab1SKenneth D. Merry 	}
633ef270ab1SKenneth D. Merry 	/* Update node->wwpn/wwnn */
634ef270ab1SKenneth D. Merry 
635ef270ab1SKenneth D. Merry 	ocs_node_build_eui_name(node->wwpn, sizeof(node->wwpn), ocs_node_get_wwpn(node));
636ef270ab1SKenneth D. Merry 	ocs_node_build_eui_name(node->wwnn, sizeof(node->wwnn), ocs_node_get_wwnn(node));
637ef270ab1SKenneth D. Merry 
638ef270ab1SKenneth D. Merry 	if (ocs->enable_hlm) {
639ef270ab1SKenneth D. Merry 		ocs_node_group_init(node);
640ef270ab1SKenneth D. Merry 	}
641ef270ab1SKenneth D. Merry 
642ef270ab1SKenneth D. Merry 	ocs_dma_copy_in(&node->sparm_dma_buf, node->service_params+4, sizeof(node->service_params)-4);
643ef270ab1SKenneth D. Merry 
644ef270ab1SKenneth D. Merry 	/* take lock to protect node->rnode.attached */
645ef270ab1SKenneth D. Merry 	ocs_node_lock(node);
646ef270ab1SKenneth D. Merry 		rc = ocs_hw_node_attach(&ocs->hw, &node->rnode, &node->sparm_dma_buf);
647ef270ab1SKenneth D. Merry 		if (OCS_HW_RTN_IS_ERROR(rc)) {
648ef270ab1SKenneth D. Merry 			ocs_log_test(ocs, "ocs_hw_node_attach failed: %d\n", rc);
649ef270ab1SKenneth D. Merry 		}
650ef270ab1SKenneth D. Merry 	ocs_node_unlock(node);
651ef270ab1SKenneth D. Merry 
652ef270ab1SKenneth D. Merry 	return rc;
653ef270ab1SKenneth D. Merry }
654ef270ab1SKenneth D. Merry 
655ef270ab1SKenneth D. Merry /**
656ef270ab1SKenneth D. Merry  * @ingroup node_common
657ef270ab1SKenneth D. Merry  * @brief Generate text for a node's fc_id
658ef270ab1SKenneth D. Merry  *
659ef270ab1SKenneth D. Merry  * The text for a nodes fc_id is generated, either as a well known name, or a 6 digit
660ef270ab1SKenneth D. Merry  * hex value.
661ef270ab1SKenneth D. Merry  *
662ef270ab1SKenneth D. Merry  * @param fc_id fc_id
663ef270ab1SKenneth D. Merry  * @param buffer text buffer
664ef270ab1SKenneth D. Merry  * @param buffer_length text buffer length in bytes
665ef270ab1SKenneth D. Merry  *
666ef270ab1SKenneth D. Merry  * @return none
667ef270ab1SKenneth D. Merry  */
668ef270ab1SKenneth D. Merry 
669ef270ab1SKenneth D. Merry void
ocs_node_fcid_display(uint32_t fc_id,char * buffer,uint32_t buffer_length)670ef270ab1SKenneth D. Merry ocs_node_fcid_display(uint32_t fc_id, char *buffer, uint32_t buffer_length)
671ef270ab1SKenneth D. Merry {
672ef270ab1SKenneth D. Merry 	switch (fc_id) {
673ef270ab1SKenneth D. Merry 	case FC_ADDR_FABRIC:
674ef270ab1SKenneth D. Merry 		ocs_snprintf(buffer, buffer_length, "fabric");
675ef270ab1SKenneth D. Merry 		break;
676ef270ab1SKenneth D. Merry 	case FC_ADDR_CONTROLLER:
677ef270ab1SKenneth D. Merry 		ocs_snprintf(buffer, buffer_length, "fabctl");
678ef270ab1SKenneth D. Merry 		break;
679ef270ab1SKenneth D. Merry 	case FC_ADDR_NAMESERVER:
680ef270ab1SKenneth D. Merry 		ocs_snprintf(buffer, buffer_length, "nserve");
681ef270ab1SKenneth D. Merry 		break;
682ef270ab1SKenneth D. Merry 	default:
683ef270ab1SKenneth D. Merry 		if (FC_ADDR_IS_DOMAIN_CTRL(fc_id)) {
684ef270ab1SKenneth D. Merry 			ocs_snprintf(buffer, buffer_length, "dctl%02x",
685ef270ab1SKenneth D. Merry 				FC_ADDR_GET_DOMAIN_CTRL(fc_id));
686ef270ab1SKenneth D. Merry 		} else {
687ef270ab1SKenneth D. Merry 			ocs_snprintf(buffer, buffer_length, "%06x", fc_id);
688ef270ab1SKenneth D. Merry 		}
689ef270ab1SKenneth D. Merry 		break;
690ef270ab1SKenneth D. Merry 	}
691ef270ab1SKenneth D. Merry 
692ef270ab1SKenneth D. Merry }
693ef270ab1SKenneth D. Merry 
694ef270ab1SKenneth D. Merry /**
695ef270ab1SKenneth D. Merry  * @brief update the node's display name
696ef270ab1SKenneth D. Merry  *
697ef270ab1SKenneth D. Merry  * The node's display name is updated, sometimes needed because the sport part
698ef270ab1SKenneth D. Merry  * is updated after the node is allocated.
699ef270ab1SKenneth D. Merry  *
700ef270ab1SKenneth D. Merry  * @param node pointer to the node object
701ef270ab1SKenneth D. Merry  *
702ef270ab1SKenneth D. Merry  * @return none
703ef270ab1SKenneth D. Merry  */
704ef270ab1SKenneth D. Merry 
705ef270ab1SKenneth D. Merry void
ocs_node_update_display_name(ocs_node_t * node)706ef270ab1SKenneth D. Merry ocs_node_update_display_name(ocs_node_t *node)
707ef270ab1SKenneth D. Merry {
708ef270ab1SKenneth D. Merry 	uint32_t port_id = node->rnode.fc_id;
709ef270ab1SKenneth D. Merry 	ocs_sport_t *sport = node->sport;
710ef270ab1SKenneth D. Merry 	char portid_display[16];
711ef270ab1SKenneth D. Merry 
712ef270ab1SKenneth D. Merry 	ocs_assert(sport);
713ef270ab1SKenneth D. Merry 
714ef270ab1SKenneth D. Merry 	ocs_node_fcid_display(port_id, portid_display, sizeof(portid_display));
715ef270ab1SKenneth D. Merry 
716ef270ab1SKenneth D. Merry 	ocs_snprintf(node->display_name, sizeof(node->display_name), "%s.%s", sport->display_name, portid_display);
717ef270ab1SKenneth D. Merry }
718ef270ab1SKenneth D. Merry 
719ef270ab1SKenneth D. Merry /**
720ef270ab1SKenneth D. Merry  * @brief cleans up an XRI for the pending link services accept by aborting the
721ef270ab1SKenneth D. Merry  *         XRI if required.
722ef270ab1SKenneth D. Merry  *
723ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
724ef270ab1SKenneth D. Merry  * This function is called when the LS accept is not sent.
725ef270ab1SKenneth D. Merry  *
726ef270ab1SKenneth D. Merry  * @param node Node for which should be cleaned up
727ef270ab1SKenneth D. Merry  */
728ef270ab1SKenneth D. Merry 
729ef270ab1SKenneth D. Merry void
ocs_node_send_ls_io_cleanup(ocs_node_t * node)730ef270ab1SKenneth D. Merry ocs_node_send_ls_io_cleanup(ocs_node_t *node)
731ef270ab1SKenneth D. Merry {
732ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
733ef270ab1SKenneth D. Merry 
734ef270ab1SKenneth D. Merry 	if (node->send_ls_acc != OCS_NODE_SEND_LS_ACC_NONE) {
735ef270ab1SKenneth D. Merry 		ocs_assert(node->ls_acc_io);
736ef270ab1SKenneth D. Merry 		ocs_log_debug(ocs, "[%s] cleaning up LS_ACC oxid=0x%x\n",
737ef270ab1SKenneth D. Merry 			node->display_name, node->ls_acc_oxid);
738ef270ab1SKenneth D. Merry 
739ef270ab1SKenneth D. Merry 		node->ls_acc_io->hio = NULL;
740ef270ab1SKenneth D. Merry 		ocs_els_io_free(node->ls_acc_io);
741ef270ab1SKenneth D. Merry 		node->send_ls_acc = OCS_NODE_SEND_LS_ACC_NONE;
742ef270ab1SKenneth D. Merry 		node->ls_acc_io = NULL;
743ef270ab1SKenneth D. Merry 	}
744ef270ab1SKenneth D. Merry }
745ef270ab1SKenneth D. Merry 
746ef270ab1SKenneth D. Merry /**
747ef270ab1SKenneth D. Merry  * @ingroup node_common
748ef270ab1SKenneth D. Merry  * @brief state: shutdown a node
749ef270ab1SKenneth D. Merry  *
750ef270ab1SKenneth D. Merry  * A node is shutdown,
751ef270ab1SKenneth D. Merry  *
752ef270ab1SKenneth D. Merry  * @param ctx remote node sm context
753ef270ab1SKenneth D. Merry  * @param evt event to process
754ef270ab1SKenneth D. Merry  * @param arg per event optional argument
755ef270ab1SKenneth D. Merry  *
756ef270ab1SKenneth D. Merry  * @return returns NULL
757ef270ab1SKenneth D. Merry  *
758ef270ab1SKenneth D. Merry  * @note
759ef270ab1SKenneth D. Merry  */
760ef270ab1SKenneth D. Merry 
761ef270ab1SKenneth D. Merry void *
__ocs_node_shutdown(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)762ef270ab1SKenneth D. Merry __ocs_node_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
763ef270ab1SKenneth D. Merry {
764ef270ab1SKenneth D. Merry 	int32_t rc;
765ef270ab1SKenneth D. Merry 	std_node_state_decl();
766ef270ab1SKenneth D. Merry 
767ef270ab1SKenneth D. Merry 	node_sm_trace();
768ef270ab1SKenneth D. Merry 
769ef270ab1SKenneth D. Merry 	switch(evt) {
770ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER: {
771ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
772ef270ab1SKenneth D. Merry 		ocs_assert(ocs_node_active_ios_empty(node), NULL);
773ef270ab1SKenneth D. Merry 		ocs_assert(ocs_els_io_list_empty(node, &node->els_io_active_list), NULL);
774ef270ab1SKenneth D. Merry 
775ef270ab1SKenneth D. Merry 		/* by default, we will be freeing node after we unwind */
776ef270ab1SKenneth D. Merry 		node->req_free = 1;
777ef270ab1SKenneth D. Merry 
778ef270ab1SKenneth D. Merry 		switch (node->shutdown_reason) {
779ef270ab1SKenneth D. Merry 		case OCS_NODE_SHUTDOWN_IMPLICIT_LOGO:
780ef270ab1SKenneth D. Merry 			/* sm: if shutdown reason is implicit logout / ocs_node_attach
781ef270ab1SKenneth D. Merry 			 * Node shutdown b/c of PLOGI received when node already
782ef270ab1SKenneth D. Merry 			 * logged in. We have PLOGI service parameters, so submit
783ef270ab1SKenneth D. Merry 			 * node attach; we won't be freeing this node
784ef270ab1SKenneth D. Merry 			 */
785ef270ab1SKenneth D. Merry 
786ef270ab1SKenneth D. Merry 			/* currently, only case for implicit logo is PLOGI recvd. Thus,
787ef270ab1SKenneth D. Merry 			 * node's ELS IO pending list won't be empty (PLOGI will be on it)
788ef270ab1SKenneth D. Merry 			 */
789ef270ab1SKenneth D. Merry 			ocs_assert(node->send_ls_acc == OCS_NODE_SEND_LS_ACC_PLOGI, NULL);
790ef270ab1SKenneth D. Merry 			node_printf(node, "Shutdown reason: implicit logout, re-authenticate\n");
791ef270ab1SKenneth D. Merry 
792ef270ab1SKenneth D. Merry 			ocs_scsi_io_alloc_enable(node);
793ef270ab1SKenneth D. Merry 
794ef270ab1SKenneth D. Merry 			/* Re-attach node with the same HW node resources */
795ef270ab1SKenneth D. Merry 			node->req_free = 0;
796ef270ab1SKenneth D. Merry 			rc = ocs_node_attach(node);
797ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_d_wait_node_attach, NULL);
798ef270ab1SKenneth D. Merry 			if (rc == OCS_HW_RTN_SUCCESS_SYNC) {
799ef270ab1SKenneth D. Merry 				ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL);
800ef270ab1SKenneth D. Merry 			}
801ef270ab1SKenneth D. Merry 			break;
802ef270ab1SKenneth D. Merry 		case OCS_NODE_SHUTDOWN_EXPLICIT_LOGO: {
803ef270ab1SKenneth D. Merry 			int8_t pend_frames_empty;
804ef270ab1SKenneth D. Merry 
805ef270ab1SKenneth D. Merry 			/* cleanup any pending LS_ACC ELSs */
806ef270ab1SKenneth D. Merry 			ocs_node_send_ls_io_cleanup(node);
807ef270ab1SKenneth D. Merry 			ocs_assert(ocs_els_io_list_empty(node, &node->els_io_pend_list), NULL);
808ef270ab1SKenneth D. Merry 
809ef270ab1SKenneth D. Merry 			ocs_lock(&node->pend_frames_lock);
810ef270ab1SKenneth D. Merry 				pend_frames_empty = ocs_list_empty(&node->pend_frames);
811ef270ab1SKenneth D. Merry 			ocs_unlock(&node->pend_frames_lock);
812ef270ab1SKenneth D. Merry 
813ef270ab1SKenneth D. Merry 			/* there are two scenarios where we want to keep this node alive:
814ef270ab1SKenneth D. Merry 			 * 1. there are pending frames that need to be processed or
815ef270ab1SKenneth D. Merry 			 * 2. we're an initiator and the remote node is a target and we
816ef270ab1SKenneth D. Merry 			 *    need to re-authenticate
817ef270ab1SKenneth D. Merry 			 */
818ef270ab1SKenneth D. Merry 			node_printf(node, "Shutdown: explicit logo pend=%d sport.ini=%d node.tgt=%d\n",
819ef270ab1SKenneth D. Merry 				    !pend_frames_empty, node->sport->enable_ini, node->targ);
820ef270ab1SKenneth D. Merry 
821ef270ab1SKenneth D. Merry 			if((!pend_frames_empty) || (node->sport->enable_ini && node->targ)) {
822ef270ab1SKenneth D. Merry 				uint8_t send_plogi = FALSE;
823ef270ab1SKenneth D. Merry 				if (node->sport->enable_ini && node->targ) {
824ef270ab1SKenneth D. Merry 					/* we're an initiator and node shutting down is a target; we'll
825ef270ab1SKenneth D. Merry 					 * need to re-authenticate in initial state
826ef270ab1SKenneth D. Merry 					 */
827ef270ab1SKenneth D. Merry 					send_plogi = TRUE;
828ef270ab1SKenneth D. Merry 				}
829ef270ab1SKenneth D. Merry 
830ef270ab1SKenneth D. Merry 				/* transition to __ocs_d_init (will retain HW node resources) */
831ef270ab1SKenneth D. Merry 				ocs_scsi_io_alloc_enable(node);
832ef270ab1SKenneth D. Merry 				node->req_free = 0;
833ef270ab1SKenneth D. Merry 
834ef270ab1SKenneth D. Merry 				/* either pending frames exist, or we're re-authenticating with PLOGI
835ef270ab1SKenneth D. Merry 				 * (or both); in either case, return to initial state
836ef270ab1SKenneth D. Merry 				 */
837ef270ab1SKenneth D. Merry 				ocs_node_init_device(node, send_plogi);
838ef270ab1SKenneth D. Merry 			}
839ef270ab1SKenneth D. Merry 			/* else: let node shutdown occur */
840ef270ab1SKenneth D. Merry 			break;
841ef270ab1SKenneth D. Merry 		}
842ef270ab1SKenneth D. Merry 		case OCS_NODE_SHUTDOWN_DEFAULT:
843ef270ab1SKenneth D. Merry 		default:
844ef270ab1SKenneth D. Merry 			/* shutdown due to link down, node going away (xport event) or
845ef270ab1SKenneth D. Merry 			 * sport shutdown, purge pending and proceed to cleanup node
846ef270ab1SKenneth D. Merry 			 */
847ef270ab1SKenneth D. Merry 
848ef270ab1SKenneth D. Merry 			/* cleanup any pending LS_ACC ELSs */
849ef270ab1SKenneth D. Merry 			ocs_node_send_ls_io_cleanup(node);
850ef270ab1SKenneth D. Merry 			ocs_assert(ocs_els_io_list_empty(node, &node->els_io_pend_list), NULL);
851ef270ab1SKenneth D. Merry 
852ef270ab1SKenneth D. Merry 			node_printf(node, "Shutdown reason: default, purge pending\n");
853ef270ab1SKenneth D. Merry 			ocs_node_purge_pending(node);
854ef270ab1SKenneth D. Merry 			break;
855ef270ab1SKenneth D. Merry 		}
856ef270ab1SKenneth D. Merry 
857ef270ab1SKenneth D. Merry 		break;
858ef270ab1SKenneth D. Merry 	}
859ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
860ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
861ef270ab1SKenneth D. Merry 		break;
862ef270ab1SKenneth D. Merry 
863ef270ab1SKenneth D. Merry 	default:
864ef270ab1SKenneth D. Merry 		__ocs_node_common(__func__, ctx, evt, arg);
865ef270ab1SKenneth D. Merry 		return NULL;
866ef270ab1SKenneth D. Merry 	}
867ef270ab1SKenneth D. Merry 
868ef270ab1SKenneth D. Merry 	return NULL;
869ef270ab1SKenneth D. Merry }
870ef270ab1SKenneth D. Merry 
871ef270ab1SKenneth D. Merry /**
872ef270ab1SKenneth D. Merry  * @ingroup common_node
873ef270ab1SKenneth D. Merry  * @brief Checks to see if ELS's have been quiesced
874ef270ab1SKenneth D. Merry  *
875ef270ab1SKenneth D. Merry  * Check if ELS's have been quiesced. If so, transition to the
876ef270ab1SKenneth D. Merry  * next state in the shutdown process.
877ef270ab1SKenneth D. Merry  *
878ef270ab1SKenneth D. Merry  * @param node Node for which ELS's are checked
879ef270ab1SKenneth D. Merry  *
880ef270ab1SKenneth D. Merry  * @return Returns 1 if ELS's have been quiesced, 0 otherwise.
881ef270ab1SKenneth D. Merry  */
882ef270ab1SKenneth D. Merry static int
ocs_node_check_els_quiesced(ocs_node_t * node)883ef270ab1SKenneth D. Merry ocs_node_check_els_quiesced(ocs_node_t *node)
884ef270ab1SKenneth D. Merry {
885ef270ab1SKenneth D. Merry 	ocs_assert(node, -1);
886ef270ab1SKenneth D. Merry 
887ef270ab1SKenneth D. Merry 	/* check to see if ELS requests, completions are quiesced */
888ef270ab1SKenneth D. Merry 	if ((node->els_req_cnt == 0) && (node->els_cmpl_cnt == 0) &&
889ef270ab1SKenneth D. Merry 	    ocs_els_io_list_empty(node, &node->els_io_active_list)) {
890ef270ab1SKenneth D. Merry 		if (!node->attached) {
891ef270ab1SKenneth D. Merry 			/* hw node detach already completed, proceed */
892ef270ab1SKenneth D. Merry 			node_printf(node, "HW node not attached\n");
893ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_node_wait_ios_shutdown, NULL);
894ef270ab1SKenneth D. Merry 		} else {
895ef270ab1SKenneth D. Merry 			/* hw node detach hasn't completed, transition and wait */
896ef270ab1SKenneth D. Merry 			node_printf(node, "HW node still attached\n");
897ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_node_wait_node_free, NULL);
898ef270ab1SKenneth D. Merry 		}
899ef270ab1SKenneth D. Merry 		return 1;
900ef270ab1SKenneth D. Merry 	}
901ef270ab1SKenneth D. Merry 	return 0;
902ef270ab1SKenneth D. Merry }
903ef270ab1SKenneth D. Merry 
904ef270ab1SKenneth D. Merry /**
905ef270ab1SKenneth D. Merry  * @ingroup common_node
906ef270ab1SKenneth D. Merry  * @brief Initiate node IO cleanup.
907ef270ab1SKenneth D. Merry  *
908ef270ab1SKenneth D. Merry  * Note: this function must be called with a non-attached node
909ef270ab1SKenneth D. Merry  * or a node for which the node detach (ocs_hw_node_detach())
910ef270ab1SKenneth D. Merry  * has already been initiated.
911ef270ab1SKenneth D. Merry  *
912ef270ab1SKenneth D. Merry  * @param node Node for which shutdown is initiated
913ef270ab1SKenneth D. Merry  *
914ef270ab1SKenneth D. Merry  * @return Returns None.
915ef270ab1SKenneth D. Merry  */
916ef270ab1SKenneth D. Merry 
917ef270ab1SKenneth D. Merry void
ocs_node_initiate_cleanup(ocs_node_t * node)918ef270ab1SKenneth D. Merry ocs_node_initiate_cleanup(ocs_node_t *node)
919ef270ab1SKenneth D. Merry {
920ef270ab1SKenneth D. Merry 	ocs_io_t *els;
921ef270ab1SKenneth D. Merry 	ocs_io_t *els_next;
922ef270ab1SKenneth D. Merry 	ocs_t *ocs;
923ef270ab1SKenneth D. Merry 	ocs_assert(node);
924ef270ab1SKenneth D. Merry 	ocs = node->ocs;
925ef270ab1SKenneth D. Merry 
926ef270ab1SKenneth D. Merry 	/* first cleanup ELS's that are pending (not yet active) */
927ef270ab1SKenneth D. Merry 	ocs_lock(&node->active_ios_lock);
928ef270ab1SKenneth D. Merry 		ocs_list_foreach_safe(&node->els_io_pend_list, els, els_next) {
929ef270ab1SKenneth D. Merry 			/* skip the ELS IO for which a response will be sent after shutdown */
930ef270ab1SKenneth D. Merry 			if ((node->send_ls_acc != OCS_NODE_SEND_LS_ACC_NONE) &&
931ef270ab1SKenneth D. Merry 			    (els == node->ls_acc_io)) {
932ef270ab1SKenneth D. Merry 				continue;
933ef270ab1SKenneth D. Merry 			}
934ef270ab1SKenneth D. Merry 			/* can't call ocs_els_io_free() because lock is held; cleanup manually */
935ef270ab1SKenneth D. Merry                         node_printf(node, "Freeing pending els %s\n", els->display_name);
936ef270ab1SKenneth D. Merry 			ocs_list_remove(&node->els_io_pend_list, els);
937ef270ab1SKenneth D. Merry 
938ef270ab1SKenneth D. Merry 			ocs_io_free(node->ocs, els);
939ef270ab1SKenneth D. Merry 		}
940ef270ab1SKenneth D. Merry 	ocs_unlock(&node->active_ios_lock);
941ef270ab1SKenneth D. Merry 
942ef270ab1SKenneth D. Merry 	if (node->ls_acc_io && node->ls_acc_io->hio != NULL) {
943ef270ab1SKenneth D. Merry 		/*
944ef270ab1SKenneth D. Merry 		 * if there's an IO that will result in an LS_ACC after
945ef270ab1SKenneth D. Merry 		 * shutdown and its HW IO is non-NULL, it better be an
946ef270ab1SKenneth D. Merry 		 * implicit logout in vanilla sequence coalescing. In this
947ef270ab1SKenneth D. Merry 		 * case, force the LS_ACC to go out on another XRI (hio)
948ef270ab1SKenneth D. Merry 		 * since the previous will have been aborted by the UNREG_RPI
949ef270ab1SKenneth D. Merry 		 */
950ef270ab1SKenneth D. Merry 		ocs_assert(node->shutdown_reason == OCS_NODE_SHUTDOWN_IMPLICIT_LOGO);
951ef270ab1SKenneth D. Merry 		ocs_assert(node->send_ls_acc == OCS_NODE_SEND_LS_ACC_PLOGI);
952ef270ab1SKenneth D. Merry 		node_printf(node, "invalidating ls_acc_io due to implicit logo\n");
953ef270ab1SKenneth D. Merry 
954ef270ab1SKenneth D. Merry 		/* No need to abort because the unreg_rpi takes care of it, just free */
955ef270ab1SKenneth D. Merry 		ocs_hw_io_free(&ocs->hw, node->ls_acc_io->hio);
956ef270ab1SKenneth D. Merry 
957ef270ab1SKenneth D. Merry 		/* NULL out hio to force the LS_ACC to grab a new XRI */
958ef270ab1SKenneth D. Merry 		node->ls_acc_io->hio = NULL;
959ef270ab1SKenneth D. Merry 	}
960ef270ab1SKenneth D. Merry 
961ef270ab1SKenneth D. Merry 	/*
962ef270ab1SKenneth D. Merry 	 * if ELS's have already been quiesced, will move to next state
963ef270ab1SKenneth D. Merry 	 * if ELS's have not been quiesced, abort them
964ef270ab1SKenneth D. Merry 	 */
965ef270ab1SKenneth D. Merry 	if (ocs_node_check_els_quiesced(node) == 0) {
966ef270ab1SKenneth D. Merry 		/*
967ef270ab1SKenneth D. Merry 		 * Abort all ELS's since ELS's won't be aborted by HW
968ef270ab1SKenneth D. Merry 		 * node free.
969ef270ab1SKenneth D. Merry 		 */
970ef270ab1SKenneth D. Merry 		ocs_node_abort_all_els(node);
971ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_node_wait_els_shutdown, NULL);
972ef270ab1SKenneth D. Merry 	}
973ef270ab1SKenneth D. Merry }
974ef270ab1SKenneth D. Merry 
975ef270ab1SKenneth D. Merry /**
976ef270ab1SKenneth D. Merry  * @ingroup node_common
977ef270ab1SKenneth D. Merry  * @brief Node state machine: Wait for all ELSs to complete.
978ef270ab1SKenneth D. Merry  *
979ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
980ef270ab1SKenneth D. Merry  * State waits for all ELSs to complete after aborting all
981ef270ab1SKenneth D. Merry  * outstanding .
982ef270ab1SKenneth D. Merry  *
983ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
984ef270ab1SKenneth D. Merry  * @param evt Event to process.
985ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
986ef270ab1SKenneth D. Merry  *
987ef270ab1SKenneth D. Merry  * @return Returns NULL.
988ef270ab1SKenneth D. Merry  */
989ef270ab1SKenneth D. Merry 
990ef270ab1SKenneth D. Merry void *
__ocs_node_wait_els_shutdown(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)991ef270ab1SKenneth D. Merry __ocs_node_wait_els_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
992ef270ab1SKenneth D. Merry {
993ef270ab1SKenneth D. Merry 	uint8_t check_quiesce = FALSE;
994ef270ab1SKenneth D. Merry 	std_node_state_decl();
995ef270ab1SKenneth D. Merry 
996ef270ab1SKenneth D. Merry 	node_sm_trace();
997ef270ab1SKenneth D. Merry 
998ef270ab1SKenneth D. Merry 	switch(evt) {
999ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER: {
1000ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
1001ef270ab1SKenneth D. Merry 		if (ocs_els_io_list_empty(node, &node->els_io_active_list)) {
1002ef270ab1SKenneth D. Merry 			node_printf(node, "All ELS IOs complete\n");
1003ef270ab1SKenneth D. Merry 			check_quiesce = TRUE;
1004ef270ab1SKenneth D. Merry 		}
1005ef270ab1SKenneth D. Merry 		break;
1006ef270ab1SKenneth D. Merry 	}
1007ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
1008ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
1009ef270ab1SKenneth D. Merry 		break;
1010ef270ab1SKenneth D. Merry 
1011ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_OK:
1012ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_FAIL:
1013ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_RJT:
1014ef270ab1SKenneth D. Merry 	case OCS_EVT_ELS_REQ_ABORTED:
1015ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
1016ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
1017ef270ab1SKenneth D. Merry 		check_quiesce = TRUE;
1018ef270ab1SKenneth D. Merry 		break;
1019ef270ab1SKenneth D. Merry 
1020ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_CMPL_OK:
1021ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_CMPL_FAIL:
1022ef270ab1SKenneth D. Merry 		ocs_assert(node->els_cmpl_cnt, NULL);
1023ef270ab1SKenneth D. Merry 		node->els_cmpl_cnt--;
1024ef270ab1SKenneth D. Merry 		check_quiesce = TRUE;
1025ef270ab1SKenneth D. Merry 		break;
1026ef270ab1SKenneth D. Merry 
1027ef270ab1SKenneth D. Merry 	case OCS_EVT_ALL_CHILD_NODES_FREE:
1028ef270ab1SKenneth D. Merry 		/* all ELS IO's complete */
1029ef270ab1SKenneth D. Merry 		node_printf(node, "All ELS IOs complete\n");
1030ef270ab1SKenneth D. Merry 		ocs_assert(ocs_els_io_list_empty(node, &node->els_io_active_list), NULL);
1031ef270ab1SKenneth D. Merry 		check_quiesce = TRUE;
1032ef270ab1SKenneth D. Merry 		break;
1033ef270ab1SKenneth D. Merry 
1034ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
1035ef270ab1SKenneth D. Merry 		break;
1036ef270ab1SKenneth D. Merry 
1037ef270ab1SKenneth D. Merry 	case OCS_EVT_DOMAIN_ATTACH_OK:
1038ef270ab1SKenneth D. Merry 		/* don't care about domain_attach_ok */
1039ef270ab1SKenneth D. Merry 		break;
1040ef270ab1SKenneth D. Merry 
1041ef270ab1SKenneth D. Merry 	/* ignore shutdown events as we're already in shutdown path */
1042ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN:
1043ef270ab1SKenneth D. Merry 		/* have default shutdown event take precedence */
1044ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1045ef270ab1SKenneth D. Merry 		/* fall through */
1046ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO:
1047ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO:
1048ef270ab1SKenneth D. Merry 		node_printf(node, "%s received\n", ocs_sm_event_name(evt));
1049ef270ab1SKenneth D. Merry 		break;
1050ef270ab1SKenneth D. Merry 
1051ef270ab1SKenneth D. Merry 	default:
1052ef270ab1SKenneth D. Merry 		__ocs_node_common(__func__, ctx, evt, arg);
1053ef270ab1SKenneth D. Merry 		return NULL;
1054ef270ab1SKenneth D. Merry 	}
1055ef270ab1SKenneth D. Merry 
1056ef270ab1SKenneth D. Merry 	if (check_quiesce) {
1057ef270ab1SKenneth D. Merry 		ocs_node_check_els_quiesced(node);
1058ef270ab1SKenneth D. Merry 	}
1059ef270ab1SKenneth D. Merry 	return NULL;
1060ef270ab1SKenneth D. Merry }
1061ef270ab1SKenneth D. Merry 
1062ef270ab1SKenneth D. Merry /**
1063ef270ab1SKenneth D. Merry  * @ingroup node_command
1064ef270ab1SKenneth D. Merry  * @brief Node state machine: Wait for a HW node free event to
1065ef270ab1SKenneth D. Merry  * complete.
1066ef270ab1SKenneth D. Merry  *
1067ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1068ef270ab1SKenneth D. Merry  * State waits for the node free event to be received from the HW.
1069ef270ab1SKenneth D. Merry  *
1070ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
1071ef270ab1SKenneth D. Merry  * @param evt Event to process.
1072ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
1073ef270ab1SKenneth D. Merry  *
1074ef270ab1SKenneth D. Merry  * @return Returns NULL.
1075ef270ab1SKenneth D. Merry  */
1076ef270ab1SKenneth D. Merry 
1077ef270ab1SKenneth D. Merry void *
__ocs_node_wait_node_free(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)1078ef270ab1SKenneth D. Merry __ocs_node_wait_node_free(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1079ef270ab1SKenneth D. Merry {
1080ef270ab1SKenneth D. Merry 	std_node_state_decl();
1081ef270ab1SKenneth D. Merry 
1082ef270ab1SKenneth D. Merry 	node_sm_trace();
1083ef270ab1SKenneth D. Merry 
1084ef270ab1SKenneth D. Merry 	switch(evt) {
1085ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
1086ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
1087ef270ab1SKenneth D. Merry 		break;
1088ef270ab1SKenneth D. Merry 
1089ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
1090ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
1091ef270ab1SKenneth D. Merry 		break;
1092ef270ab1SKenneth D. Merry 
1093ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_FREE_OK:
1094ef270ab1SKenneth D. Merry 		/* node is officially no longer attached */
1095ef270ab1SKenneth D. Merry 		node->attached = FALSE;
1096ef270ab1SKenneth D. Merry 		ocs_node_transition(node, __ocs_node_wait_ios_shutdown, NULL);
1097ef270ab1SKenneth D. Merry 		break;
1098ef270ab1SKenneth D. Merry 
1099ef270ab1SKenneth D. Merry 	case OCS_EVT_ALL_CHILD_NODES_FREE:
1100ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
1101ef270ab1SKenneth D. Merry 		/* As IOs and ELS IO's complete we expect to get these events */
1102ef270ab1SKenneth D. Merry 		break;
1103ef270ab1SKenneth D. Merry 
1104ef270ab1SKenneth D. Merry 	case OCS_EVT_DOMAIN_ATTACH_OK:
1105ef270ab1SKenneth D. Merry 		/* don't care about domain_attach_ok */
1106ef270ab1SKenneth D. Merry 		break;
1107ef270ab1SKenneth D. Merry 
1108ef270ab1SKenneth D. Merry 	/* ignore shutdown events as we're already in shutdown path */
1109ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN:
1110ef270ab1SKenneth D. Merry 		/* have default shutdown event take precedence */
1111ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1112ef270ab1SKenneth D. Merry 		/* Fall through */
1113ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO:
1114ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO:
1115ef270ab1SKenneth D. Merry 		node_printf(node, "%s received\n", ocs_sm_event_name(evt));
1116ef270ab1SKenneth D. Merry 		break;
1117ef270ab1SKenneth D. Merry 	default:
1118ef270ab1SKenneth D. Merry 		__ocs_node_common(__func__, ctx, evt, arg);
1119ef270ab1SKenneth D. Merry 		return NULL;
1120ef270ab1SKenneth D. Merry 	}
1121ef270ab1SKenneth D. Merry 
1122ef270ab1SKenneth D. Merry 	return NULL;
1123ef270ab1SKenneth D. Merry }
1124ef270ab1SKenneth D. Merry 
1125ef270ab1SKenneth D. Merry /**
1126ef270ab1SKenneth D. Merry  * @ingroup node_common
1127ef270ab1SKenneth D. Merry  * @brief state: initiate node shutdown
1128ef270ab1SKenneth D. Merry  *
1129ef270ab1SKenneth D. Merry  * State is entered when a node receives a shutdown event, and it's waiting
1130ef270ab1SKenneth D. Merry  * for all the active IOs and ELS IOs associated with the node to complete.
1131ef270ab1SKenneth D. Merry  *
1132ef270ab1SKenneth D. Merry  * @param ctx remote node sm context
1133ef270ab1SKenneth D. Merry  * @param evt event to process
1134ef270ab1SKenneth D. Merry  * @param arg per event optional argument
1135ef270ab1SKenneth D. Merry  *
1136ef270ab1SKenneth D. Merry  * @return returns NULL
1137ef270ab1SKenneth D. Merry  */
1138ef270ab1SKenneth D. Merry 
1139ef270ab1SKenneth D. Merry void *
__ocs_node_wait_ios_shutdown(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)1140ef270ab1SKenneth D. Merry __ocs_node_wait_ios_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1141ef270ab1SKenneth D. Merry {
1142ef270ab1SKenneth D. Merry 	ocs_io_t *io;
1143ef270ab1SKenneth D. Merry 	ocs_io_t *next;
1144ef270ab1SKenneth D. Merry 	std_node_state_decl();
1145ef270ab1SKenneth D. Merry 
1146ef270ab1SKenneth D. Merry 	node_sm_trace();
1147ef270ab1SKenneth D. Merry 
1148ef270ab1SKenneth D. Merry 	switch(evt) {
1149ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
1150ef270ab1SKenneth D. Merry 		ocs_node_hold_frames(node);
1151ef270ab1SKenneth D. Merry 
1152ef270ab1SKenneth D. Merry 		/* first check to see if no ELS IOs are outstanding */
1153ef270ab1SKenneth D. Merry 		if (ocs_els_io_list_empty(node, &node->els_io_active_list)) {
1154ef270ab1SKenneth D. Merry 			/* If there are any active IOS, Free them. */
1155ef270ab1SKenneth D. Merry 			if (!ocs_node_active_ios_empty(node)) {
1156ef270ab1SKenneth D. Merry 				ocs_lock(&node->active_ios_lock);
1157ef270ab1SKenneth D. Merry 				ocs_list_foreach_safe(&node->active_ios, io, next) {
1158ef270ab1SKenneth D. Merry 					ocs_list_remove(&io->node->active_ios, io);
1159ef270ab1SKenneth D. Merry 					ocs_io_free(node->ocs, io);
1160ef270ab1SKenneth D. Merry 				}
1161ef270ab1SKenneth D. Merry 				ocs_unlock(&node->active_ios_lock);
1162ef270ab1SKenneth D. Merry 			}
1163ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_node_shutdown, NULL);
1164ef270ab1SKenneth D. Merry 		}
1165ef270ab1SKenneth D. Merry 		break;
1166ef270ab1SKenneth D. Merry 
1167ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
1168ef270ab1SKenneth D. Merry 	case OCS_EVT_ALL_CHILD_NODES_FREE: {
1169ef270ab1SKenneth D. Merry 		if (ocs_node_active_ios_empty(node) &&
1170ef270ab1SKenneth D. Merry 		    ocs_els_io_list_empty(node, &node->els_io_active_list)) {
1171ef270ab1SKenneth D. Merry 			ocs_node_transition(node, __ocs_node_shutdown, NULL);
1172ef270ab1SKenneth D. Merry 		}
1173ef270ab1SKenneth D. Merry 		break;
1174ef270ab1SKenneth D. Merry 	}
1175ef270ab1SKenneth D. Merry 
1176ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
1177ef270ab1SKenneth D. Merry 		ocs_node_accept_frames(node);
1178ef270ab1SKenneth D. Merry 		break;
1179ef270ab1SKenneth D. Merry 
1180ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_FAIL:
1181ef270ab1SKenneth D. Merry 		/* Can happen as ELS IO IO's complete */
1182ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
1183ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
1184ef270ab1SKenneth D. Merry 		break;
1185ef270ab1SKenneth D. Merry 
1186ef270ab1SKenneth D. Merry 	/* ignore shutdown events as we're already in shutdown path */
1187ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN:
1188ef270ab1SKenneth D. Merry 		/* have default shutdown event take precedence */
1189ef270ab1SKenneth D. Merry 		node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1190ef270ab1SKenneth D. Merry 		/* fall through */
1191ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO:
1192ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO:
1193ef270ab1SKenneth D. Merry 		ocs_log_debug(ocs, "[%s] %-20s\n", node->display_name, ocs_sm_event_name(evt));
1194ef270ab1SKenneth D. Merry 		break;
1195ef270ab1SKenneth D. Merry 	case OCS_EVT_DOMAIN_ATTACH_OK:
1196ef270ab1SKenneth D. Merry 		/* don't care about domain_attach_ok */
1197ef270ab1SKenneth D. Merry 		break;
1198ef270ab1SKenneth D. Merry 	default:
1199ef270ab1SKenneth D. Merry 		__ocs_node_common(__func__, ctx, evt, arg);
1200ef270ab1SKenneth D. Merry 		return NULL;
1201ef270ab1SKenneth D. Merry 	}
1202ef270ab1SKenneth D. Merry 
1203ef270ab1SKenneth D. Merry 	return NULL;
1204ef270ab1SKenneth D. Merry }
1205ef270ab1SKenneth D. Merry 
1206ef270ab1SKenneth D. Merry /**
1207ef270ab1SKenneth D. Merry  * @ingroup node_common
1208ef270ab1SKenneth D. Merry  * @brief state: common node event handler
1209ef270ab1SKenneth D. Merry  *
1210ef270ab1SKenneth D. Merry  * Handle common/shared node events
1211ef270ab1SKenneth D. Merry  *
1212ef270ab1SKenneth D. Merry  * @param funcname calling function's name
1213ef270ab1SKenneth D. Merry  * @param ctx remote node sm context
1214ef270ab1SKenneth D. Merry  * @param evt event to process
1215ef270ab1SKenneth D. Merry  * @param arg per event optional argument
1216ef270ab1SKenneth D. Merry  *
1217ef270ab1SKenneth D. Merry  * @return returns NULL
1218ef270ab1SKenneth D. Merry  */
1219ef270ab1SKenneth D. Merry 
1220ef270ab1SKenneth D. Merry void *
__ocs_node_common(const char * funcname,ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)1221ef270ab1SKenneth D. Merry __ocs_node_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1222ef270ab1SKenneth D. Merry {
1223ef270ab1SKenneth D. Merry 	ocs_node_t *node = NULL;
1224ef270ab1SKenneth D. Merry 	ocs_t *ocs = NULL;
1225ef270ab1SKenneth D. Merry 	ocs_node_cb_t *cbdata = arg;
1226ef270ab1SKenneth D. Merry 	ocs_assert(ctx, NULL);
1227ef270ab1SKenneth D. Merry 	ocs_assert(ctx->app, NULL);
1228ef270ab1SKenneth D. Merry 	node = ctx->app;
1229ef270ab1SKenneth D. Merry 	ocs_assert(node->ocs, NULL);
1230ef270ab1SKenneth D. Merry 	ocs = node->ocs;
1231ef270ab1SKenneth D. Merry 
1232ef270ab1SKenneth D. Merry 	switch(evt) {
1233ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
1234ef270ab1SKenneth D. Merry 	case OCS_EVT_REENTER:
1235ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
1236ef270ab1SKenneth D. Merry 	case OCS_EVT_SPORT_TOPOLOGY_NOTIFY:
1237ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_MISSING:
1238ef270ab1SKenneth D. Merry 	case OCS_EVT_FCP_CMD_RCVD:
1239ef270ab1SKenneth D. Merry 		break;
1240ef270ab1SKenneth D. Merry 
1241ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_REFOUND:
1242ef270ab1SKenneth D. Merry 		node->refound = 1;
1243ef270ab1SKenneth D. Merry 		break;
1244ef270ab1SKenneth D. Merry 
1245ef270ab1SKenneth D. Merry 	/* node->attached must be set appropriately for all node attach/detach events */
1246ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ATTACH_OK:
1247ef270ab1SKenneth D. Merry 		node->attached = TRUE;
1248ef270ab1SKenneth D. Merry 		break;
1249ef270ab1SKenneth D. Merry 
1250ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_FREE_OK:
1251ef270ab1SKenneth D. Merry 	case OCS_EVT_NODE_ATTACH_FAIL:
1252ef270ab1SKenneth D. Merry 		node->attached = FALSE;
1253ef270ab1SKenneth D. Merry 		break;
1254ef270ab1SKenneth D. Merry 
1255ef270ab1SKenneth D. Merry 	/* handle any ELS completions that other states either didn't care about
1256ef270ab1SKenneth D. Merry 	 * or forgot about
1257ef270ab1SKenneth D. Merry 	 */
1258ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_CMPL_OK:
1259ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_CMPL_FAIL:
1260ef270ab1SKenneth D. Merry 		ocs_assert(node->els_cmpl_cnt, NULL);
1261ef270ab1SKenneth D. Merry 		node->els_cmpl_cnt--;
1262ef270ab1SKenneth D. Merry 		break;
1263ef270ab1SKenneth D. Merry 
1264ef270ab1SKenneth D. Merry 	/* handle any ELS request completions that other states either didn't care about
1265ef270ab1SKenneth D. Merry 	 * or forgot about
1266ef270ab1SKenneth D. Merry 	 */
1267ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_OK:
1268ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_FAIL:
1269ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_RJT:
1270ef270ab1SKenneth D. Merry 	case OCS_EVT_ELS_REQ_ABORTED:
1271ef270ab1SKenneth D. Merry 		ocs_assert(node->els_req_cnt, NULL);
1272ef270ab1SKenneth D. Merry 		node->els_req_cnt--;
1273ef270ab1SKenneth D. Merry 		break;
1274ef270ab1SKenneth D. Merry 
1275ef270ab1SKenneth D. Merry 	case OCS_EVT_ELS_RCVD: {
1276ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
1277ef270ab1SKenneth D. Merry 
1278ef270ab1SKenneth D. Merry 		/* Unsupported ELS was received, send LS_RJT, command not supported */
1279ef270ab1SKenneth D. Merry 		ocs_log_debug(ocs, "[%s] (%s) ELS x%02x, LS_RJT not supported\n",
1280ef270ab1SKenneth D. Merry 			      node->display_name, funcname, ((uint8_t*)cbdata->payload->dma.virt)[0]);
1281ef270ab1SKenneth D. Merry 		ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id),
1282ef270ab1SKenneth D. Merry 			FC_REASON_COMMAND_NOT_SUPPORTED, FC_EXPL_NO_ADDITIONAL, 0,
1283ef270ab1SKenneth D. Merry 			NULL, NULL);
1284ef270ab1SKenneth D. Merry 		break;
1285ef270ab1SKenneth D. Merry 	}
1286ef270ab1SKenneth D. Merry 
1287ef270ab1SKenneth D. Merry 	case OCS_EVT_PLOGI_RCVD:
1288ef270ab1SKenneth D. Merry 	case OCS_EVT_FLOGI_RCVD:
1289ef270ab1SKenneth D. Merry 	case OCS_EVT_LOGO_RCVD:
1290ef270ab1SKenneth D. Merry 	case OCS_EVT_PRLI_RCVD:
1291ef270ab1SKenneth D. Merry 	case OCS_EVT_PRLO_RCVD:
1292ef270ab1SKenneth D. Merry 	case OCS_EVT_PDISC_RCVD:
1293ef270ab1SKenneth D. Merry 	case OCS_EVT_FDISC_RCVD:
1294ef270ab1SKenneth D. Merry 	case OCS_EVT_ADISC_RCVD:
1295ef270ab1SKenneth D. Merry 	case OCS_EVT_RSCN_RCVD:
1296ef270ab1SKenneth D. Merry 	case OCS_EVT_SCR_RCVD: {
1297ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
1298ef270ab1SKenneth D. Merry 		/* sm: / send ELS_RJT */
1299ef270ab1SKenneth D. Merry 		ocs_log_debug(ocs, "[%s] (%s) %s sending ELS_RJT\n",
1300ef270ab1SKenneth D. Merry 			      node->display_name, funcname, ocs_sm_event_name(evt));
1301ef270ab1SKenneth D. Merry 		/* if we didn't catch this in a state, send generic LS_RJT */
1302ef270ab1SKenneth D. Merry 		ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id),
1303ef270ab1SKenneth D. Merry 			FC_REASON_UNABLE_TO_PERFORM, FC_EXPL_NO_ADDITIONAL, 0,
1304ef270ab1SKenneth D. Merry 			NULL, NULL);
1305ef270ab1SKenneth D. Merry 
1306ef270ab1SKenneth D. Merry 		break;
1307ef270ab1SKenneth D. Merry 	}
1308ef270ab1SKenneth D. Merry 	case OCS_EVT_GID_PT_RCVD:
1309ef270ab1SKenneth D. Merry 	case OCS_EVT_RFT_ID_RCVD:
1310ef270ab1SKenneth D. Merry 	case OCS_EVT_RFF_ID_RCVD: {
1311ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
1312ef270ab1SKenneth D. Merry 		ocs_log_debug(ocs, "[%s] (%s) %s sending CT_REJECT\n",
1313ef270ab1SKenneth D. Merry 			      node->display_name, funcname, ocs_sm_event_name(evt));
1314ef270ab1SKenneth D. Merry 		ocs_send_ct_rsp(cbdata->io, hdr->ox_id, cbdata->payload->dma.virt, FCCT_HDR_CMDRSP_REJECT, FCCT_COMMAND_NOT_SUPPORTED, 0);
1315ef270ab1SKenneth D. Merry 		break;
1316ef270ab1SKenneth D. Merry 	}
1317ef270ab1SKenneth D. Merry 
1318ef270ab1SKenneth D. Merry 	case OCS_EVT_ABTS_RCVD: {
1319ef270ab1SKenneth D. Merry 		fc_header_t *hdr = cbdata->header->dma.virt;
1320ef270ab1SKenneth D. Merry 		ocs_log_debug(ocs, "[%s] (%s) %s sending BA_ACC\n",
1321ef270ab1SKenneth D. Merry 			      node->display_name, funcname, ocs_sm_event_name(evt));
1322ef270ab1SKenneth D. Merry 
1323ef270ab1SKenneth D. Merry 		/* sm: send BA_ACC */
1324ef270ab1SKenneth D. Merry 		ocs_bls_send_acc_hdr(cbdata->io, hdr);
1325ef270ab1SKenneth D. Merry 		break;
1326ef270ab1SKenneth D. Merry 	}
1327ef270ab1SKenneth D. Merry 
1328ef270ab1SKenneth D. Merry 	default:
1329ef270ab1SKenneth D. Merry 		ocs_log_test(node->ocs, "[%s] %-20s %-20s not handled\n", node->display_name, funcname,
1330ef270ab1SKenneth D. Merry 			ocs_sm_event_name(evt));
1331ef270ab1SKenneth D. Merry 		break;
1332ef270ab1SKenneth D. Merry 	}
1333ef270ab1SKenneth D. Merry 	return NULL;
1334ef270ab1SKenneth D. Merry }
1335ef270ab1SKenneth D. Merry 
1336ef270ab1SKenneth D. Merry /**
1337ef270ab1SKenneth D. Merry  * @ingroup node_common
1338ef270ab1SKenneth D. Merry  * @brief save node service parameters
1339ef270ab1SKenneth D. Merry  *
1340ef270ab1SKenneth D. Merry  * Service parameters are copyed into the node structure
1341ef270ab1SKenneth D. Merry  *
1342ef270ab1SKenneth D. Merry  * @param node pointer to node structure
1343ef270ab1SKenneth D. Merry  * @param payload pointer to service parameters to save
1344ef270ab1SKenneth D. Merry  *
1345ef270ab1SKenneth D. Merry  * @return none
1346ef270ab1SKenneth D. Merry  */
1347ef270ab1SKenneth D. Merry 
1348ef270ab1SKenneth D. Merry void
ocs_node_save_sparms(ocs_node_t * node,void * payload)1349ef270ab1SKenneth D. Merry ocs_node_save_sparms(ocs_node_t *node, void *payload)
1350ef270ab1SKenneth D. Merry {
1351ef270ab1SKenneth D. Merry 	ocs_memcpy(node->service_params, payload, sizeof(node->service_params));
1352ef270ab1SKenneth D. Merry }
1353ef270ab1SKenneth D. Merry 
1354ef270ab1SKenneth D. Merry /**
1355ef270ab1SKenneth D. Merry  * @ingroup node_common
1356ef270ab1SKenneth D. Merry  * @brief Post event to node state machine context
1357ef270ab1SKenneth D. Merry  *
1358ef270ab1SKenneth D. Merry  * This is used by the node state machine code to post events to the nodes.  Upon
1359ef270ab1SKenneth D. Merry  * completion of the event posting, if the nesting depth is zero and we're not holding
1360ef270ab1SKenneth D. Merry  * inbound frames, then the pending frames are processed.
1361ef270ab1SKenneth D. Merry  *
1362ef270ab1SKenneth D. Merry  * @param node pointer to node
1363ef270ab1SKenneth D. Merry  * @param evt event to post
1364ef270ab1SKenneth D. Merry  * @param arg event posting argument
1365ef270ab1SKenneth D. Merry  *
1366ef270ab1SKenneth D. Merry  * @return none
1367ef270ab1SKenneth D. Merry  */
1368ef270ab1SKenneth D. Merry 
1369ef270ab1SKenneth D. Merry void
ocs_node_post_event(ocs_node_t * node,ocs_sm_event_t evt,void * arg)1370ef270ab1SKenneth D. Merry ocs_node_post_event(ocs_node_t *node, ocs_sm_event_t evt, void *arg)
1371ef270ab1SKenneth D. Merry {
1372ef270ab1SKenneth D. Merry 	int free_node = FALSE;
1373ef270ab1SKenneth D. Merry 	ocs_assert(node);
1374ef270ab1SKenneth D. Merry 
1375ef270ab1SKenneth D. Merry 	ocs_node_lock(node);
1376ef270ab1SKenneth D. Merry 		node->evtdepth ++;
1377ef270ab1SKenneth D. Merry 
1378ef270ab1SKenneth D. Merry 		ocs_sm_post_event(&node->sm, evt, arg);
1379ef270ab1SKenneth D. Merry 
1380ef270ab1SKenneth D. Merry 		/* If our event call depth is one and we're not holding frames
1381ef270ab1SKenneth D. Merry 		 * then we can dispatch any pending frames.   We don't want to allow
1382ef270ab1SKenneth D. Merry 		 * the ocs_process_node_pending() call to recurse.
1383ef270ab1SKenneth D. Merry 		 */
1384ef270ab1SKenneth D. Merry 		if (!node->hold_frames && (node->evtdepth == 1)) {
1385ef270ab1SKenneth D. Merry 			ocs_process_node_pending(node);
1386ef270ab1SKenneth D. Merry 		}
1387ef270ab1SKenneth D. Merry 		node->evtdepth --;
1388ef270ab1SKenneth D. Merry 
1389ef270ab1SKenneth D. Merry 		/* Free the node object if so requested, and we're at an event
1390ef270ab1SKenneth D. Merry 		 * call depth of zero
1391ef270ab1SKenneth D. Merry 		 */
1392ef270ab1SKenneth D. Merry 		if ((node->evtdepth == 0) && node->req_free) {
1393ef270ab1SKenneth D. Merry 			free_node = TRUE;
1394ef270ab1SKenneth D. Merry 		}
1395ef270ab1SKenneth D. Merry 	ocs_node_unlock(node);
1396ef270ab1SKenneth D. Merry 
1397ef270ab1SKenneth D. Merry 	if (free_node) {
1398ef270ab1SKenneth D. Merry 		ocs_node_free(node);
1399ef270ab1SKenneth D. Merry 	}
1400ef270ab1SKenneth D. Merry 
1401ef270ab1SKenneth D. Merry 	return;
1402ef270ab1SKenneth D. Merry }
1403ef270ab1SKenneth D. Merry 
1404ef270ab1SKenneth D. Merry /**
1405ef270ab1SKenneth D. Merry  * @ingroup node_common
1406ef270ab1SKenneth D. Merry  * @brief transition state of a node
1407ef270ab1SKenneth D. Merry  *
1408ef270ab1SKenneth D. Merry  * The node's state is transitioned to the requested state.  Entry/Exit
1409ef270ab1SKenneth D. Merry  * events are posted as needed.
1410ef270ab1SKenneth D. Merry  *
1411ef270ab1SKenneth D. Merry  * @param node pointer to node
1412ef270ab1SKenneth D. Merry  * @param state state to transition to
1413ef270ab1SKenneth D. Merry  * @param data transition data
1414ef270ab1SKenneth D. Merry  *
1415ef270ab1SKenneth D. Merry  * @return none
1416ef270ab1SKenneth D. Merry  */
1417ef270ab1SKenneth D. Merry 
1418ef270ab1SKenneth D. Merry void
ocs_node_transition(ocs_node_t * node,ocs_sm_function_t state,void * data)1419ef270ab1SKenneth D. Merry ocs_node_transition(ocs_node_t *node, ocs_sm_function_t state, void *data)
1420ef270ab1SKenneth D. Merry {
1421ef270ab1SKenneth D. Merry 	ocs_sm_ctx_t *ctx = &node->sm;
1422ef270ab1SKenneth D. Merry 
1423ef270ab1SKenneth D. Merry 	ocs_node_lock(node);
1424ef270ab1SKenneth D. Merry 		if (ctx->current_state == state) {
1425ef270ab1SKenneth D. Merry 			ocs_node_post_event(node, OCS_EVT_REENTER, data);
1426ef270ab1SKenneth D. Merry 		} else {
1427ef270ab1SKenneth D. Merry 			ocs_node_post_event(node, OCS_EVT_EXIT, data);
1428ef270ab1SKenneth D. Merry 			ctx->current_state = state;
1429ef270ab1SKenneth D. Merry 			ocs_node_post_event(node, OCS_EVT_ENTER, data);
1430ef270ab1SKenneth D. Merry 		}
1431ef270ab1SKenneth D. Merry 	ocs_node_unlock(node);
1432ef270ab1SKenneth D. Merry }
1433ef270ab1SKenneth D. Merry 
1434ef270ab1SKenneth D. Merry /**
1435ef270ab1SKenneth D. Merry  * @ingroup node_common
1436ef270ab1SKenneth D. Merry  * @brief build EUI formatted WWN
1437ef270ab1SKenneth D. Merry  *
1438ef270ab1SKenneth D. Merry  * Build a WWN given the somewhat transport agnostic iScsi naming specification, for FC
1439ef270ab1SKenneth D. Merry  * use the eui. format, an ascii string such as: "eui.10000000C9A19501"
1440ef270ab1SKenneth D. Merry  *
1441ef270ab1SKenneth D. Merry  * @param buffer buffer to place formatted name into
1442ef270ab1SKenneth D. Merry  * @param buffer_len length in bytes of the buffer
1443ef270ab1SKenneth D. Merry  * @param eui_name cpu endian 64 bit WWN value
1444ef270ab1SKenneth D. Merry  *
1445ef270ab1SKenneth D. Merry  * @return none
1446ef270ab1SKenneth D. Merry  */
1447ef270ab1SKenneth D. Merry 
1448ef270ab1SKenneth D. Merry void
ocs_node_build_eui_name(char * buffer,uint32_t buffer_len,uint64_t eui_name)1449ef270ab1SKenneth D. Merry ocs_node_build_eui_name(char *buffer, uint32_t buffer_len, uint64_t eui_name)
1450ef270ab1SKenneth D. Merry {
1451ef270ab1SKenneth D. Merry 	ocs_memset(buffer, 0, buffer_len);
1452ef270ab1SKenneth D. Merry 
1453ef270ab1SKenneth D. Merry 	ocs_snprintf(buffer, buffer_len, "eui.%016llx", (unsigned long long)eui_name);
1454ef270ab1SKenneth D. Merry }
1455ef270ab1SKenneth D. Merry 
1456ef270ab1SKenneth D. Merry /**
1457ef270ab1SKenneth D. Merry  * @ingroup node_common
1458ef270ab1SKenneth D. Merry  * @brief return nodes' WWPN as a uint64_t
1459ef270ab1SKenneth D. Merry  *
1460ef270ab1SKenneth D. Merry  * The WWPN is computed from service parameters and returned as a uint64_t
1461ef270ab1SKenneth D. Merry  *
1462ef270ab1SKenneth D. Merry  * @param node pointer to node structure
1463ef270ab1SKenneth D. Merry  *
1464ef270ab1SKenneth D. Merry  * @return WWPN
1465ef270ab1SKenneth D. Merry  *
1466ef270ab1SKenneth D. Merry  */
1467ef270ab1SKenneth D. Merry 
1468ef270ab1SKenneth D. Merry uint64_t
ocs_node_get_wwpn(ocs_node_t * node)1469ef270ab1SKenneth D. Merry ocs_node_get_wwpn(ocs_node_t *node)
1470ef270ab1SKenneth D. Merry {
1471ef270ab1SKenneth D. Merry 	fc_plogi_payload_t *sp = (fc_plogi_payload_t*) node->service_params;
1472ef270ab1SKenneth D. Merry 
1473ef270ab1SKenneth D. Merry 	return (((uint64_t)ocs_be32toh(sp->port_name_hi) << 32ll) | (ocs_be32toh(sp->port_name_lo)));
1474ef270ab1SKenneth D. Merry }
1475ef270ab1SKenneth D. Merry 
1476ef270ab1SKenneth D. Merry /**
1477ef270ab1SKenneth D. Merry  * @ingroup node_common
1478ef270ab1SKenneth D. Merry  * @brief return nodes' WWNN as a uint64_t
1479ef270ab1SKenneth D. Merry  *
1480ef270ab1SKenneth D. Merry  * The WWNN is computed from service parameters and returned as a uint64_t
1481ef270ab1SKenneth D. Merry  *
1482ef270ab1SKenneth D. Merry  * @param node pointer to node structure
1483ef270ab1SKenneth D. Merry  *
1484ef270ab1SKenneth D. Merry  * @return WWNN
1485ef270ab1SKenneth D. Merry  *
1486ef270ab1SKenneth D. Merry  */
1487ef270ab1SKenneth D. Merry 
1488ef270ab1SKenneth D. Merry uint64_t
ocs_node_get_wwnn(ocs_node_t * node)1489ef270ab1SKenneth D. Merry ocs_node_get_wwnn(ocs_node_t *node)
1490ef270ab1SKenneth D. Merry {
1491ef270ab1SKenneth D. Merry 	fc_plogi_payload_t *sp = (fc_plogi_payload_t*) node->service_params;
1492ef270ab1SKenneth D. Merry 
1493ef270ab1SKenneth D. Merry 	return (((uint64_t)ocs_be32toh(sp->node_name_hi) << 32ll) | (ocs_be32toh(sp->node_name_lo)));
1494ef270ab1SKenneth D. Merry }
1495ef270ab1SKenneth D. Merry 
1496ef270ab1SKenneth D. Merry /**
1497ef270ab1SKenneth D. Merry  * @brief Generate node ddump data
1498ef270ab1SKenneth D. Merry  *
1499ef270ab1SKenneth D. Merry  * Generates the node ddumpdata
1500ef270ab1SKenneth D. Merry  *
1501ef270ab1SKenneth D. Merry  * @param textbuf pointer to text buffer
1502ef270ab1SKenneth D. Merry  * @param node pointer to node context
1503ef270ab1SKenneth D. Merry  *
1504ef270ab1SKenneth D. Merry  * @return Returns 0 on success, or a negative value on failure.
1505ef270ab1SKenneth D. Merry  */
1506ef270ab1SKenneth D. Merry 
1507ef270ab1SKenneth D. Merry int
ocs_ddump_node(ocs_textbuf_t * textbuf,ocs_node_t * node)1508ef270ab1SKenneth D. Merry ocs_ddump_node(ocs_textbuf_t *textbuf, ocs_node_t *node)
1509ef270ab1SKenneth D. Merry {
1510ef270ab1SKenneth D. Merry 	ocs_io_t *io;
1511ef270ab1SKenneth D. Merry 	ocs_io_t *els;
1512ef270ab1SKenneth D. Merry 	int retval = 0;
1513ef270ab1SKenneth D. Merry 
1514ef270ab1SKenneth D. Merry 	ocs_ddump_section(textbuf, "node", node->instance_index);
1515ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "display_name", "%s", node->display_name);
1516ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "current_state", "%s", node->current_state_name);
1517ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "prev_state", "%s", node->prev_state_name);
1518ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "current_evt", "%s", ocs_sm_event_name(node->current_evt));
1519ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "prev_evt", "%s", ocs_sm_event_name(node->prev_evt));
1520ef270ab1SKenneth D. Merry 
1521ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "indicator", "%#x", node->rnode.indicator);
1522ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "fc_id", "%#06x", node->rnode.fc_id);
1523ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "attached", "%d", node->rnode.attached);
1524ef270ab1SKenneth D. Merry 
1525ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "hold_frames", "%d", node->hold_frames);
1526ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "io_alloc_enabled", "%d", node->io_alloc_enabled);
1527ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "shutdown_reason", "%d", node->shutdown_reason);
1528ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "send_ls_acc", "%d", node->send_ls_acc);
1529ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "ls_acc_did", "%d", node->ls_acc_did);
1530ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "ls_acc_oxid", "%#04x", node->ls_acc_oxid);
1531ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "req_free", "%d", node->req_free);
1532ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "els_req_cnt", "%d", node->els_req_cnt);
1533ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "els_cmpl_cnt", "%d", node->els_cmpl_cnt);
1534ef270ab1SKenneth D. Merry 
1535ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "targ", "%d", node->targ);
1536ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "init", "%d", node->init);
1537ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "wwnn", "%s", node->wwnn);
1538ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "wwpn", "%s", node->wwpn);
1539ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "login_state", "%d", (node->sm.current_state == __ocs_d_device_ready) ? 1 : 0);
1540ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "chained_io_count", "%d", node->chained_io_count);
1541ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "abort_cnt", "%d", node->abort_cnt);
1542ef270ab1SKenneth D. Merry 
1543ef270ab1SKenneth D. Merry 	ocs_display_sparams(NULL, "node_sparams", 1, textbuf, node->service_params+4);
1544ef270ab1SKenneth D. Merry 
1545ef270ab1SKenneth D. Merry 	ocs_lock(&node->pend_frames_lock);
1546ef270ab1SKenneth D. Merry 		if (!ocs_list_empty(&node->pend_frames)) {
1547ef270ab1SKenneth D. Merry 			ocs_hw_sequence_t *frame;
1548ef270ab1SKenneth D. Merry 			ocs_ddump_section(textbuf, "pending_frames", 0);
1549ef270ab1SKenneth D. Merry 			ocs_list_foreach(&node->pend_frames, frame) {
1550ef270ab1SKenneth D. Merry 				fc_header_t *hdr;
1551ef270ab1SKenneth D. Merry 				char buf[128];
1552ef270ab1SKenneth D. Merry 
1553ef270ab1SKenneth D. Merry 				hdr = frame->header->dma.virt;
1554ef270ab1SKenneth D. Merry 				ocs_snprintf(buf, sizeof(buf), "%02x/%04x/%04x len %zu",
1555ef270ab1SKenneth D. Merry 				 hdr->r_ctl, ocs_be16toh(hdr->ox_id), ocs_be16toh(hdr->rx_id),
1556ef270ab1SKenneth D. Merry 				 frame->payload->dma.len);
1557ef270ab1SKenneth D. Merry 				ocs_ddump_value(textbuf, "frame", "%s", buf);
1558ef270ab1SKenneth D. Merry 			}
1559ef270ab1SKenneth D. Merry 			ocs_ddump_endsection(textbuf, "pending_frames", 0);
1560ef270ab1SKenneth D. Merry 		}
1561ef270ab1SKenneth D. Merry 	ocs_unlock(&node->pend_frames_lock);
1562ef270ab1SKenneth D. Merry 
1563ef270ab1SKenneth D. Merry 	ocs_scsi_ini_ddump(textbuf, OCS_SCSI_DDUMP_NODE, node);
1564ef270ab1SKenneth D. Merry 	ocs_scsi_tgt_ddump(textbuf, OCS_SCSI_DDUMP_NODE, node);
1565ef270ab1SKenneth D. Merry 
1566ef270ab1SKenneth D. Merry 	ocs_lock(&node->active_ios_lock);
1567ef270ab1SKenneth D. Merry 		ocs_ddump_section(textbuf, "active_ios", 0);
1568ef270ab1SKenneth D. Merry 		ocs_list_foreach(&node->active_ios, io) {
1569ef270ab1SKenneth D. Merry 			ocs_ddump_io(textbuf, io);
1570ef270ab1SKenneth D. Merry 		}
1571ef270ab1SKenneth D. Merry 		ocs_ddump_endsection(textbuf, "active_ios", 0);
1572ef270ab1SKenneth D. Merry 
1573ef270ab1SKenneth D. Merry 		ocs_ddump_section(textbuf, "els_io_pend_list", 0);
1574ef270ab1SKenneth D. Merry 		ocs_list_foreach(&node->els_io_pend_list, els) {
1575ef270ab1SKenneth D. Merry 			ocs_ddump_els(textbuf, els);
1576ef270ab1SKenneth D. Merry 		}
1577ef270ab1SKenneth D. Merry 		ocs_ddump_endsection(textbuf, "els_io_pend_list", 0);
1578ef270ab1SKenneth D. Merry 
1579ef270ab1SKenneth D. Merry 		ocs_ddump_section(textbuf, "els_io_active_list", 0);
1580ef270ab1SKenneth D. Merry 		ocs_list_foreach(&node->els_io_active_list, els) {
1581ef270ab1SKenneth D. Merry 			ocs_ddump_els(textbuf, els);
1582ef270ab1SKenneth D. Merry 		}
1583ef270ab1SKenneth D. Merry 		ocs_ddump_endsection(textbuf, "els_io_active_list", 0);
1584ef270ab1SKenneth D. Merry 	ocs_unlock(&node->active_ios_lock);
1585ef270ab1SKenneth D. Merry 
1586ef270ab1SKenneth D. Merry 	ocs_ddump_endsection(textbuf, "node", node->instance_index);
1587ef270ab1SKenneth D. Merry 
1588ef270ab1SKenneth D. Merry 	return retval;
1589ef270ab1SKenneth D. Merry }
1590ef270ab1SKenneth D. Merry 
1591ef270ab1SKenneth D. Merry /**
1592ef270ab1SKenneth D. Merry  * @brief check ELS request completion
1593ef270ab1SKenneth D. Merry  *
1594ef270ab1SKenneth D. Merry  * Check ELS request completion event to make sure it's for the
1595ef270ab1SKenneth D. Merry  * ELS request we expect. If not, invoke given common event
1596ef270ab1SKenneth D. Merry  * handler and return an error.
1597ef270ab1SKenneth D. Merry  *
1598ef270ab1SKenneth D. Merry  * @param ctx state machine context
1599ef270ab1SKenneth D. Merry  * @param evt ELS request event
1600ef270ab1SKenneth D. Merry  * @param arg event argument
1601ef270ab1SKenneth D. Merry  * @param cmd ELS command expected
1602ef270ab1SKenneth D. Merry  * @param node_common_func common event handler to call if ELS
1603ef270ab1SKenneth D. Merry  *      		   doesn't match
1604ef270ab1SKenneth D. Merry  * @param funcname function name that called this
1605ef270ab1SKenneth D. Merry  *
1606ef270ab1SKenneth D. Merry  * @return zero if ELS command matches, -1 otherwise
1607ef270ab1SKenneth D. Merry  */
1608ef270ab1SKenneth D. Merry int32_t
node_check_els_req(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg,uint8_t cmd,ocs_node_common_func_t node_common_func,const char * funcname)1609ef270ab1SKenneth D. Merry node_check_els_req(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg, uint8_t cmd, ocs_node_common_func_t node_common_func, const char *funcname)
1610ef270ab1SKenneth D. Merry {
1611ef270ab1SKenneth D. Merry 	ocs_node_t *node = NULL;
1612ef270ab1SKenneth D. Merry 	ocs_t *ocs = NULL;
1613ef270ab1SKenneth D. Merry 	ocs_node_cb_t *cbdata = arg;
1614ef270ab1SKenneth D. Merry 	fc_els_gen_t *els_gen = NULL;
1615ef270ab1SKenneth D. Merry 	ocs_assert(ctx, -1);
1616ef270ab1SKenneth D. Merry 	node = ctx->app;
1617ef270ab1SKenneth D. Merry 	ocs_assert(node, -1);
1618ef270ab1SKenneth D. Merry 	ocs = node->ocs;
1619ef270ab1SKenneth D. Merry 	ocs_assert(ocs, -1);
1620ef270ab1SKenneth D. Merry 	cbdata = arg;
1621ef270ab1SKenneth D. Merry 	ocs_assert(cbdata, -1);
1622ef270ab1SKenneth D. Merry 	ocs_assert(cbdata->els, -1);
1623ef270ab1SKenneth D. Merry 	els_gen = (fc_els_gen_t *)cbdata->els->els_req.virt;
1624ef270ab1SKenneth D. Merry 	ocs_assert(els_gen, -1);
1625ef270ab1SKenneth D. Merry 
1626ef270ab1SKenneth D. Merry 	if ((cbdata->els->hio_type != OCS_HW_ELS_REQ) || (els_gen->command_code != cmd)) {
1627ef270ab1SKenneth D. Merry 		if (cbdata->els->hio_type != OCS_HW_ELS_REQ) {
1628ef270ab1SKenneth D. Merry 			ocs_log_debug(node->ocs, "[%s] %-20s expecting ELS cmd=x%x received type=%d\n",
1629ef270ab1SKenneth D. Merry 				node->display_name, funcname, cmd, cbdata->els->hio_type);
1630ef270ab1SKenneth D. Merry 		} else {
1631ef270ab1SKenneth D. Merry 			ocs_log_debug(node->ocs, "[%s] %-20s expecting ELS cmd=x%x received cmd=x%x\n",
1632ef270ab1SKenneth D. Merry 				node->display_name, funcname, cmd, els_gen->command_code);
1633ef270ab1SKenneth D. Merry 		}
1634ef270ab1SKenneth D. Merry 		/* send event to common handler */
1635ef270ab1SKenneth D. Merry 		node_common_func(funcname, ctx, evt, arg);
1636ef270ab1SKenneth D. Merry 		return -1;
1637ef270ab1SKenneth D. Merry 	}
1638ef270ab1SKenneth D. Merry 	return 0;
1639ef270ab1SKenneth D. Merry }
1640ef270ab1SKenneth D. Merry 
1641ef270ab1SKenneth D. Merry /**
1642ef270ab1SKenneth D. Merry  * @brief check NS request completion
1643ef270ab1SKenneth D. Merry  *
1644ef270ab1SKenneth D. Merry  * Check ELS request completion event to make sure it's for the
1645ef270ab1SKenneth D. Merry  * nameserver request we expect. If not, invoke given common
1646ef270ab1SKenneth D. Merry  * event handler and return an error.
1647ef270ab1SKenneth D. Merry  *
1648ef270ab1SKenneth D. Merry  * @param ctx state machine context
1649ef270ab1SKenneth D. Merry  * @param evt ELS request event
1650ef270ab1SKenneth D. Merry  * @param arg event argument
1651ef270ab1SKenneth D. Merry  * @param cmd nameserver command expected
1652ef270ab1SKenneth D. Merry  * @param node_common_func common event handler to call if
1653ef270ab1SKenneth D. Merry  *      		   nameserver cmd doesn't match
1654ef270ab1SKenneth D. Merry  * @param funcname function name that called this
1655ef270ab1SKenneth D. Merry  *
1656ef270ab1SKenneth D. Merry  * @return zero if NS command matches, -1 otherwise
1657ef270ab1SKenneth D. Merry  */
1658ef270ab1SKenneth D. Merry int32_t
node_check_ns_req(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg,uint32_t cmd,ocs_node_common_func_t node_common_func,const char * funcname)1659ef270ab1SKenneth D. Merry node_check_ns_req(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg, uint32_t cmd, ocs_node_common_func_t node_common_func, const char *funcname)
1660ef270ab1SKenneth D. Merry {
1661ef270ab1SKenneth D. Merry 	ocs_node_t *node = NULL;
1662ef270ab1SKenneth D. Merry 	ocs_t *ocs = NULL;
1663ef270ab1SKenneth D. Merry 	ocs_node_cb_t *cbdata = arg;
1664ef270ab1SKenneth D. Merry 	fcct_iu_header_t *fcct = NULL;
1665ef270ab1SKenneth D. Merry 	ocs_assert(ctx, -1);
1666ef270ab1SKenneth D. Merry 	node = ctx->app;
1667ef270ab1SKenneth D. Merry 	ocs_assert(node, -1);
1668ef270ab1SKenneth D. Merry 	ocs = node->ocs;
1669ef270ab1SKenneth D. Merry 	ocs_assert(ocs, -1);
1670ef270ab1SKenneth D. Merry 	cbdata = arg;
1671ef270ab1SKenneth D. Merry 	ocs_assert(cbdata, -1);
1672ef270ab1SKenneth D. Merry 	ocs_assert(cbdata->els, -1);
1673ef270ab1SKenneth D. Merry 	fcct = (fcct_iu_header_t *)cbdata->els->els_req.virt;
1674ef270ab1SKenneth D. Merry 	ocs_assert(fcct, -1);
1675ef270ab1SKenneth D. Merry 
1676ef270ab1SKenneth D. Merry 	if ((cbdata->els->hio_type != OCS_HW_FC_CT) || fcct->cmd_rsp_code != ocs_htobe16(cmd)) {
1677ef270ab1SKenneth D. Merry 		if (cbdata->els->hio_type != OCS_HW_FC_CT) {
1678ef270ab1SKenneth D. Merry 			ocs_log_debug(node->ocs, "[%s] %-20s expecting NS cmd=x%x received type=%d\n",
1679ef270ab1SKenneth D. Merry 				node->display_name, funcname, cmd, cbdata->els->hio_type);
1680ef270ab1SKenneth D. Merry 		} else {
1681ef270ab1SKenneth D. Merry 			ocs_log_debug(node->ocs, "[%s] %-20s expecting NS cmd=x%x received cmd=x%x\n",
1682ef270ab1SKenneth D. Merry 				node->display_name, funcname, cmd, fcct->cmd_rsp_code);
1683ef270ab1SKenneth D. Merry 		}
1684ef270ab1SKenneth D. Merry 		/* send event to common handler */
1685ef270ab1SKenneth D. Merry 		node_common_func(funcname, ctx, evt, arg);
1686ef270ab1SKenneth D. Merry 		return -1;
1687ef270ab1SKenneth D. Merry 	}
1688ef270ab1SKenneth D. Merry 	return 0;
1689ef270ab1SKenneth D. Merry }
1690ef270ab1SKenneth D. Merry 
1691ef270ab1SKenneth D. Merry void
ocs_mgmt_node_list(ocs_textbuf_t * textbuf,void * object)1692ef270ab1SKenneth D. Merry ocs_mgmt_node_list(ocs_textbuf_t *textbuf, void *object)
1693ef270ab1SKenneth D. Merry {
1694ef270ab1SKenneth D. Merry 	ocs_io_t *io;
1695ef270ab1SKenneth D. Merry 	ocs_node_t *node = (ocs_node_t *)object;
1696ef270ab1SKenneth D. Merry 
1697ef270ab1SKenneth D. Merry 	ocs_mgmt_start_section(textbuf, "node", node->instance_index);
1698ef270ab1SKenneth D. Merry 
1699ef270ab1SKenneth D. Merry 	/* Readonly values */
1700ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "display_name");
1701ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "indicator");
1702ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "fc_id");
1703ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "attached");
1704ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "hold_frames");
1705ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "shutting_down");
1706ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "req_free");
1707ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "ox_id");
1708ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "ox_id_in_use");
1709ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "abort_cnt");
1710ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "targ");
1711ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "init");
1712ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "wwpn");
1713ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "wwnn");
1714ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "pend_frames");
1715ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "chained_io_count");
1716ef270ab1SKenneth D. Merry 
1717ef270ab1SKenneth D. Merry 	/* Actions */
1718ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_EX, "resume");
1719ef270ab1SKenneth D. Merry 
1720ef270ab1SKenneth D. Merry 	ocs_lock(&node->active_ios_lock);
1721ef270ab1SKenneth D. Merry 	ocs_list_foreach(&node->active_ios, io) {
1722ef270ab1SKenneth D. Merry 		if ((io->mgmt_functions) && (io->mgmt_functions->get_list_handler)) {
1723ef270ab1SKenneth D. Merry 			io->mgmt_functions->get_list_handler(textbuf, io);
1724ef270ab1SKenneth D. Merry 		}
1725ef270ab1SKenneth D. Merry 	}
1726ef270ab1SKenneth D. Merry 	ocs_unlock(&node->active_ios_lock);
1727ef270ab1SKenneth D. Merry 
1728ef270ab1SKenneth D. Merry 	ocs_mgmt_end_section(textbuf, "node", node->instance_index);
1729ef270ab1SKenneth D. Merry }
1730ef270ab1SKenneth D. Merry 
1731ef270ab1SKenneth D. Merry int
ocs_mgmt_node_get(ocs_textbuf_t * textbuf,char * parent,char * name,void * object)1732ef270ab1SKenneth D. Merry ocs_mgmt_node_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *object)
1733ef270ab1SKenneth D. Merry {
1734ef270ab1SKenneth D. Merry 	ocs_io_t *io;
1735ef270ab1SKenneth D. Merry 	ocs_node_t *node = (ocs_node_t *)object;
1736ef270ab1SKenneth D. Merry 	char qualifier[80];
1737ef270ab1SKenneth D. Merry 	int retval = -1;
1738ef270ab1SKenneth D. Merry 
1739ef270ab1SKenneth D. Merry 	ocs_mgmt_start_section(textbuf, "node", node->instance_index);
1740ef270ab1SKenneth D. Merry 
1741ef270ab1SKenneth D. Merry 	ocs_snprintf(qualifier, sizeof(qualifier), "%s/node[%d]", parent, node->instance_index);
1742ef270ab1SKenneth D. Merry 
1743ef270ab1SKenneth D. Merry 	/* If it doesn't start with my qualifier I don't know what to do with it */
1744ef270ab1SKenneth D. Merry 	if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) {
1745ef270ab1SKenneth D. Merry 		char *unqualified_name = name + strlen(qualifier) +1;
1746ef270ab1SKenneth D. Merry 
1747ef270ab1SKenneth D. Merry 		/* See if it's a value I can supply */
1748ef270ab1SKenneth D. Merry 		if (ocs_strcmp(unqualified_name, "display_name") == 0) {
1749ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", node->display_name);
1750ef270ab1SKenneth D. Merry 			retval = 0;
1751ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "indicator") == 0) {
1752ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "indicator", "0x%x", node->rnode.indicator);
1753ef270ab1SKenneth D. Merry 			retval = 0;
1754ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "fc_id") == 0) {
1755ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fc_id", "0x%06x", node->rnode.fc_id);
1756ef270ab1SKenneth D. Merry 			retval = 0;
1757ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "attached") == 0) {
1758ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "attached", node->rnode.attached);
1759ef270ab1SKenneth D. Merry 			retval = 0;
1760ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "hold_frames") == 0) {
1761ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "hold_frames", node->hold_frames);
1762ef270ab1SKenneth D. Merry 			retval = 0;
1763ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "io_alloc_enabled") == 0) {
1764ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "io_alloc_enabled", node->io_alloc_enabled);
1765ef270ab1SKenneth D. Merry 			retval = 0;
1766ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "req_free") == 0) {
1767ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "req_free", node->req_free);
1768ef270ab1SKenneth D. Merry 			retval = 0;
1769ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "ls_acc_oxid") == 0) {
1770ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "ls_acc_oxid", "0x%#04x", node->ls_acc_oxid);
1771ef270ab1SKenneth D. Merry 			retval = 0;
1772ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "ls_acc_did") == 0) {
1773ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "ls_acc_did", "0x%#04x", node->ls_acc_did);
1774ef270ab1SKenneth D. Merry 			retval = 0;
1775ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "abort_cnt") == 0) {
1776ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "abort_cnt", "%d", node->abort_cnt);
1777ef270ab1SKenneth D. Merry 			retval = 0;
1778ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "targ") == 0) {
1779ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "targ",  node->targ);
1780ef270ab1SKenneth D. Merry 			retval = 0;
1781ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "init") == 0) {
1782ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "init",  node->init);
1783ef270ab1SKenneth D. Merry 			retval = 0;
1784ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "wwpn") == 0) {
1785ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwpn", "%s", node->wwpn);
1786ef270ab1SKenneth D. Merry 			retval = 0;
1787ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "wwnn") == 0) {
1788ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwnn", "%s", node->wwnn);
1789ef270ab1SKenneth D. Merry 			retval = 0;
1790ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "current_state") == 0) {
1791ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "current_state", node->current_state_name);
1792ef270ab1SKenneth D. Merry 			retval = 0;
1793ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "login_state") == 0) {
1794ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "login_state", "%d", (node->sm.current_state == __ocs_d_device_ready) ? 1 : 0);
1795ef270ab1SKenneth D. Merry 			retval = 0;
1796ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "pend_frames") == 0) {
1797ef270ab1SKenneth D. Merry 			ocs_hw_sequence_t *frame;
1798ef270ab1SKenneth D. Merry 			ocs_lock(&node->pend_frames_lock);
1799ef270ab1SKenneth D. Merry 				ocs_list_foreach(&node->pend_frames, frame) {
1800ef270ab1SKenneth D. Merry 					fc_header_t *hdr;
1801ef270ab1SKenneth D. Merry 					char buf[128];
1802ef270ab1SKenneth D. Merry 
1803ef270ab1SKenneth D. Merry 					hdr = frame->header->dma.virt;
1804ef270ab1SKenneth D. Merry 					ocs_snprintf(buf, sizeof(buf), "%02x/%04x/%04x len %zu", hdr->r_ctl,
1805ef270ab1SKenneth D. Merry 						 ocs_be16toh(hdr->ox_id), ocs_be16toh(hdr->rx_id),
1806ef270ab1SKenneth D. Merry 						 frame->payload->dma.len);
1807ef270ab1SKenneth D. Merry 					ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "pend_frames", buf);
1808ef270ab1SKenneth D. Merry 				}
1809ef270ab1SKenneth D. Merry 			ocs_unlock(&node->pend_frames_lock);
1810ef270ab1SKenneth D. Merry 			retval = 0;
1811ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "chained_io_count") == 0) {
1812ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "chained_io_count", "%d", node->chained_io_count);
1813ef270ab1SKenneth D. Merry 			retval = 0;
1814ef270ab1SKenneth D. Merry 		} else {
1815ef270ab1SKenneth D. Merry 			/* If I didn't know the value of this status pass the request to each of my children */
1816ef270ab1SKenneth D. Merry 			ocs_lock(&node->active_ios_lock);
1817ef270ab1SKenneth D. Merry 				ocs_list_foreach(&node->active_ios, io) {
1818ef270ab1SKenneth D. Merry 					if ((io->mgmt_functions) && (io->mgmt_functions->get_handler)) {
1819ef270ab1SKenneth D. Merry 						retval = io->mgmt_functions->get_handler(textbuf, qualifier, name, io);
1820ef270ab1SKenneth D. Merry 					}
1821ef270ab1SKenneth D. Merry 
1822ef270ab1SKenneth D. Merry 					if (retval == 0) {
1823ef270ab1SKenneth D. Merry 						break;
1824ef270ab1SKenneth D. Merry 					}
1825ef270ab1SKenneth D. Merry 				}
1826ef270ab1SKenneth D. Merry 			ocs_unlock(&node->active_ios_lock);
1827ef270ab1SKenneth D. Merry 		}
1828ef270ab1SKenneth D. Merry 	}
1829ef270ab1SKenneth D. Merry 
1830ef270ab1SKenneth D. Merry 	ocs_mgmt_end_section(textbuf, "node", node->instance_index);
1831ef270ab1SKenneth D. Merry 
1832ef270ab1SKenneth D. Merry 	return retval;
1833ef270ab1SKenneth D. Merry }
1834ef270ab1SKenneth D. Merry 
1835ef270ab1SKenneth D. Merry void
ocs_mgmt_node_get_all(ocs_textbuf_t * textbuf,void * object)1836ef270ab1SKenneth D. Merry ocs_mgmt_node_get_all(ocs_textbuf_t *textbuf, void *object)
1837ef270ab1SKenneth D. Merry {
1838ef270ab1SKenneth D. Merry 	ocs_io_t *io;
1839ef270ab1SKenneth D. Merry 	ocs_node_t *node = (ocs_node_t *)object;
1840ef270ab1SKenneth D. Merry 	ocs_hw_sequence_t *frame;
1841ef270ab1SKenneth D. Merry 
1842ef270ab1SKenneth D. Merry 	ocs_mgmt_start_section(textbuf, "node", node->instance_index);
1843ef270ab1SKenneth D. Merry 
1844ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", node->display_name);
1845ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "indicator", "0x%x", node->rnode.indicator);
1846ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fc_id", "0x%06x", node->rnode.fc_id);
1847ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "attached", node->rnode.attached);
1848ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "hold_frames", node->hold_frames);
1849ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "io_alloc_enabled", node->io_alloc_enabled);
1850ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "req_free", node->req_free);
1851ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "ls_acc_oxid", "0x%#04x", node->ls_acc_oxid);
1852ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "ls_acc_did", "0x%#04x", node->ls_acc_did);
1853ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "abort_cnt", "%d", node->abort_cnt);
1854ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "targ",  node->targ);
1855ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "init",  node->init);
1856ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwpn", "%s", node->wwpn);
1857ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwnn", "%s", node->wwnn);
1858ef270ab1SKenneth D. Merry 
1859ef270ab1SKenneth D. Merry 	ocs_lock(&node->pend_frames_lock);
1860ef270ab1SKenneth D. Merry 	ocs_list_foreach(&node->pend_frames, frame) {
1861ef270ab1SKenneth D. Merry 		fc_header_t *hdr;
1862ef270ab1SKenneth D. Merry 		char buf[128];
1863ef270ab1SKenneth D. Merry 
1864ef270ab1SKenneth D. Merry 		hdr = frame->header->dma.virt;
1865ef270ab1SKenneth D. Merry 		ocs_snprintf(buf, sizeof(buf), "%02x/%04x/%04x len %zu", hdr->r_ctl,
1866ef270ab1SKenneth D. Merry 			     ocs_be16toh(hdr->ox_id), ocs_be16toh(hdr->rx_id),
1867ef270ab1SKenneth D. Merry 			     frame->payload->dma.len);
1868ef270ab1SKenneth D. Merry 		ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "pend_frames", buf);
1869ef270ab1SKenneth D. Merry 	}
1870ef270ab1SKenneth D. Merry 	ocs_unlock(&node->pend_frames_lock);
1871ef270ab1SKenneth D. Merry 
1872ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "chained_io_count", "%d", node->chained_io_count);
1873ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_EX, "resume");
1874ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "current_state", node->current_state_name);
1875ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "login_state", "%d", (node->sm.current_state == __ocs_d_device_ready) ? 1 : 0);
1876ef270ab1SKenneth D. Merry 
1877ef270ab1SKenneth D. Merry 	ocs_lock(&node->active_ios_lock);
1878ef270ab1SKenneth D. Merry 	ocs_list_foreach(&node->active_ios, io) {
1879ef270ab1SKenneth D. Merry 		if ((io->mgmt_functions) && (io->mgmt_functions->get_all_handler)) {
1880ef270ab1SKenneth D. Merry 			io->mgmt_functions->get_all_handler(textbuf,io);
1881ef270ab1SKenneth D. Merry 		}
1882ef270ab1SKenneth D. Merry 	}
1883ef270ab1SKenneth D. Merry 	ocs_unlock(&node->active_ios_lock);
1884ef270ab1SKenneth D. Merry 
1885ef270ab1SKenneth D. Merry 	ocs_mgmt_end_section(textbuf, "node", node->instance_index);
1886ef270ab1SKenneth D. Merry }
1887ef270ab1SKenneth D. Merry 
1888ef270ab1SKenneth D. Merry int
ocs_mgmt_node_set(char * parent,char * name,char * value,void * object)1889ef270ab1SKenneth D. Merry ocs_mgmt_node_set(char *parent, char *name, char *value, void *object)
1890ef270ab1SKenneth D. Merry {
1891ef270ab1SKenneth D. Merry 	ocs_io_t *io;
1892ef270ab1SKenneth D. Merry 	ocs_node_t *node = (ocs_node_t *)object;
1893ef270ab1SKenneth D. Merry 	char qualifier[80];
1894ef270ab1SKenneth D. Merry 	int retval = -1;
1895ef270ab1SKenneth D. Merry 
1896ef270ab1SKenneth D. Merry 	ocs_snprintf(qualifier, sizeof(qualifier), "%s/node[%d]", parent, node->instance_index);
1897ef270ab1SKenneth D. Merry 
1898ef270ab1SKenneth D. Merry 	/* If it doesn't start with my qualifier I don't know what to do with it */
1899ef270ab1SKenneth D. Merry 	if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) {
1900ef270ab1SKenneth D. Merry 		ocs_lock(&node->active_ios_lock);
1901ef270ab1SKenneth D. Merry 		ocs_list_foreach(&node->active_ios, io) {
1902ef270ab1SKenneth D. Merry 			if ((io->mgmt_functions) && (io->mgmt_functions->set_handler)) {
1903ef270ab1SKenneth D. Merry 				retval = io->mgmt_functions->set_handler(qualifier, name, value, io);
1904ef270ab1SKenneth D. Merry 			}
1905ef270ab1SKenneth D. Merry 
1906ef270ab1SKenneth D. Merry 			if (retval == 0) {
1907ef270ab1SKenneth D. Merry 				break;
1908ef270ab1SKenneth D. Merry 			}
1909ef270ab1SKenneth D. Merry 		}
1910ef270ab1SKenneth D. Merry 		ocs_unlock(&node->active_ios_lock);
1911ef270ab1SKenneth D. Merry 	}
1912ef270ab1SKenneth D. Merry 
1913ef270ab1SKenneth D. Merry 	return retval;
1914ef270ab1SKenneth D. Merry }
1915ef270ab1SKenneth D. Merry 
1916ef270ab1SKenneth D. Merry int
ocs_mgmt_node_exec(char * parent,char * action,void * arg_in,uint32_t arg_in_length,void * arg_out,uint32_t arg_out_length,void * object)1917ef270ab1SKenneth D. Merry ocs_mgmt_node_exec(char *parent, char *action, void *arg_in, uint32_t arg_in_length,
1918ef270ab1SKenneth D. Merry 		   void *arg_out, uint32_t arg_out_length, void *object)
1919ef270ab1SKenneth D. Merry {
1920ef270ab1SKenneth D. Merry 	ocs_io_t *io;
1921ef270ab1SKenneth D. Merry 	ocs_node_t *node = (ocs_node_t *)object;
1922ef270ab1SKenneth D. Merry 	char qualifier[80];
1923ef270ab1SKenneth D. Merry 	int retval = -1;
1924ef270ab1SKenneth D. Merry 
1925ef270ab1SKenneth D. Merry 	ocs_snprintf(qualifier, sizeof(qualifier), "%s.node%d", parent, node->instance_index);
1926ef270ab1SKenneth D. Merry 
1927ef270ab1SKenneth D. Merry 	/* If it doesn't start with my qualifier I don't know what to do with it */
1928ef270ab1SKenneth D. Merry 	if (ocs_strncmp(action, qualifier, strlen(qualifier)) == 0) {
1929ef270ab1SKenneth D. Merry 		char *unqualified_name = action + strlen(qualifier) +1;
1930ef270ab1SKenneth D. Merry 
1931ef270ab1SKenneth D. Merry 		if (ocs_strcmp(unqualified_name, "resume") == 0) {
1932ef270ab1SKenneth D. Merry 			ocs_node_post_event(node, OCS_EVT_RESUME, NULL);
1933ef270ab1SKenneth D. Merry 		}
1934ef270ab1SKenneth D. Merry 
1935ef270ab1SKenneth D. Merry 		{
1936ef270ab1SKenneth D. Merry 			/* If I didn't know how to do this action pass the request to each of my children */
1937ef270ab1SKenneth D. Merry 			ocs_lock(&node->active_ios_lock);
1938ef270ab1SKenneth D. Merry 				ocs_list_foreach(&node->active_ios, io) {
1939ef270ab1SKenneth D. Merry 					if ((io->mgmt_functions) && (io->mgmt_functions->exec_handler)) {
1940ef270ab1SKenneth D. Merry 						retval = io->mgmt_functions->exec_handler(qualifier, action, arg_in, arg_in_length,
1941ef270ab1SKenneth D. Merry 							arg_out, arg_out_length, io);
1942ef270ab1SKenneth D. Merry 					}
1943ef270ab1SKenneth D. Merry 
1944ef270ab1SKenneth D. Merry 					if (retval == 0) {
1945ef270ab1SKenneth D. Merry 						break;
1946ef270ab1SKenneth D. Merry 					}
1947ef270ab1SKenneth D. Merry 				}
1948ef270ab1SKenneth D. Merry 			ocs_unlock(&node->active_ios_lock);
1949ef270ab1SKenneth D. Merry 		}
1950ef270ab1SKenneth D. Merry 	}
1951ef270ab1SKenneth D. Merry 
1952ef270ab1SKenneth D. Merry 	return retval;
1953ef270ab1SKenneth D. Merry }
1954ef270ab1SKenneth D. Merry 
1955ef270ab1SKenneth D. Merry /**
1956ef270ab1SKenneth D. Merry  * @brief Return TRUE if active ios list is empty
1957ef270ab1SKenneth D. Merry  *
1958ef270ab1SKenneth D. Merry  * Test if node->active_ios list is empty while holding the node->active_ios_lock.
1959ef270ab1SKenneth D. Merry  *
1960ef270ab1SKenneth D. Merry  * @param node pointer to node object
1961ef270ab1SKenneth D. Merry  *
1962ef270ab1SKenneth D. Merry  * @return TRUE if node active ios list is empty
1963ef270ab1SKenneth D. Merry  */
1964ef270ab1SKenneth D. Merry 
1965ef270ab1SKenneth D. Merry int
ocs_node_active_ios_empty(ocs_node_t * node)1966ef270ab1SKenneth D. Merry ocs_node_active_ios_empty(ocs_node_t *node)
1967ef270ab1SKenneth D. Merry {
1968ef270ab1SKenneth D. Merry 	int empty;
1969ef270ab1SKenneth D. Merry 
1970ef270ab1SKenneth D. Merry 	ocs_lock(&node->active_ios_lock);
1971ef270ab1SKenneth D. Merry 		empty = ocs_list_empty(&node->active_ios);
1972ef270ab1SKenneth D. Merry 	ocs_unlock(&node->active_ios_lock);
1973ef270ab1SKenneth D. Merry 	return empty;
1974ef270ab1SKenneth D. Merry }
1975ef270ab1SKenneth D. Merry 
1976ef270ab1SKenneth D. Merry /**
1977ef270ab1SKenneth D. Merry  * @brief Pause a node
1978ef270ab1SKenneth D. Merry  *
1979ef270ab1SKenneth D. Merry  * The node is placed in the __ocs_node_paused state after saving the state
1980ef270ab1SKenneth D. Merry  * to return to
1981ef270ab1SKenneth D. Merry  *
1982ef270ab1SKenneth D. Merry  * @param node Pointer to node object
1983ef270ab1SKenneth D. Merry  * @param state State to resume to
1984ef270ab1SKenneth D. Merry  *
1985ef270ab1SKenneth D. Merry  * @return none
1986ef270ab1SKenneth D. Merry  */
1987ef270ab1SKenneth D. Merry 
1988ef270ab1SKenneth D. Merry void
ocs_node_pause(ocs_node_t * node,ocs_sm_function_t state)1989ef270ab1SKenneth D. Merry ocs_node_pause(ocs_node_t *node, ocs_sm_function_t state)
1990ef270ab1SKenneth D. Merry {
1991ef270ab1SKenneth D. Merry 	node->nodedb_state = state;
1992ef270ab1SKenneth D. Merry 	ocs_node_transition(node, __ocs_node_paused, NULL);
1993ef270ab1SKenneth D. Merry }
1994ef270ab1SKenneth D. Merry 
1995ef270ab1SKenneth D. Merry /**
1996ef270ab1SKenneth D. Merry  * @brief Paused node state
1997ef270ab1SKenneth D. Merry  *
1998ef270ab1SKenneth D. Merry  * This state is entered when a state is "paused". When resumed, the node
1999ef270ab1SKenneth D. Merry  * is transitioned to a previously saved state (node->ndoedb_state)
2000ef270ab1SKenneth D. Merry  *
2001ef270ab1SKenneth D. Merry  * @param ctx Remote node state machine context.
2002ef270ab1SKenneth D. Merry  * @param evt Event to process.
2003ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
2004ef270ab1SKenneth D. Merry  *
2005ef270ab1SKenneth D. Merry  * @return returns NULL
2006ef270ab1SKenneth D. Merry  */
2007ef270ab1SKenneth D. Merry 
2008ef270ab1SKenneth D. Merry void *
__ocs_node_paused(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)2009ef270ab1SKenneth D. Merry __ocs_node_paused(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
2010ef270ab1SKenneth D. Merry {
2011ef270ab1SKenneth D. Merry 	std_node_state_decl();
2012ef270ab1SKenneth D. Merry 
2013ef270ab1SKenneth D. Merry 	node_sm_trace();
2014ef270ab1SKenneth D. Merry 
2015ef270ab1SKenneth D. Merry 	switch(evt) {
2016ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
2017ef270ab1SKenneth D. Merry 		node_printf(node, "Paused\n");
2018ef270ab1SKenneth D. Merry 		break;
2019ef270ab1SKenneth D. Merry 
2020ef270ab1SKenneth D. Merry 	case OCS_EVT_RESUME: {
2021ef270ab1SKenneth D. Merry 		ocs_sm_function_t pf = node->nodedb_state;
2022ef270ab1SKenneth D. Merry 
2023ef270ab1SKenneth D. Merry 		node->nodedb_state = NULL;
2024ef270ab1SKenneth D. Merry 		ocs_node_transition(node, pf, NULL);
2025ef270ab1SKenneth D. Merry 		break;
2026ef270ab1SKenneth D. Merry 	}
2027ef270ab1SKenneth D. Merry 
2028ef270ab1SKenneth D. Merry 	case OCS_EVT_DOMAIN_ATTACH_OK:
2029ef270ab1SKenneth D. Merry 		break;
2030ef270ab1SKenneth D. Merry 
2031ef270ab1SKenneth D. Merry 	case OCS_EVT_SHUTDOWN:
2032ef270ab1SKenneth D. Merry 		node->req_free = 1;
2033ef270ab1SKenneth D. Merry 		break;
2034ef270ab1SKenneth D. Merry 
2035ef270ab1SKenneth D. Merry 	default:
2036ef270ab1SKenneth D. Merry 		__ocs_node_common(__func__, ctx, evt, arg);
2037ef270ab1SKenneth D. Merry 		break;
2038ef270ab1SKenneth D. Merry 	}
2039ef270ab1SKenneth D. Merry 	return NULL;
2040ef270ab1SKenneth D. Merry }
2041ef270ab1SKenneth D. Merry 
2042ef270ab1SKenneth D. Merry /**
2043ef270ab1SKenneth D. Merry  * @brief Resume a paused state
2044ef270ab1SKenneth D. Merry  *
2045ef270ab1SKenneth D. Merry  * Posts a resume event to the paused node.
2046ef270ab1SKenneth D. Merry  *
2047ef270ab1SKenneth D. Merry  * @param node Pointer to node object
2048ef270ab1SKenneth D. Merry  *
2049ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
2050ef270ab1SKenneth D. Merry  */
2051ef270ab1SKenneth D. Merry 
2052ef270ab1SKenneth D. Merry int32_t
ocs_node_resume(ocs_node_t * node)2053ef270ab1SKenneth D. Merry ocs_node_resume(ocs_node_t *node)
2054ef270ab1SKenneth D. Merry {
2055ef270ab1SKenneth D. Merry 	ocs_assert(node != NULL, -1);
2056ef270ab1SKenneth D. Merry 
2057ef270ab1SKenneth D. Merry 	ocs_node_post_event(node, OCS_EVT_RESUME, NULL);
2058ef270ab1SKenneth D. Merry 
2059ef270ab1SKenneth D. Merry 	return 0;
2060ef270ab1SKenneth D. Merry }
2061ef270ab1SKenneth D. Merry 
2062ef270ab1SKenneth D. Merry /**
2063ef270ab1SKenneth D. Merry  * @ingroup node_common
2064ef270ab1SKenneth D. Merry  * @brief Dispatch a ELS frame.
2065ef270ab1SKenneth D. Merry  *
2066ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
2067ef270ab1SKenneth D. Merry  * An ELS frame is dispatched to the \c node state machine.
2068ef270ab1SKenneth D. Merry  * RQ Pair mode: this function is always called with a NULL hw
2069ef270ab1SKenneth D. Merry  * io.
2070ef270ab1SKenneth D. Merry  *
2071ef270ab1SKenneth D. Merry  * @param node Node that originated the frame.
2072ef270ab1SKenneth D. Merry  * @param seq header/payload sequence buffers
2073ef270ab1SKenneth D. Merry  *
2074ef270ab1SKenneth D. Merry  * @return Returns 0 if frame processed and RX buffers cleaned
2075ef270ab1SKenneth D. Merry  * up appropriately, -1 if frame not handled and RX buffers need
2076ef270ab1SKenneth D. Merry  * to be returned.
2077ef270ab1SKenneth D. Merry  */
2078ef270ab1SKenneth D. Merry 
2079ef270ab1SKenneth D. Merry int32_t
ocs_node_recv_els_frame(ocs_node_t * node,ocs_hw_sequence_t * seq)2080ef270ab1SKenneth D. Merry ocs_node_recv_els_frame(ocs_node_t *node, ocs_hw_sequence_t *seq)
2081ef270ab1SKenneth D. Merry {
2082ef270ab1SKenneth D. Merry 	struct {
2083ef270ab1SKenneth D. Merry 		uint32_t cmd;
2084ef270ab1SKenneth D. Merry 		ocs_sm_event_t evt;
2085ef270ab1SKenneth D. Merry 		uint32_t payload_size;
2086ef270ab1SKenneth D. Merry 	} els_cmd_list[] = {
2087ef270ab1SKenneth D. Merry 		{FC_ELS_CMD_PLOGI,	OCS_EVT_PLOGI_RCVD, 	sizeof(fc_plogi_payload_t)},
2088ef270ab1SKenneth D. Merry 		{FC_ELS_CMD_FLOGI,	OCS_EVT_FLOGI_RCVD, 	sizeof(fc_plogi_payload_t)},
2089ef270ab1SKenneth D. Merry 		{FC_ELS_CMD_LOGO,	OCS_EVT_LOGO_RCVD, 	sizeof(fc_acc_payload_t)},
2090ef270ab1SKenneth D. Merry 		{FC_ELS_CMD_RRQ,	OCS_EVT_RRQ_RCVD, 	sizeof(fc_acc_payload_t)},
2091ef270ab1SKenneth D. Merry 		{FC_ELS_CMD_PRLI, 	OCS_EVT_PRLI_RCVD, 	sizeof(fc_prli_payload_t)},
2092ef270ab1SKenneth D. Merry 		{FC_ELS_CMD_PRLO, 	OCS_EVT_PRLO_RCVD, 	sizeof(fc_prlo_payload_t)},
2093ef270ab1SKenneth D. Merry 		{FC_ELS_CMD_PDISC, 	OCS_EVT_PDISC_RCVD, 	MAX_ACC_REJECT_PAYLOAD},
2094ef270ab1SKenneth D. Merry 		{FC_ELS_CMD_FDISC, 	OCS_EVT_FDISC_RCVD, 	MAX_ACC_REJECT_PAYLOAD},
2095ef270ab1SKenneth D. Merry 		{FC_ELS_CMD_ADISC, 	OCS_EVT_ADISC_RCVD, 	sizeof(fc_adisc_payload_t)},
2096ef270ab1SKenneth D. Merry 		{FC_ELS_CMD_RSCN, 	OCS_EVT_RSCN_RCVD, 	MAX_ACC_REJECT_PAYLOAD},
2097ef270ab1SKenneth D. Merry 		{FC_ELS_CMD_SCR	, 	OCS_EVT_SCR_RCVD, 	MAX_ACC_REJECT_PAYLOAD},
2098ef270ab1SKenneth D. Merry 	};
2099ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
2100ef270ab1SKenneth D. Merry 	ocs_node_cb_t cbdata;
2101ef270ab1SKenneth D. Merry 	fc_header_t *hdr = seq->header->dma.virt;
2102ef270ab1SKenneth D. Merry 	uint8_t *buf = seq->payload->dma.virt;
2103ef270ab1SKenneth D. Merry 	ocs_sm_event_t evt = OCS_EVT_ELS_RCVD;
2104ef270ab1SKenneth D. Merry 	uint32_t payload_size = MAX_ACC_REJECT_PAYLOAD;
2105ef270ab1SKenneth D. Merry 	uint32_t i;
2106ef270ab1SKenneth D. Merry 
2107ef270ab1SKenneth D. Merry 	ocs_memset(&cbdata, 0, sizeof(cbdata));
2108ef270ab1SKenneth D. Merry 	cbdata.header = seq->header;
2109ef270ab1SKenneth D. Merry 	cbdata.payload = seq->payload;
2110ef270ab1SKenneth D. Merry 
2111ef270ab1SKenneth D. Merry 	/* find a matching event for the ELS command */
2112ef270ab1SKenneth D. Merry 	for (i = 0; i < ARRAY_SIZE(els_cmd_list); i ++) {
2113ef270ab1SKenneth D. Merry 		if (els_cmd_list[i].cmd == buf[0]) {
2114ef270ab1SKenneth D. Merry 			evt = els_cmd_list[i].evt;
2115ef270ab1SKenneth D. Merry 			payload_size = els_cmd_list[i].payload_size;
2116ef270ab1SKenneth D. Merry 			break;
2117ef270ab1SKenneth D. Merry 		}
2118ef270ab1SKenneth D. Merry 	}
2119ef270ab1SKenneth D. Merry 
2120ef270ab1SKenneth D. Merry 	switch(evt) {
2121ef270ab1SKenneth D. Merry 	case OCS_EVT_FLOGI_RCVD:
2122ef270ab1SKenneth D. Merry 		ocs_display_sparams(node->display_name, "flogi rcvd req", 0, NULL, ((uint8_t*)seq->payload->dma.virt)+4);
2123ef270ab1SKenneth D. Merry 		break;
2124ef270ab1SKenneth D. Merry 	case OCS_EVT_FDISC_RCVD:
2125ef270ab1SKenneth D. Merry 		ocs_display_sparams(node->display_name, "fdisc rcvd req", 0, NULL, ((uint8_t*)seq->payload->dma.virt)+4);
2126ef270ab1SKenneth D. Merry 		break;
2127ef270ab1SKenneth D. Merry 	case OCS_EVT_PLOGI_RCVD:
2128ef270ab1SKenneth D. Merry 		ocs_display_sparams(node->display_name, "plogi rcvd req", 0, NULL, ((uint8_t*)seq->payload->dma.virt)+4);
2129ef270ab1SKenneth D. Merry 		break;
2130ef270ab1SKenneth D. Merry 	default:
2131ef270ab1SKenneth D. Merry 		break;
2132ef270ab1SKenneth D. Merry 	}
2133ef270ab1SKenneth D. Merry 
2134ef270ab1SKenneth D. Merry 	cbdata.io = ocs_els_io_alloc(node, payload_size, OCS_ELS_ROLE_RESPONDER);
2135ef270ab1SKenneth D. Merry 
2136ef270ab1SKenneth D. Merry 	if (cbdata.io != NULL) {
2137ef270ab1SKenneth D. Merry 		cbdata.io->hw_priv = seq->hw_priv;
2138ef270ab1SKenneth D. Merry 		/* if we're here, sequence initiative has been transferred */
2139ef270ab1SKenneth D. Merry 		cbdata.io->seq_init = 1;
2140ef270ab1SKenneth D. Merry 
2141ef270ab1SKenneth D. Merry 		ocs_node_post_event(node, evt, &cbdata);
2142ef270ab1SKenneth D. Merry 	} else {
2143ef270ab1SKenneth D. Merry 		node_printf(node, "failure to allocate SCSI IO for ELS s_id %06x d_id %06x ox_id %04x rx_id %04x\n",
2144ef270ab1SKenneth D. Merry 			    fc_be24toh(hdr->s_id), fc_be24toh(hdr->d_id), ocs_be16toh(hdr->ox_id), ocs_be16toh(hdr->rx_id));
2145ef270ab1SKenneth D. Merry 	}
2146ef270ab1SKenneth D. Merry 	ocs_hw_sequence_free(&ocs->hw, seq);
2147ef270ab1SKenneth D. Merry 	return 0;
2148ef270ab1SKenneth D. Merry }
2149ef270ab1SKenneth D. Merry 
2150ef270ab1SKenneth D. Merry /**
2151ef270ab1SKenneth D. Merry  * @ingroup node_common
2152ef270ab1SKenneth D. Merry  * @brief Dispatch a ABTS frame (RQ Pair/sequence coalescing).
2153ef270ab1SKenneth D. Merry  *
2154ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
2155ef270ab1SKenneth D. Merry  * An ABTS frame is dispatched to the node state machine. This
2156ef270ab1SKenneth D. Merry  * function is used for both RQ Pair and sequence coalescing.
2157ef270ab1SKenneth D. Merry  *
2158ef270ab1SKenneth D. Merry  * @param node Node that originated the frame.
2159ef270ab1SKenneth D. Merry  * @param seq Header/payload sequence buffers
2160ef270ab1SKenneth D. Merry  *
2161ef270ab1SKenneth D. Merry  * @return Returns 0 if frame processed and RX buffers cleaned
2162ef270ab1SKenneth D. Merry  * up appropriately, -1 if frame not handled and RX buffers need
2163ef270ab1SKenneth D. Merry  * to be returned.
2164ef270ab1SKenneth D. Merry  */
2165ef270ab1SKenneth D. Merry 
2166ef270ab1SKenneth D. Merry int32_t
ocs_node_recv_abts_frame(ocs_node_t * node,ocs_hw_sequence_t * seq)2167ef270ab1SKenneth D. Merry ocs_node_recv_abts_frame(ocs_node_t *node, ocs_hw_sequence_t *seq)
2168ef270ab1SKenneth D. Merry {
2169ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
2170ef270ab1SKenneth D. Merry 	ocs_xport_t *xport = ocs->xport;
2171ef270ab1SKenneth D. Merry 	fc_header_t *hdr = seq->header->dma.virt;
2172ef270ab1SKenneth D. Merry 	uint16_t ox_id = ocs_be16toh(hdr->ox_id);
2173ef270ab1SKenneth D. Merry 	uint16_t rx_id = ocs_be16toh(hdr->rx_id);
2174ef270ab1SKenneth D. Merry 	ocs_node_cb_t cbdata;
2175ef270ab1SKenneth D. Merry 	int32_t rc = 0;
2176ef270ab1SKenneth D. Merry 
2177ef270ab1SKenneth D. Merry 	node->abort_cnt++;
2178ef270ab1SKenneth D. Merry 
2179ef270ab1SKenneth D. Merry 	/*
2180ef270ab1SKenneth D. Merry 	 * Check to see if the IO we want to abort is active, if it not active,
2181ef270ab1SKenneth D. Merry 	 * then we can send the BA_ACC using the send frame option
2182ef270ab1SKenneth D. Merry 	 */
2183ef270ab1SKenneth D. Merry 	if (ocs_io_find_tgt_io(ocs, node, ox_id, rx_id) == NULL) {
2184ef270ab1SKenneth D. Merry 		uint32_t send_frame_capable;
2185ef270ab1SKenneth D. Merry 
2186ef270ab1SKenneth D. Merry 		ocs_log_debug(ocs, "IO not found (ox_id %04x)\n", ox_id);
2187ef270ab1SKenneth D. Merry 
2188ef270ab1SKenneth D. Merry 		/* If we have SEND_FRAME capability, then use it to send BA_ACC */
2189ef270ab1SKenneth D. Merry 		rc = ocs_hw_get(&ocs->hw, OCS_HW_SEND_FRAME_CAPABLE, &send_frame_capable);
2190ef270ab1SKenneth D. Merry 		if ((rc == 0) && send_frame_capable) {
2191ef270ab1SKenneth D. Merry 			rc = ocs_sframe_send_bls_acc(node, seq);
2192ef270ab1SKenneth D. Merry 			if (rc) {
2193ef270ab1SKenneth D. Merry 				ocs_log_test(ocs, "ocs_bls_acc_send_frame failed\n");
2194ef270ab1SKenneth D. Merry 			}
2195ef270ab1SKenneth D. Merry 			return rc;
2196ef270ab1SKenneth D. Merry 		}
2197ef270ab1SKenneth D. Merry 		/* continuing */
2198ef270ab1SKenneth D. Merry 	}
2199ef270ab1SKenneth D. Merry 
2200ef270ab1SKenneth D. Merry 	ocs_memset(&cbdata, 0, sizeof(cbdata));
2201ef270ab1SKenneth D. Merry 	cbdata.header = seq->header;
2202ef270ab1SKenneth D. Merry 	cbdata.payload = seq->payload;
2203ef270ab1SKenneth D. Merry 
2204ef270ab1SKenneth D. Merry 	cbdata.io = ocs_scsi_io_alloc(node, OCS_SCSI_IO_ROLE_RESPONDER);
2205ef270ab1SKenneth D. Merry 	if (cbdata.io != NULL) {
2206ef270ab1SKenneth D. Merry 		cbdata.io->hw_priv = seq->hw_priv;
2207ef270ab1SKenneth D. Merry 		/* If we got this far, SIT=1 */
2208ef270ab1SKenneth D. Merry 		cbdata.io->seq_init = 1;
2209ef270ab1SKenneth D. Merry 
2210ef270ab1SKenneth D. Merry 		/* fill out generic fields */
2211ef270ab1SKenneth D. Merry 		cbdata.io->ocs = ocs;
2212ef270ab1SKenneth D. Merry 		cbdata.io->node = node;
2213ef270ab1SKenneth D. Merry 		cbdata.io->cmd_tgt = TRUE;
2214ef270ab1SKenneth D. Merry 
2215ef270ab1SKenneth D. Merry 		ocs_node_post_event(node, OCS_EVT_ABTS_RCVD, &cbdata);
2216ef270ab1SKenneth D. Merry 	} else {
2217ef270ab1SKenneth D. Merry 		ocs_atomic_add_return(&xport->io_alloc_failed_count, 1);
2218ef270ab1SKenneth D. Merry 		node_printf(node, "SCSI IO allocation failed for ABTS received s_id %06x d_id %06x ox_id %04x rx_id %04x\n",
2219ef270ab1SKenneth D. Merry 			    fc_be24toh(hdr->s_id), fc_be24toh(hdr->d_id), ocs_be16toh(hdr->ox_id), ocs_be16toh(hdr->rx_id));
2220ef270ab1SKenneth D. Merry 	}
2221ef270ab1SKenneth D. Merry 
2222ef270ab1SKenneth D. Merry 	/* ABTS processed, return RX buffer to the chip */
2223ef270ab1SKenneth D. Merry 	ocs_hw_sequence_free(&ocs->hw, seq);
2224ef270ab1SKenneth D. Merry 	return 0;
2225ef270ab1SKenneth D. Merry }
2226ef270ab1SKenneth D. Merry 
2227ef270ab1SKenneth D. Merry /**
2228ef270ab1SKenneth D. Merry  * @ingroup node_common
2229ef270ab1SKenneth D. Merry  * @brief Dispatch a CT frame.
2230ef270ab1SKenneth D. Merry  *
2231ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
2232ef270ab1SKenneth D. Merry  * A CT frame is dispatched to the \c node state machine.
2233ef270ab1SKenneth D. Merry  * RQ Pair mode: this function is always called with a NULL hw
2234ef270ab1SKenneth D. Merry  * io.
2235ef270ab1SKenneth D. Merry  *
2236ef270ab1SKenneth D. Merry  * @param node Node that originated the frame.
2237ef270ab1SKenneth D. Merry  * @param seq header/payload sequence buffers
2238ef270ab1SKenneth D. Merry  *
2239ef270ab1SKenneth D. Merry  * @return Returns 0 if frame processed and RX buffers cleaned
2240ef270ab1SKenneth D. Merry  * up appropriately, -1 if frame not handled and RX buffers need
2241ef270ab1SKenneth D. Merry  * to be returned.
2242ef270ab1SKenneth D. Merry  */
2243ef270ab1SKenneth D. Merry 
2244ef270ab1SKenneth D. Merry int32_t
ocs_node_recv_ct_frame(ocs_node_t * node,ocs_hw_sequence_t * seq)2245ef270ab1SKenneth D. Merry ocs_node_recv_ct_frame(ocs_node_t *node, ocs_hw_sequence_t *seq)
2246ef270ab1SKenneth D. Merry {
2247ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
2248ef270ab1SKenneth D. Merry 	fc_header_t *hdr = seq->header->dma.virt;
2249ef270ab1SKenneth D. Merry 	fcct_iu_header_t *iu = seq->payload->dma.virt;
2250ef270ab1SKenneth D. Merry 	ocs_sm_event_t evt = OCS_EVT_ELS_RCVD;
2251ef270ab1SKenneth D. Merry 	uint32_t payload_size = MAX_ACC_REJECT_PAYLOAD;
2252ef270ab1SKenneth D. Merry 	uint16_t gscmd = ocs_be16toh(iu->cmd_rsp_code);
2253ef270ab1SKenneth D. Merry 	ocs_node_cb_t cbdata;
2254ef270ab1SKenneth D. Merry 	uint32_t i;
2255ef270ab1SKenneth D. Merry 	struct {
2256ef270ab1SKenneth D. Merry 		uint32_t cmd;
2257ef270ab1SKenneth D. Merry 		ocs_sm_event_t evt;
2258ef270ab1SKenneth D. Merry 		uint32_t payload_size;
2259ef270ab1SKenneth D. Merry 	} ct_cmd_list[] = {
2260ef270ab1SKenneth D. Merry 		{FC_GS_NAMESERVER_RFF_ID, OCS_EVT_RFF_ID_RCVD, 100},
2261ef270ab1SKenneth D. Merry 		{FC_GS_NAMESERVER_RFT_ID, OCS_EVT_RFT_ID_RCVD, 100},
2262ef270ab1SKenneth D. Merry 		{FC_GS_NAMESERVER_GNN_ID, OCS_EVT_GNN_ID_RCVD, 100},
2263ef270ab1SKenneth D. Merry 		{FC_GS_NAMESERVER_GPN_ID, OCS_EVT_GPN_ID_RCVD, 100},
2264ef270ab1SKenneth D. Merry 		{FC_GS_NAMESERVER_GFPN_ID, OCS_EVT_GFPN_ID_RCVD, 100},
2265ef270ab1SKenneth D. Merry 		{FC_GS_NAMESERVER_GFF_ID, OCS_EVT_GFF_ID_RCVD, 100},
2266ef270ab1SKenneth D. Merry 		{FC_GS_NAMESERVER_GID_FT, OCS_EVT_GID_FT_RCVD, 256},
2267ef270ab1SKenneth D. Merry 		{FC_GS_NAMESERVER_GID_PT, OCS_EVT_GID_PT_RCVD, 256},
2268ef270ab1SKenneth D. Merry 		{FC_GS_NAMESERVER_RPN_ID, OCS_EVT_RPN_ID_RCVD, 100},
2269ef270ab1SKenneth D. Merry 		{FC_GS_NAMESERVER_RNN_ID, OCS_EVT_RNN_ID_RCVD, 100},
2270ef270ab1SKenneth D. Merry 		{FC_GS_NAMESERVER_RCS_ID, OCS_EVT_RCS_ID_RCVD, 100},
2271ef270ab1SKenneth D. Merry 		{FC_GS_NAMESERVER_RSNN_NN, OCS_EVT_RSNN_NN_RCVD, 100},
2272ef270ab1SKenneth D. Merry 		{FC_GS_NAMESERVER_RSPN_ID, OCS_EVT_RSPN_ID_RCVD, 100},
2273ef270ab1SKenneth D. Merry 		{FC_GS_NAMESERVER_RHBA, OCS_EVT_RHBA_RCVD, 100},
2274ef270ab1SKenneth D. Merry 		{FC_GS_NAMESERVER_RPA, OCS_EVT_RPA_RCVD, 100},
2275ef270ab1SKenneth D. Merry 	};
2276ef270ab1SKenneth D. Merry 
2277ef270ab1SKenneth D. Merry 	ocs_memset(&cbdata, 0, sizeof(cbdata));
2278ef270ab1SKenneth D. Merry 	cbdata.header = seq->header;
2279ef270ab1SKenneth D. Merry 	cbdata.payload = seq->payload;
2280ef270ab1SKenneth D. Merry 
2281ef270ab1SKenneth D. Merry 	/* find a matching event for the ELS/GS command */
2282ef270ab1SKenneth D. Merry 	for (i = 0; i < ARRAY_SIZE(ct_cmd_list); i ++) {
2283ef270ab1SKenneth D. Merry 		if (ct_cmd_list[i].cmd == gscmd) {
2284ef270ab1SKenneth D. Merry 			evt = ct_cmd_list[i].evt;
2285ef270ab1SKenneth D. Merry 			payload_size = ct_cmd_list[i].payload_size;
2286ef270ab1SKenneth D. Merry 			break;
2287ef270ab1SKenneth D. Merry 		}
2288ef270ab1SKenneth D. Merry 	}
2289ef270ab1SKenneth D. Merry 
2290ef270ab1SKenneth D. Merry 	/* Allocate an IO and send a reject */
2291ef270ab1SKenneth D. Merry 	cbdata.io = ocs_els_io_alloc(node, payload_size, OCS_ELS_ROLE_RESPONDER);
2292ef270ab1SKenneth D. Merry 	if (cbdata.io == NULL) {
2293ef270ab1SKenneth D. Merry 		node_printf(node, "GS IO failed for s_id %06x d_id %06x ox_id %04x rx_id %04x\n",
2294ef270ab1SKenneth D. Merry 			fc_be24toh(hdr->s_id), fc_be24toh(hdr->d_id),
2295ef270ab1SKenneth D. Merry 			ocs_be16toh(hdr->ox_id), ocs_be16toh(hdr->rx_id));
2296ef270ab1SKenneth D. Merry 		return -1;
2297ef270ab1SKenneth D. Merry 	}
2298ef270ab1SKenneth D. Merry 	cbdata.io->hw_priv = seq->hw_priv;
2299ef270ab1SKenneth D. Merry 	ocs_node_post_event(node, evt, &cbdata);
2300ef270ab1SKenneth D. Merry 
2301ef270ab1SKenneth D. Merry 	ocs_hw_sequence_free(&ocs->hw, seq);
2302ef270ab1SKenneth D. Merry 	return 0;
2303ef270ab1SKenneth D. Merry }
2304ef270ab1SKenneth D. Merry 
2305ef270ab1SKenneth D. Merry /**
2306ef270ab1SKenneth D. Merry  * @ingroup node_common
2307ef270ab1SKenneth D. Merry  * @brief Dispatch a FCP command frame when the node is not ready.
2308ef270ab1SKenneth D. Merry  *
2309ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
2310ef270ab1SKenneth D. Merry  * A frame is dispatched to the \c node state machine.
2311ef270ab1SKenneth D. Merry  *
2312ef270ab1SKenneth D. Merry  * @param node Node that originated the frame.
2313ef270ab1SKenneth D. Merry  * @param seq header/payload sequence buffers
2314ef270ab1SKenneth D. Merry  *
2315ef270ab1SKenneth D. Merry  * @return Returns 0 if frame processed and RX buffers cleaned
2316ef270ab1SKenneth D. Merry  * up appropriately, -1 if frame not handled.
2317ef270ab1SKenneth D. Merry  */
2318ef270ab1SKenneth D. Merry 
2319ef270ab1SKenneth D. Merry int32_t
ocs_node_recv_fcp_cmd(ocs_node_t * node,ocs_hw_sequence_t * seq)2320ef270ab1SKenneth D. Merry ocs_node_recv_fcp_cmd(ocs_node_t *node, ocs_hw_sequence_t *seq)
2321ef270ab1SKenneth D. Merry {
2322ef270ab1SKenneth D. Merry 	ocs_node_cb_t cbdata;
2323ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
2324ef270ab1SKenneth D. Merry 
2325ef270ab1SKenneth D. Merry 	ocs_memset(&cbdata, 0, sizeof(cbdata));
2326ef270ab1SKenneth D. Merry 	cbdata.header = seq->header;
2327ef270ab1SKenneth D. Merry 	cbdata.payload = seq->payload;
2328ef270ab1SKenneth D. Merry 	ocs_node_post_event(node, OCS_EVT_FCP_CMD_RCVD, &cbdata);
2329ef270ab1SKenneth D. Merry 	ocs_hw_sequence_free(&ocs->hw, seq);
2330ef270ab1SKenneth D. Merry 	return 0;
2331ef270ab1SKenneth D. Merry }
2332ef270ab1SKenneth D. Merry 
2333ef270ab1SKenneth D. Merry /**
2334ef270ab1SKenneth D. Merry  * @ingroup node_common
2335ef270ab1SKenneth D. Merry  * @brief Stub handler for non-ABTS BLS frames
2336ef270ab1SKenneth D. Merry  *
2337ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
2338ef270ab1SKenneth D. Merry  * Log message and drop. Customer can plumb it to their back-end as needed
2339ef270ab1SKenneth D. Merry  *
2340ef270ab1SKenneth D. Merry  * @param node Node that originated the frame.
2341ef270ab1SKenneth D. Merry  * @param seq header/payload sequence buffers
2342ef270ab1SKenneth D. Merry  *
2343ef270ab1SKenneth D. Merry  * @return Returns 0
2344ef270ab1SKenneth D. Merry  */
2345ef270ab1SKenneth D. Merry 
2346ef270ab1SKenneth D. Merry int32_t
ocs_node_recv_bls_no_sit(ocs_node_t * node,ocs_hw_sequence_t * seq)2347ef270ab1SKenneth D. Merry ocs_node_recv_bls_no_sit(ocs_node_t *node, ocs_hw_sequence_t *seq)
2348ef270ab1SKenneth D. Merry {
2349ef270ab1SKenneth D. Merry 	fc_header_t *hdr = seq->header->dma.virt;
2350ef270ab1SKenneth D. Merry 
2351ef270ab1SKenneth D. Merry 	node_printf(node, "Dropping frame hdr = %08x %08x %08x %08x %08x %08x\n",
2352ef270ab1SKenneth D. Merry 		    ocs_htobe32(((uint32_t *)hdr)[0]),
2353ef270ab1SKenneth D. Merry 		    ocs_htobe32(((uint32_t *)hdr)[1]),
2354ef270ab1SKenneth D. Merry 		    ocs_htobe32(((uint32_t *)hdr)[2]),
2355ef270ab1SKenneth D. Merry 		    ocs_htobe32(((uint32_t *)hdr)[3]),
2356ef270ab1SKenneth D. Merry 		    ocs_htobe32(((uint32_t *)hdr)[4]),
2357ef270ab1SKenneth D. Merry 		    ocs_htobe32(((uint32_t *)hdr)[5]));
2358ef270ab1SKenneth D. Merry 
2359ef270ab1SKenneth D. Merry 	return -1;
2360ef270ab1SKenneth D. Merry }
2361