xref: /freebsd-src/sys/dev/ocs_fc/ocs_els.c (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
1*ef270ab1SKenneth D. Merry /*-
2*ef270ab1SKenneth D. Merry  * Copyright (c) 2017 Broadcom. All rights reserved.
3*ef270ab1SKenneth D. Merry  * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
4*ef270ab1SKenneth D. Merry  *
5*ef270ab1SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
6*ef270ab1SKenneth D. Merry  * modification, are permitted provided that the following conditions are met:
7*ef270ab1SKenneth D. Merry  *
8*ef270ab1SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright notice,
9*ef270ab1SKenneth D. Merry  *    this list of conditions and the following disclaimer.
10*ef270ab1SKenneth D. Merry  *
11*ef270ab1SKenneth D. Merry  * 2. Redistributions in binary form must reproduce the above copyright notice,
12*ef270ab1SKenneth D. Merry  *    this list of conditions and the following disclaimer in the documentation
13*ef270ab1SKenneth D. Merry  *    and/or other materials provided with the distribution.
14*ef270ab1SKenneth D. Merry  *
15*ef270ab1SKenneth D. Merry  * 3. Neither the name of the copyright holder nor the names of its contributors
16*ef270ab1SKenneth D. Merry  *    may be used to endorse or promote products derived from this software
17*ef270ab1SKenneth D. Merry  *    without specific prior written permission.
18*ef270ab1SKenneth D. Merry  *
19*ef270ab1SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20*ef270ab1SKenneth D. Merry  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*ef270ab1SKenneth D. Merry  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*ef270ab1SKenneth D. Merry  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23*ef270ab1SKenneth D. Merry  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*ef270ab1SKenneth D. Merry  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*ef270ab1SKenneth D. Merry  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*ef270ab1SKenneth D. Merry  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*ef270ab1SKenneth D. Merry  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*ef270ab1SKenneth D. Merry  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*ef270ab1SKenneth D. Merry  * POSSIBILITY OF SUCH DAMAGE.
30*ef270ab1SKenneth D. Merry  */
31*ef270ab1SKenneth D. Merry 
32*ef270ab1SKenneth D. Merry /**
33*ef270ab1SKenneth D. Merry  * @file
34*ef270ab1SKenneth D. Merry  * Functions to build and send ELS/CT/BLS commands and responses.
35*ef270ab1SKenneth D. Merry  */
36*ef270ab1SKenneth D. Merry 
37*ef270ab1SKenneth D. Merry /*!
38*ef270ab1SKenneth D. Merry @defgroup els_api ELS/BLS/CT Command and Response Functions
39*ef270ab1SKenneth D. Merry */
40*ef270ab1SKenneth D. Merry 
41*ef270ab1SKenneth D. Merry #include "ocs.h"
42*ef270ab1SKenneth D. Merry #include "ocs_els.h"
43*ef270ab1SKenneth D. Merry #include "ocs_scsi.h"
44*ef270ab1SKenneth D. Merry #include "ocs_device.h"
45*ef270ab1SKenneth D. Merry 
46*ef270ab1SKenneth D. Merry #define ELS_IOFMT "[i:%04x t:%04x h:%04x]"
47*ef270ab1SKenneth D. Merry #define ELS_IOFMT_ARGS(els) els->init_task_tag, els->tgt_task_tag, els->hw_tag
48*ef270ab1SKenneth D. Merry 
49*ef270ab1SKenneth D. Merry #define node_els_trace()  \
50*ef270ab1SKenneth D. Merry 	do { \
51*ef270ab1SKenneth D. Merry 		if (OCS_LOG_ENABLE_ELS_TRACE(ocs)) \
52*ef270ab1SKenneth D. Merry 			ocs_log_info(ocs, "[%s] %-20s\n", node->display_name, __func__); \
53*ef270ab1SKenneth D. Merry 	} while (0)
54*ef270ab1SKenneth D. Merry 
55*ef270ab1SKenneth D. Merry #define els_io_printf(els, fmt, ...) \
56*ef270ab1SKenneth D. Merry 	ocs_log_debug(els->node->ocs, "[%s]" ELS_IOFMT " %-8s " fmt, els->node->display_name, ELS_IOFMT_ARGS(els), els->display_name, ##__VA_ARGS__);
57*ef270ab1SKenneth D. Merry 
58*ef270ab1SKenneth D. Merry static int32_t ocs_els_send(ocs_io_t *els, uint32_t reqlen, uint32_t timeout_sec, ocs_hw_srrs_cb_t cb);
59*ef270ab1SKenneth D. Merry static int32_t ocs_els_send_rsp(ocs_io_t *els, uint32_t rsplen);
60*ef270ab1SKenneth D. Merry static int32_t ocs_els_acc_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *arg);
61*ef270ab1SKenneth D. Merry static ocs_io_t *ocs_bls_send_acc(ocs_io_t *io, uint32_t s_id, uint16_t ox_id, uint16_t rx_id);
62*ef270ab1SKenneth D. Merry static int32_t ocs_bls_send_acc_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length,
63*ef270ab1SKenneth D. Merry 	int32_t status, uint32_t ext_status, void *app);
64*ef270ab1SKenneth D. Merry static void ocs_io_transition(ocs_io_t *els, ocs_sm_function_t state, void *data);
65*ef270ab1SKenneth D. Merry static ocs_io_t *ocs_els_abort_io(ocs_io_t *els, int send_abts);
66*ef270ab1SKenneth D. Merry static void _ocs_els_io_free(void *arg);
67*ef270ab1SKenneth D. Merry static void ocs_els_delay_timer_cb(void *arg);
68*ef270ab1SKenneth D. Merry 
69*ef270ab1SKenneth D. Merry /**
70*ef270ab1SKenneth D. Merry  * @ingroup els_api
71*ef270ab1SKenneth D. Merry  * @brief ELS state machine transition wrapper.
72*ef270ab1SKenneth D. Merry  *
73*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
74*ef270ab1SKenneth D. Merry  * This function is the transition wrapper for the ELS state machine. It grabs
75*ef270ab1SKenneth D. Merry  * the node lock prior to making the transition to protect
76*ef270ab1SKenneth D. Merry  * against multiple threads accessing a particular ELS. For example,
77*ef270ab1SKenneth D. Merry  * one thread transitioning from __els_init to
78*ef270ab1SKenneth D. Merry  * __ocs_els_wait_resp and another thread (tasklet) handling the
79*ef270ab1SKenneth D. Merry  * completion of that ELS request.
80*ef270ab1SKenneth D. Merry  *
81*ef270ab1SKenneth D. Merry  * @param els Pointer to the IO context.
82*ef270ab1SKenneth D. Merry  * @param state State to transition to.
83*ef270ab1SKenneth D. Merry  * @param data Data to pass in with the transition.
84*ef270ab1SKenneth D. Merry  *
85*ef270ab1SKenneth D. Merry  * @return None.
86*ef270ab1SKenneth D. Merry  */
87*ef270ab1SKenneth D. Merry static void
ocs_io_transition(ocs_io_t * els,ocs_sm_function_t state,void * data)88*ef270ab1SKenneth D. Merry ocs_io_transition(ocs_io_t *els, ocs_sm_function_t state, void *data)
89*ef270ab1SKenneth D. Merry {
90*ef270ab1SKenneth D. Merry 	/* protect ELS events with node lock */
91*ef270ab1SKenneth D. Merry 	ocs_node_t *node = els->node;
92*ef270ab1SKenneth D. Merry 	ocs_node_lock(node);
93*ef270ab1SKenneth D. Merry 		ocs_sm_transition(&els->els_sm, state, data);
94*ef270ab1SKenneth D. Merry 	ocs_node_unlock(node);
95*ef270ab1SKenneth D. Merry }
96*ef270ab1SKenneth D. Merry 
97*ef270ab1SKenneth D. Merry /**
98*ef270ab1SKenneth D. Merry  * @ingroup els_api
99*ef270ab1SKenneth D. Merry  * @brief ELS state machine post event wrapper.
100*ef270ab1SKenneth D. Merry  *
101*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
102*ef270ab1SKenneth D. Merry  * Post an event wrapper for the ELS state machine. This function grabs
103*ef270ab1SKenneth D. Merry  * the node lock prior to posting the event.
104*ef270ab1SKenneth D. Merry  *
105*ef270ab1SKenneth D. Merry  * @param els Pointer to the IO context.
106*ef270ab1SKenneth D. Merry  * @param evt Event to process.
107*ef270ab1SKenneth D. Merry  * @param data Data to pass in with the transition.
108*ef270ab1SKenneth D. Merry  *
109*ef270ab1SKenneth D. Merry  * @return None.
110*ef270ab1SKenneth D. Merry  */
111*ef270ab1SKenneth D. Merry void
ocs_els_post_event(ocs_io_t * els,ocs_sm_event_t evt,void * data)112*ef270ab1SKenneth D. Merry ocs_els_post_event(ocs_io_t *els, ocs_sm_event_t evt, void *data)
113*ef270ab1SKenneth D. Merry {
114*ef270ab1SKenneth D. Merry 	/* protect ELS events with node lock */
115*ef270ab1SKenneth D. Merry 	ocs_node_t *node = els->node;
116*ef270ab1SKenneth D. Merry 	ocs_node_lock(node);
117*ef270ab1SKenneth D. Merry 		els->els_evtdepth ++;
118*ef270ab1SKenneth D. Merry 		ocs_sm_post_event(&els->els_sm, evt, data);
119*ef270ab1SKenneth D. Merry 		els->els_evtdepth --;
120*ef270ab1SKenneth D. Merry 	ocs_node_unlock(node);
121*ef270ab1SKenneth D. Merry 	if (els->els_evtdepth == 0 && els->els_req_free) {
122*ef270ab1SKenneth D. Merry 		ocs_els_io_free(els);
123*ef270ab1SKenneth D. Merry 	}
124*ef270ab1SKenneth D. Merry }
125*ef270ab1SKenneth D. Merry 
126*ef270ab1SKenneth D. Merry /**
127*ef270ab1SKenneth D. Merry  * @ingroup els_api
128*ef270ab1SKenneth D. Merry  * @brief Allocate an IO structure for an ELS IO context.
129*ef270ab1SKenneth D. Merry  *
130*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
131*ef270ab1SKenneth D. Merry  * Allocate an IO for an ELS context.  Uses OCS_ELS_RSP_LEN as response size.
132*ef270ab1SKenneth D. Merry  *
133*ef270ab1SKenneth D. Merry  * @param node node to associate ELS IO with
134*ef270ab1SKenneth D. Merry  * @param reqlen Length of ELS request
135*ef270ab1SKenneth D. Merry  * @param role Role of ELS (originator/responder)
136*ef270ab1SKenneth D. Merry  *
137*ef270ab1SKenneth D. Merry  * @return pointer to IO structure allocated
138*ef270ab1SKenneth D. Merry  */
139*ef270ab1SKenneth D. Merry 
140*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_els_io_alloc(ocs_node_t * node,uint32_t reqlen,ocs_els_role_e role)141*ef270ab1SKenneth D. Merry ocs_els_io_alloc(ocs_node_t *node, uint32_t reqlen, ocs_els_role_e role)
142*ef270ab1SKenneth D. Merry {
143*ef270ab1SKenneth D. Merry 	return ocs_els_io_alloc_size(node, reqlen, OCS_ELS_RSP_LEN, role);
144*ef270ab1SKenneth D. Merry }
145*ef270ab1SKenneth D. Merry 
146*ef270ab1SKenneth D. Merry /**
147*ef270ab1SKenneth D. Merry  * @ingroup els_api
148*ef270ab1SKenneth D. Merry  * @brief Allocate an IO structure for an ELS IO context.
149*ef270ab1SKenneth D. Merry  *
150*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
151*ef270ab1SKenneth D. Merry  * Allocate an IO for an ELS context, allowing the caller to specify the size of the response.
152*ef270ab1SKenneth D. Merry  *
153*ef270ab1SKenneth D. Merry  * @param node node to associate ELS IO with
154*ef270ab1SKenneth D. Merry  * @param reqlen Length of ELS request
155*ef270ab1SKenneth D. Merry  * @param rsplen Length of ELS response
156*ef270ab1SKenneth D. Merry  * @param role Role of ELS (originator/responder)
157*ef270ab1SKenneth D. Merry  *
158*ef270ab1SKenneth D. Merry  * @return pointer to IO structure allocated
159*ef270ab1SKenneth D. Merry  */
160*ef270ab1SKenneth D. Merry 
161*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_els_io_alloc_size(ocs_node_t * node,uint32_t reqlen,uint32_t rsplen,ocs_els_role_e role)162*ef270ab1SKenneth D. Merry ocs_els_io_alloc_size(ocs_node_t *node, uint32_t reqlen, uint32_t rsplen, ocs_els_role_e role)
163*ef270ab1SKenneth D. Merry {
164*ef270ab1SKenneth D. Merry 
165*ef270ab1SKenneth D. Merry 	ocs_t *ocs;
166*ef270ab1SKenneth D. Merry 	ocs_xport_t *xport;
167*ef270ab1SKenneth D. Merry 	ocs_io_t *els;
168*ef270ab1SKenneth D. Merry 	ocs_assert(node, NULL);
169*ef270ab1SKenneth D. Merry 	ocs_assert(node->ocs, NULL);
170*ef270ab1SKenneth D. Merry 	ocs = node->ocs;
171*ef270ab1SKenneth D. Merry 	ocs_assert(ocs->xport, NULL);
172*ef270ab1SKenneth D. Merry 	xport = ocs->xport;
173*ef270ab1SKenneth D. Merry 
174*ef270ab1SKenneth D. Merry 	ocs_lock(&node->active_ios_lock);
175*ef270ab1SKenneth D. Merry 		if (!node->io_alloc_enabled) {
176*ef270ab1SKenneth D. Merry 			ocs_log_debug(ocs, "called with io_alloc_enabled = FALSE\n");
177*ef270ab1SKenneth D. Merry 			ocs_unlock(&node->active_ios_lock);
178*ef270ab1SKenneth D. Merry 			return NULL;
179*ef270ab1SKenneth D. Merry 		}
180*ef270ab1SKenneth D. Merry 
181*ef270ab1SKenneth D. Merry 		els = ocs_io_alloc(ocs);
182*ef270ab1SKenneth D. Merry 		if (els == NULL) {
183*ef270ab1SKenneth D. Merry 			ocs_atomic_add_return(&xport->io_alloc_failed_count, 1);
184*ef270ab1SKenneth D. Merry 			ocs_unlock(&node->active_ios_lock);
185*ef270ab1SKenneth D. Merry 			return NULL;
186*ef270ab1SKenneth D. Merry 		}
187*ef270ab1SKenneth D. Merry 
188*ef270ab1SKenneth D. Merry 		/* initialize refcount */
189*ef270ab1SKenneth D. Merry 		ocs_ref_init(&els->ref, _ocs_els_io_free, els);
190*ef270ab1SKenneth D. Merry 
191*ef270ab1SKenneth D. Merry 		switch (role) {
192*ef270ab1SKenneth D. Merry 		case OCS_ELS_ROLE_ORIGINATOR:
193*ef270ab1SKenneth D. Merry 			els->cmd_ini = TRUE;
194*ef270ab1SKenneth D. Merry 			els->cmd_tgt = FALSE;
195*ef270ab1SKenneth D. Merry 			break;
196*ef270ab1SKenneth D. Merry 		case OCS_ELS_ROLE_RESPONDER:
197*ef270ab1SKenneth D. Merry 			els->cmd_ini = FALSE;
198*ef270ab1SKenneth D. Merry 			els->cmd_tgt = TRUE;
199*ef270ab1SKenneth D. Merry 			break;
200*ef270ab1SKenneth D. Merry 		}
201*ef270ab1SKenneth D. Merry 
202*ef270ab1SKenneth D. Merry 		/* IO should not have an associated HW IO yet.  Assigned below. */
203*ef270ab1SKenneth D. Merry 		if (els->hio != NULL) {
204*ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "assertion failed.  HIO is not null\n");
205*ef270ab1SKenneth D. Merry 			ocs_io_free(ocs, els);
206*ef270ab1SKenneth D. Merry 			ocs_unlock(&node->active_ios_lock);
207*ef270ab1SKenneth D. Merry 			return NULL;
208*ef270ab1SKenneth D. Merry 		}
209*ef270ab1SKenneth D. Merry 
210*ef270ab1SKenneth D. Merry 		/* populate generic io fields */
211*ef270ab1SKenneth D. Merry 		els->ocs = ocs;
212*ef270ab1SKenneth D. Merry 		els->node = node;
213*ef270ab1SKenneth D. Merry 
214*ef270ab1SKenneth D. Merry 		/* set type and ELS-specific fields */
215*ef270ab1SKenneth D. Merry 		els->io_type = OCS_IO_TYPE_ELS;
216*ef270ab1SKenneth D. Merry 		els->display_name = "pending";
217*ef270ab1SKenneth D. Merry 
218*ef270ab1SKenneth D. Merry 		if (reqlen > OCS_ELS_REQ_LEN) {
219*ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "ELS command request len greater than allocated\n");
220*ef270ab1SKenneth D. Merry 			ocs_io_free(ocs, els);
221*ef270ab1SKenneth D. Merry 			ocs_unlock(&node->active_ios_lock);
222*ef270ab1SKenneth D. Merry 			return NULL;
223*ef270ab1SKenneth D. Merry 		}
224*ef270ab1SKenneth D. Merry 
225*ef270ab1SKenneth D. Merry 		if (rsplen > OCS_ELS_GID_PT_RSP_LEN) {
226*ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "ELS command response len: %d "
227*ef270ab1SKenneth D. Merry 				"greater than allocated\n", rsplen);
228*ef270ab1SKenneth D. Merry 			ocs_io_free(ocs, els);
229*ef270ab1SKenneth D. Merry 			ocs_unlock(&node->active_ios_lock);
230*ef270ab1SKenneth D. Merry 			return NULL;
231*ef270ab1SKenneth D. Merry 		}
232*ef270ab1SKenneth D. Merry 
233*ef270ab1SKenneth D. Merry 		els->els_req.size = reqlen;
234*ef270ab1SKenneth D. Merry 		els->els_rsp.size = rsplen;
235*ef270ab1SKenneth D. Merry 
236*ef270ab1SKenneth D. Merry 		if (els != NULL) {
237*ef270ab1SKenneth D. Merry 			ocs_memset(&els->els_sm, 0, sizeof(els->els_sm));
238*ef270ab1SKenneth D. Merry 			els->els_sm.app = els;
239*ef270ab1SKenneth D. Merry 
240*ef270ab1SKenneth D. Merry 			/* initialize fields */
241*ef270ab1SKenneth D. Merry 			els->els_retries_remaining = OCS_FC_ELS_DEFAULT_RETRIES;
242*ef270ab1SKenneth D. Merry 			els->els_evtdepth = 0;
243*ef270ab1SKenneth D. Merry 			els->els_pend = 0;
244*ef270ab1SKenneth D. Merry 			els->els_active = 0;
245*ef270ab1SKenneth D. Merry 
246*ef270ab1SKenneth D. Merry 			/* add els structure to ELS IO list */
247*ef270ab1SKenneth D. Merry 			ocs_list_add_tail(&node->els_io_pend_list, els);
248*ef270ab1SKenneth D. Merry 			els->els_pend = 1;
249*ef270ab1SKenneth D. Merry 		}
250*ef270ab1SKenneth D. Merry 	ocs_unlock(&node->active_ios_lock);
251*ef270ab1SKenneth D. Merry 	return els;
252*ef270ab1SKenneth D. Merry }
253*ef270ab1SKenneth D. Merry 
254*ef270ab1SKenneth D. Merry /**
255*ef270ab1SKenneth D. Merry  * @ingroup els_api
256*ef270ab1SKenneth D. Merry  * @brief Free IO structure for an ELS IO context.
257*ef270ab1SKenneth D. Merry  *
258*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3> Free IO for an ELS
259*ef270ab1SKenneth D. Merry  * IO context
260*ef270ab1SKenneth D. Merry  *
261*ef270ab1SKenneth D. Merry  * @param els ELS IO structure for which IO is allocated
262*ef270ab1SKenneth D. Merry  *
263*ef270ab1SKenneth D. Merry  * @return None
264*ef270ab1SKenneth D. Merry  */
265*ef270ab1SKenneth D. Merry 
266*ef270ab1SKenneth D. Merry void
ocs_els_io_free(ocs_io_t * els)267*ef270ab1SKenneth D. Merry ocs_els_io_free(ocs_io_t *els)
268*ef270ab1SKenneth D. Merry {
269*ef270ab1SKenneth D. Merry 	ocs_ref_put(&els->ref);
270*ef270ab1SKenneth D. Merry }
271*ef270ab1SKenneth D. Merry 
272*ef270ab1SKenneth D. Merry /**
273*ef270ab1SKenneth D. Merry  * @ingroup els_api
274*ef270ab1SKenneth D. Merry  * @brief Free IO structure for an ELS IO context.
275*ef270ab1SKenneth D. Merry  *
276*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3> Free IO for an ELS
277*ef270ab1SKenneth D. Merry  * IO context
278*ef270ab1SKenneth D. Merry  *
279*ef270ab1SKenneth D. Merry  * @param arg ELS IO structure for which IO is allocated
280*ef270ab1SKenneth D. Merry  *
281*ef270ab1SKenneth D. Merry  * @return None
282*ef270ab1SKenneth D. Merry  */
283*ef270ab1SKenneth D. Merry 
284*ef270ab1SKenneth D. Merry static void
_ocs_els_io_free(void * arg)285*ef270ab1SKenneth D. Merry _ocs_els_io_free(void *arg)
286*ef270ab1SKenneth D. Merry {
287*ef270ab1SKenneth D. Merry 	ocs_io_t *els = (ocs_io_t *)arg;
288*ef270ab1SKenneth D. Merry 	ocs_t *ocs;
289*ef270ab1SKenneth D. Merry 	ocs_node_t *node;
290*ef270ab1SKenneth D. Merry 	int send_empty_event = FALSE;
291*ef270ab1SKenneth D. Merry 
292*ef270ab1SKenneth D. Merry 	ocs_assert(els);
293*ef270ab1SKenneth D. Merry 	ocs_assert(els->node);
294*ef270ab1SKenneth D. Merry 	ocs_assert(els->node->ocs);
295*ef270ab1SKenneth D. Merry 	ocs = els->node->ocs;
296*ef270ab1SKenneth D. Merry 
297*ef270ab1SKenneth D. Merry 	node = els->node;
298*ef270ab1SKenneth D. Merry 	ocs = node->ocs;
299*ef270ab1SKenneth D. Merry 
300*ef270ab1SKenneth D. Merry 	ocs_lock(&node->active_ios_lock);
301*ef270ab1SKenneth D. Merry 		if (els->els_active) {
302*ef270ab1SKenneth D. Merry 			/* if active, remove from active list and check empty */
303*ef270ab1SKenneth D. Merry 			ocs_list_remove(&node->els_io_active_list, els);
304*ef270ab1SKenneth D. Merry 			/* Send list empty event if the IO allocator is disabled, and the list is empty
305*ef270ab1SKenneth D. Merry 			 * If node->io_alloc_enabled was not checked, the event would be posted continually
306*ef270ab1SKenneth D. Merry 			 */
307*ef270ab1SKenneth D. Merry 			send_empty_event = (!node->io_alloc_enabled) && ocs_list_empty(&node->els_io_active_list);
308*ef270ab1SKenneth D. Merry 			els->els_active = 0;
309*ef270ab1SKenneth D. Merry 		} else if (els->els_pend) {
310*ef270ab1SKenneth D. Merry 			/* if pending, remove from pending list; node shutdown isn't
311*ef270ab1SKenneth D. Merry 			 * gated off the pending list (only the active list), so no
312*ef270ab1SKenneth D. Merry 			 * need to check if pending list is empty
313*ef270ab1SKenneth D. Merry 			 */
314*ef270ab1SKenneth D. Merry 			ocs_list_remove(&node->els_io_pend_list, els);
315*ef270ab1SKenneth D. Merry 			els->els_pend = 0;
316*ef270ab1SKenneth D. Merry 		} else {
317*ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "assertion failed: niether els->els_pend nor els->active set\n");
318*ef270ab1SKenneth D. Merry 			ocs_unlock(&node->active_ios_lock);
319*ef270ab1SKenneth D. Merry 			return;
320*ef270ab1SKenneth D. Merry 		}
321*ef270ab1SKenneth D. Merry 
322*ef270ab1SKenneth D. Merry 	ocs_unlock(&node->active_ios_lock);
323*ef270ab1SKenneth D. Merry 
324*ef270ab1SKenneth D. Merry 	ocs_io_free(ocs, els);
325*ef270ab1SKenneth D. Merry 
326*ef270ab1SKenneth D. Merry 	if (send_empty_event) {
327*ef270ab1SKenneth D. Merry 		ocs_node_post_event(node, OCS_EVT_ALL_CHILD_NODES_FREE, NULL);
328*ef270ab1SKenneth D. Merry 	}
329*ef270ab1SKenneth D. Merry 
330*ef270ab1SKenneth D. Merry 	ocs_scsi_check_pending(ocs);
331*ef270ab1SKenneth D. Merry }
332*ef270ab1SKenneth D. Merry 
333*ef270ab1SKenneth D. Merry /**
334*ef270ab1SKenneth D. Merry  * @ingroup els_api
335*ef270ab1SKenneth D. Merry  * @brief Make ELS IO active
336*ef270ab1SKenneth D. Merry  *
337*ef270ab1SKenneth D. Merry  * @param els Pointer to the IO context to make active.
338*ef270ab1SKenneth D. Merry  *
339*ef270ab1SKenneth D. Merry  * @return Returns 0 on success; or a negative error code value on failure.
340*ef270ab1SKenneth D. Merry  */
341*ef270ab1SKenneth D. Merry 
342*ef270ab1SKenneth D. Merry static void
ocs_els_make_active(ocs_io_t * els)343*ef270ab1SKenneth D. Merry ocs_els_make_active(ocs_io_t *els)
344*ef270ab1SKenneth D. Merry {
345*ef270ab1SKenneth D. Merry 	ocs_node_t *node = els->node;
346*ef270ab1SKenneth D. Merry 
347*ef270ab1SKenneth D. Merry 	/* move ELS from pending list to active list */
348*ef270ab1SKenneth D. Merry 	ocs_lock(&node->active_ios_lock);
349*ef270ab1SKenneth D. Merry 		if (els->els_pend) {
350*ef270ab1SKenneth D. Merry 			if (els->els_active) {
351*ef270ab1SKenneth D. Merry 				ocs_log_err(node->ocs, "assertion failed: both els->els_pend and els->active set\n");
352*ef270ab1SKenneth D. Merry 				ocs_unlock(&node->active_ios_lock);
353*ef270ab1SKenneth D. Merry 				return;
354*ef270ab1SKenneth D. Merry 			} else {
355*ef270ab1SKenneth D. Merry 				/* remove from pending list */
356*ef270ab1SKenneth D. Merry 				ocs_list_remove(&node->els_io_pend_list, els);
357*ef270ab1SKenneth D. Merry 				els->els_pend = 0;
358*ef270ab1SKenneth D. Merry 
359*ef270ab1SKenneth D. Merry 				/* add els structure to ELS IO list */
360*ef270ab1SKenneth D. Merry 				ocs_list_add_tail(&node->els_io_active_list, els);
361*ef270ab1SKenneth D. Merry 				els->els_active = 1;
362*ef270ab1SKenneth D. Merry 			}
363*ef270ab1SKenneth D. Merry 		} else {
364*ef270ab1SKenneth D. Merry 			/* must be retrying; make sure it's already active */
365*ef270ab1SKenneth D. Merry 			if (!els->els_active) {
366*ef270ab1SKenneth D. Merry 				ocs_log_err(node->ocs, "assertion failed: niether els->els_pend nor els->active set\n");
367*ef270ab1SKenneth D. Merry 			}
368*ef270ab1SKenneth D. Merry 		}
369*ef270ab1SKenneth D. Merry 	ocs_unlock(&node->active_ios_lock);
370*ef270ab1SKenneth D. Merry }
371*ef270ab1SKenneth D. Merry 
372*ef270ab1SKenneth D. Merry /**
373*ef270ab1SKenneth D. Merry  * @ingroup els_api
374*ef270ab1SKenneth D. Merry  * @brief Send the ELS command.
375*ef270ab1SKenneth D. Merry  *
376*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
377*ef270ab1SKenneth D. Merry  * The command, given by the \c els IO context, is sent to the node that the IO was
378*ef270ab1SKenneth D. Merry  * configured with, using ocs_hw_srrs_send(). Upon completion,
379*ef270ab1SKenneth D. Merry  * the \c cb callback is invoked,
380*ef270ab1SKenneth D. Merry  * with the application-specific argument set to the \c els IO context.
381*ef270ab1SKenneth D. Merry  *
382*ef270ab1SKenneth D. Merry  * @param els Pointer to the IO context.
383*ef270ab1SKenneth D. Merry  * @param reqlen Byte count in the payload to send.
384*ef270ab1SKenneth D. Merry  * @param timeout_sec Command timeout, in seconds (0 -> 2*R_A_TOV).
385*ef270ab1SKenneth D. Merry  * @param cb Completion callback.
386*ef270ab1SKenneth D. Merry  *
387*ef270ab1SKenneth D. Merry  * @return Returns 0 on success; or a negative error code value on failure.
388*ef270ab1SKenneth D. Merry  */
389*ef270ab1SKenneth D. Merry 
390*ef270ab1SKenneth D. Merry static int32_t
ocs_els_send(ocs_io_t * els,uint32_t reqlen,uint32_t timeout_sec,ocs_hw_srrs_cb_t cb)391*ef270ab1SKenneth D. Merry ocs_els_send(ocs_io_t *els, uint32_t reqlen, uint32_t timeout_sec, ocs_hw_srrs_cb_t cb)
392*ef270ab1SKenneth D. Merry {
393*ef270ab1SKenneth D. Merry 	ocs_node_t *node = els->node;
394*ef270ab1SKenneth D. Merry 
395*ef270ab1SKenneth D. Merry 	/* update ELS request counter */
396*ef270ab1SKenneth D. Merry 	node->els_req_cnt++;
397*ef270ab1SKenneth D. Merry 
398*ef270ab1SKenneth D. Merry 	/* move ELS from pending list to active list */
399*ef270ab1SKenneth D. Merry 	ocs_els_make_active(els);
400*ef270ab1SKenneth D. Merry 
401*ef270ab1SKenneth D. Merry 	els->wire_len = reqlen;
402*ef270ab1SKenneth D. Merry 	return ocs_scsi_io_dispatch(els, cb);
403*ef270ab1SKenneth D. Merry }
404*ef270ab1SKenneth D. Merry 
405*ef270ab1SKenneth D. Merry /**
406*ef270ab1SKenneth D. Merry  * @ingroup els_api
407*ef270ab1SKenneth D. Merry  * @brief Send the ELS response.
408*ef270ab1SKenneth D. Merry  *
409*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
410*ef270ab1SKenneth D. Merry  * The ELS response, given by the \c els IO context, is sent to the node
411*ef270ab1SKenneth D. Merry  * that the IO was configured with, using ocs_hw_srrs_send().
412*ef270ab1SKenneth D. Merry  *
413*ef270ab1SKenneth D. Merry  * @param els Pointer to the IO context.
414*ef270ab1SKenneth D. Merry  * @param rsplen Byte count in the payload to send.
415*ef270ab1SKenneth D. Merry  *
416*ef270ab1SKenneth D. Merry  * @return Returns 0 on success; or a negative error value on failure.
417*ef270ab1SKenneth D. Merry  */
418*ef270ab1SKenneth D. Merry 
419*ef270ab1SKenneth D. Merry static int32_t
ocs_els_send_rsp(ocs_io_t * els,uint32_t rsplen)420*ef270ab1SKenneth D. Merry ocs_els_send_rsp(ocs_io_t *els, uint32_t rsplen)
421*ef270ab1SKenneth D. Merry {
422*ef270ab1SKenneth D. Merry 	ocs_node_t *node = els->node;
423*ef270ab1SKenneth D. Merry 
424*ef270ab1SKenneth D. Merry 	/* increment ELS completion counter */
425*ef270ab1SKenneth D. Merry 	node->els_cmpl_cnt++;
426*ef270ab1SKenneth D. Merry 
427*ef270ab1SKenneth D. Merry 	/* move ELS from pending list to active list */
428*ef270ab1SKenneth D. Merry 	ocs_els_make_active(els);
429*ef270ab1SKenneth D. Merry 
430*ef270ab1SKenneth D. Merry 	els->wire_len = rsplen;
431*ef270ab1SKenneth D. Merry 	return ocs_scsi_io_dispatch(els, ocs_els_acc_cb);
432*ef270ab1SKenneth D. Merry }
433*ef270ab1SKenneth D. Merry 
434*ef270ab1SKenneth D. Merry /**
435*ef270ab1SKenneth D. Merry  * @ingroup els_api
436*ef270ab1SKenneth D. Merry  * @brief Handle ELS IO request completions.
437*ef270ab1SKenneth D. Merry  *
438*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
439*ef270ab1SKenneth D. Merry  * This callback is used for several ELS send operations.
440*ef270ab1SKenneth D. Merry  *
441*ef270ab1SKenneth D. Merry  * @param hio Pointer to the HW IO context that completed.
442*ef270ab1SKenneth D. Merry  * @param rnode Pointer to the remote node.
443*ef270ab1SKenneth D. Merry  * @param length Length of the returned payload data.
444*ef270ab1SKenneth D. Merry  * @param status Status of the completion.
445*ef270ab1SKenneth D. Merry  * @param ext_status Extended status of the completion.
446*ef270ab1SKenneth D. Merry  * @param arg Application-specific argument (generally a pointer to the ELS IO context).
447*ef270ab1SKenneth D. Merry  *
448*ef270ab1SKenneth D. Merry  * @return Returns 0 on success; or a negative error value on failure.
449*ef270ab1SKenneth D. Merry  */
450*ef270ab1SKenneth D. Merry 
451*ef270ab1SKenneth D. Merry static int32_t
ocs_els_req_cb(ocs_hw_io_t * hio,ocs_remote_node_t * rnode,uint32_t length,int32_t status,uint32_t ext_status,void * arg)452*ef270ab1SKenneth D. Merry ocs_els_req_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *arg)
453*ef270ab1SKenneth D. Merry {
454*ef270ab1SKenneth D. Merry 	ocs_io_t *els;
455*ef270ab1SKenneth D. Merry 	ocs_node_t *node;
456*ef270ab1SKenneth D. Merry 	ocs_t *ocs;
457*ef270ab1SKenneth D. Merry 	ocs_node_cb_t cbdata;
458*ef270ab1SKenneth D. Merry 	ocs_io_t *io;
459*ef270ab1SKenneth D. Merry 
460*ef270ab1SKenneth D. Merry 	ocs_assert(arg, -1);
461*ef270ab1SKenneth D. Merry 	io = arg;
462*ef270ab1SKenneth D. Merry 	els = io;
463*ef270ab1SKenneth D. Merry 	ocs_assert(els, -1);
464*ef270ab1SKenneth D. Merry 	ocs_assert(els->node, -1);
465*ef270ab1SKenneth D. Merry 	node = els->node;
466*ef270ab1SKenneth D. Merry 	ocs_assert(node->ocs, -1);
467*ef270ab1SKenneth D. Merry 	ocs = node->ocs;
468*ef270ab1SKenneth D. Merry 
469*ef270ab1SKenneth D. Merry 	ocs_assert(io->hio, -1);
470*ef270ab1SKenneth D. Merry 	ocs_assert(hio == io->hio, -1);
471*ef270ab1SKenneth D. Merry 
472*ef270ab1SKenneth D. Merry 	if (status != 0) {
473*ef270ab1SKenneth D. Merry 		els_io_printf(els, "status x%x ext x%x\n", status, ext_status);
474*ef270ab1SKenneth D. Merry 	}
475*ef270ab1SKenneth D. Merry 
476*ef270ab1SKenneth D. Merry 	/* set the response len element of els->rsp */
477*ef270ab1SKenneth D. Merry 	els->els_rsp.len = length;
478*ef270ab1SKenneth D. Merry 
479*ef270ab1SKenneth D. Merry 	cbdata.status = status;
480*ef270ab1SKenneth D. Merry 	cbdata.ext_status = ext_status;
481*ef270ab1SKenneth D. Merry 	cbdata.header = NULL;
482*ef270ab1SKenneth D. Merry 	cbdata.els = els;
483*ef270ab1SKenneth D. Merry 
484*ef270ab1SKenneth D. Merry 	/* FW returns the number of bytes received on the link in
485*ef270ab1SKenneth D. Merry 	 * the WCQE, not the amount placed in the buffer; use this info to
486*ef270ab1SKenneth D. Merry 	 * check if there was an overrun.
487*ef270ab1SKenneth D. Merry 	 */
488*ef270ab1SKenneth D. Merry 	if (length > els->els_rsp.size) {
489*ef270ab1SKenneth D. Merry 		ocs_log_warn(ocs, "ELS response returned len=%d > buflen=%zu\n",
490*ef270ab1SKenneth D. Merry 				length, els->els_rsp.size);
491*ef270ab1SKenneth D. Merry 		ocs_els_post_event(els, OCS_EVT_SRRS_ELS_REQ_FAIL, &cbdata);
492*ef270ab1SKenneth D. Merry 		return 0;
493*ef270ab1SKenneth D. Merry 	}
494*ef270ab1SKenneth D. Merry 
495*ef270ab1SKenneth D. Merry 	/* Post event to ELS IO object */
496*ef270ab1SKenneth D. Merry 	switch (status) {
497*ef270ab1SKenneth D. Merry 	case SLI4_FC_WCQE_STATUS_SUCCESS:
498*ef270ab1SKenneth D. Merry 		ocs_els_post_event(els, OCS_EVT_SRRS_ELS_REQ_OK, &cbdata);
499*ef270ab1SKenneth D. Merry 		break;
500*ef270ab1SKenneth D. Merry 
501*ef270ab1SKenneth D. Merry 	case SLI4_FC_WCQE_STATUS_LS_RJT:
502*ef270ab1SKenneth D. Merry 		ocs_els_post_event(els, OCS_EVT_SRRS_ELS_REQ_RJT, &cbdata);
503*ef270ab1SKenneth D. Merry 		break;
504*ef270ab1SKenneth D. Merry 
505*ef270ab1SKenneth D. Merry 	case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
506*ef270ab1SKenneth D. Merry 		switch (ext_status) {
507*ef270ab1SKenneth D. Merry 		case SLI4_FC_LOCAL_REJECT_SEQUENCE_TIMEOUT:
508*ef270ab1SKenneth D. Merry 			ocs_els_post_event(els, OCS_EVT_ELS_REQ_TIMEOUT, &cbdata);
509*ef270ab1SKenneth D. Merry 			break;
510*ef270ab1SKenneth D. Merry 		case SLI4_FC_LOCAL_REJECT_ABORT_REQUESTED:
511*ef270ab1SKenneth D. Merry 			ocs_els_post_event(els, OCS_EVT_ELS_REQ_ABORTED, &cbdata);
512*ef270ab1SKenneth D. Merry 			break;
513*ef270ab1SKenneth D. Merry 		default:
514*ef270ab1SKenneth D. Merry 			ocs_els_post_event(els, OCS_EVT_SRRS_ELS_REQ_FAIL, &cbdata);
515*ef270ab1SKenneth D. Merry 			break;
516*ef270ab1SKenneth D. Merry 		}
517*ef270ab1SKenneth D. Merry 		break;
518*ef270ab1SKenneth D. Merry 	default:
519*ef270ab1SKenneth D. Merry 		ocs_log_warn(ocs, "els req complete: failed status x%x, ext_status, x%x\n", status, ext_status);
520*ef270ab1SKenneth D. Merry 		ocs_els_post_event(els, OCS_EVT_SRRS_ELS_REQ_FAIL, &cbdata);
521*ef270ab1SKenneth D. Merry 		break;
522*ef270ab1SKenneth D. Merry 	}
523*ef270ab1SKenneth D. Merry 
524*ef270ab1SKenneth D. Merry 	return 0;
525*ef270ab1SKenneth D. Merry }
526*ef270ab1SKenneth D. Merry 
527*ef270ab1SKenneth D. Merry /**
528*ef270ab1SKenneth D. Merry  * @ingroup els_api
529*ef270ab1SKenneth D. Merry  * @brief Handle ELS IO accept/response completions.
530*ef270ab1SKenneth D. Merry  *
531*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
532*ef270ab1SKenneth D. Merry  * This callback is used for several ELS send operations.
533*ef270ab1SKenneth D. Merry  *
534*ef270ab1SKenneth D. Merry  * @param hio Pointer to the HW IO context that completed.
535*ef270ab1SKenneth D. Merry  * @param rnode Pointer to the remote node.
536*ef270ab1SKenneth D. Merry  * @param length Length of the returned payload data.
537*ef270ab1SKenneth D. Merry  * @param status Status of the completion.
538*ef270ab1SKenneth D. Merry  * @param ext_status Extended status of the completion.
539*ef270ab1SKenneth D. Merry  * @param arg Application-specific argument (generally a pointer to the ELS IO context).
540*ef270ab1SKenneth D. Merry  *
541*ef270ab1SKenneth D. Merry  * @return Returns 0 on success; or a negative error value on failure.
542*ef270ab1SKenneth D. Merry  */
543*ef270ab1SKenneth D. Merry 
544*ef270ab1SKenneth D. Merry static int32_t
ocs_els_acc_cb(ocs_hw_io_t * hio,ocs_remote_node_t * rnode,uint32_t length,int32_t status,uint32_t ext_status,void * arg)545*ef270ab1SKenneth D. Merry ocs_els_acc_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *arg)
546*ef270ab1SKenneth D. Merry {
547*ef270ab1SKenneth D. Merry 	ocs_io_t *els;
548*ef270ab1SKenneth D. Merry 	ocs_node_t *node;
549*ef270ab1SKenneth D. Merry 	ocs_t *ocs;
550*ef270ab1SKenneth D. Merry 	ocs_node_cb_t cbdata;
551*ef270ab1SKenneth D. Merry 	ocs_io_t *io;
552*ef270ab1SKenneth D. Merry 
553*ef270ab1SKenneth D. Merry 	ocs_assert(arg, -1);
554*ef270ab1SKenneth D. Merry 	io = arg;
555*ef270ab1SKenneth D. Merry 	els = io;
556*ef270ab1SKenneth D. Merry 	ocs_assert(els, -1);
557*ef270ab1SKenneth D. Merry 	ocs_assert(els->node, -1);
558*ef270ab1SKenneth D. Merry 	node = els->node;
559*ef270ab1SKenneth D. Merry 	ocs_assert(node->ocs, -1);
560*ef270ab1SKenneth D. Merry 	ocs = node->ocs;
561*ef270ab1SKenneth D. Merry 
562*ef270ab1SKenneth D. Merry 	ocs_assert(io->hio, -1);
563*ef270ab1SKenneth D. Merry 	ocs_assert(hio == io->hio, -1);
564*ef270ab1SKenneth D. Merry 
565*ef270ab1SKenneth D. Merry 	cbdata.status = status;
566*ef270ab1SKenneth D. Merry 	cbdata.ext_status = ext_status;
567*ef270ab1SKenneth D. Merry 	cbdata.header = NULL;
568*ef270ab1SKenneth D. Merry 	cbdata.els = els;
569*ef270ab1SKenneth D. Merry 
570*ef270ab1SKenneth D. Merry 	/* Post node event */
571*ef270ab1SKenneth D. Merry 	switch (status) {
572*ef270ab1SKenneth D. Merry 	case SLI4_FC_WCQE_STATUS_SUCCESS:
573*ef270ab1SKenneth D. Merry 		ocs_node_post_event(node, OCS_EVT_SRRS_ELS_CMPL_OK, &cbdata);
574*ef270ab1SKenneth D. Merry 		break;
575*ef270ab1SKenneth D. Merry 
576*ef270ab1SKenneth D. Merry 	default:
577*ef270ab1SKenneth D. Merry 		ocs_log_warn(ocs, "[%s] %-8s failed status x%x, ext_status x%x\n",
578*ef270ab1SKenneth D. Merry 			node->display_name, els->display_name, status, ext_status);
579*ef270ab1SKenneth D. Merry 		ocs_log_warn(ocs, "els acc complete: failed status x%x, ext_status, x%x\n", status, ext_status);
580*ef270ab1SKenneth D. Merry 		ocs_node_post_event(node, OCS_EVT_SRRS_ELS_CMPL_FAIL, &cbdata);
581*ef270ab1SKenneth D. Merry 		break;
582*ef270ab1SKenneth D. Merry 	}
583*ef270ab1SKenneth D. Merry 
584*ef270ab1SKenneth D. Merry 	/* If this IO has a callback, invoke it */
585*ef270ab1SKenneth D. Merry 	if (els->els_callback) {
586*ef270ab1SKenneth D. Merry 		(*els->els_callback)(node, &cbdata, els->els_callback_arg);
587*ef270ab1SKenneth D. Merry 	}
588*ef270ab1SKenneth D. Merry 
589*ef270ab1SKenneth D. Merry 	ocs_els_io_free(els);
590*ef270ab1SKenneth D. Merry 
591*ef270ab1SKenneth D. Merry 	return 0;
592*ef270ab1SKenneth D. Merry }
593*ef270ab1SKenneth D. Merry 
594*ef270ab1SKenneth D. Merry /**
595*ef270ab1SKenneth D. Merry  * @ingroup els_api
596*ef270ab1SKenneth D. Merry  * @brief Format and send a PLOGI ELS command.
597*ef270ab1SKenneth D. Merry  *
598*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
599*ef270ab1SKenneth D. Merry  * Construct a PLOGI payload using the domain SLI port service parameters,
600*ef270ab1SKenneth D. Merry  * and send to the \c node.
601*ef270ab1SKenneth D. Merry  *
602*ef270ab1SKenneth D. Merry  * @param node Node to which the PLOGI is sent.
603*ef270ab1SKenneth D. Merry  * @param timeout_sec Command timeout, in seconds.
604*ef270ab1SKenneth D. Merry  * @param retries Number of times to retry errors before reporting a failure.
605*ef270ab1SKenneth D. Merry  * @param cb Callback function.
606*ef270ab1SKenneth D. Merry  * @param cbarg Callback function argument.
607*ef270ab1SKenneth D. Merry  *
608*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
609*ef270ab1SKenneth D. Merry  */
610*ef270ab1SKenneth D. Merry 
611*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_send_plogi(ocs_node_t * node,uint32_t timeout_sec,uint32_t retries,void (* cb)(ocs_node_t * node,ocs_node_cb_t * cbdata,void * arg),void * cbarg)612*ef270ab1SKenneth D. Merry ocs_send_plogi(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
613*ef270ab1SKenneth D. Merry 	void (*cb)(ocs_node_t *node, ocs_node_cb_t *cbdata, void *arg), void *cbarg)
614*ef270ab1SKenneth D. Merry {
615*ef270ab1SKenneth D. Merry 	ocs_io_t *els;
616*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
617*ef270ab1SKenneth D. Merry 	fc_plogi_payload_t *plogi;
618*ef270ab1SKenneth D. Merry 
619*ef270ab1SKenneth D. Merry 	node_els_trace();
620*ef270ab1SKenneth D. Merry 
621*ef270ab1SKenneth D. Merry 	els = ocs_els_io_alloc(node, sizeof(*plogi), OCS_ELS_ROLE_ORIGINATOR);
622*ef270ab1SKenneth D. Merry 	if (els == NULL) {
623*ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "IO alloc failed\n");
624*ef270ab1SKenneth D. Merry 	} else {
625*ef270ab1SKenneth D. Merry 		els->els_timeout_sec = timeout_sec;
626*ef270ab1SKenneth D. Merry 		els->els_retries_remaining = retries;
627*ef270ab1SKenneth D. Merry 		els->els_callback = cb;
628*ef270ab1SKenneth D. Merry 		els->els_callback_arg = cbarg;
629*ef270ab1SKenneth D. Merry 		els->display_name = "plogi";
630*ef270ab1SKenneth D. Merry 
631*ef270ab1SKenneth D. Merry 		/* Build PLOGI request */
632*ef270ab1SKenneth D. Merry 		plogi = els->els_req.virt;
633*ef270ab1SKenneth D. Merry 
634*ef270ab1SKenneth D. Merry 		ocs_memcpy(plogi, node->sport->service_params, sizeof(*plogi));
635*ef270ab1SKenneth D. Merry 
636*ef270ab1SKenneth D. Merry 		plogi->command_code = FC_ELS_CMD_PLOGI;
637*ef270ab1SKenneth D. Merry 		plogi->resv1 = 0;
638*ef270ab1SKenneth D. Merry 
639*ef270ab1SKenneth D. Merry 		ocs_display_sparams(node->display_name, "plogi send req", 0, NULL, plogi->common_service_parameters);
640*ef270ab1SKenneth D. Merry 
641*ef270ab1SKenneth D. Merry 		els->hio_type = OCS_HW_ELS_REQ;
642*ef270ab1SKenneth D. Merry 		els->iparam.els.timeout = timeout_sec;
643*ef270ab1SKenneth D. Merry 
644*ef270ab1SKenneth D. Merry 		ocs_io_transition(els, __ocs_els_init, NULL);
645*ef270ab1SKenneth D. Merry 	}
646*ef270ab1SKenneth D. Merry 	return els;
647*ef270ab1SKenneth D. Merry }
648*ef270ab1SKenneth D. Merry 
649*ef270ab1SKenneth D. Merry /**
650*ef270ab1SKenneth D. Merry  * @ingroup els_api
651*ef270ab1SKenneth D. Merry  * @brief Format and send a FLOGI ELS command.
652*ef270ab1SKenneth D. Merry  *
653*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
654*ef270ab1SKenneth D. Merry  * Construct an FLOGI payload, and send to the \c node.
655*ef270ab1SKenneth D. Merry  *
656*ef270ab1SKenneth D. Merry  * @param node Node to which the FLOGI is sent.
657*ef270ab1SKenneth D. Merry  * @param timeout_sec Command timeout, in seconds.
658*ef270ab1SKenneth D. Merry  * @param retries Number of times to retry errors before reporting a failure.
659*ef270ab1SKenneth D. Merry  * @param cb Callback function.
660*ef270ab1SKenneth D. Merry  * @param cbarg Callback function argument.
661*ef270ab1SKenneth D. Merry  *
662*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
663*ef270ab1SKenneth D. Merry  */
664*ef270ab1SKenneth D. Merry 
665*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_send_flogi(ocs_node_t * node,uint32_t timeout_sec,uint32_t retries,els_cb_t cb,void * cbarg)666*ef270ab1SKenneth D. Merry ocs_send_flogi(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
667*ef270ab1SKenneth D. Merry 	els_cb_t cb, void *cbarg)
668*ef270ab1SKenneth D. Merry {
669*ef270ab1SKenneth D. Merry 	ocs_io_t *els;
670*ef270ab1SKenneth D. Merry 	ocs_t *ocs;
671*ef270ab1SKenneth D. Merry 	fc_plogi_payload_t *flogi;
672*ef270ab1SKenneth D. Merry 
673*ef270ab1SKenneth D. Merry 	ocs_assert(node, NULL);
674*ef270ab1SKenneth D. Merry 	ocs_assert(node->ocs, NULL);
675*ef270ab1SKenneth D. Merry 	ocs_assert(node->sport, NULL);
676*ef270ab1SKenneth D. Merry 	ocs = node->ocs;
677*ef270ab1SKenneth D. Merry 
678*ef270ab1SKenneth D. Merry 	node_els_trace();
679*ef270ab1SKenneth D. Merry 
680*ef270ab1SKenneth D. Merry 	els = ocs_els_io_alloc(node, sizeof(*flogi), OCS_ELS_ROLE_ORIGINATOR);
681*ef270ab1SKenneth D. Merry 	if (els == NULL) {
682*ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "IO alloc failed\n");
683*ef270ab1SKenneth D. Merry 	} else {
684*ef270ab1SKenneth D. Merry 		els->els_timeout_sec = timeout_sec;
685*ef270ab1SKenneth D. Merry 		els->els_retries_remaining = retries;
686*ef270ab1SKenneth D. Merry 		els->els_callback = cb;
687*ef270ab1SKenneth D. Merry 		els->els_callback_arg = cbarg;
688*ef270ab1SKenneth D. Merry 		els->display_name = "flogi";
689*ef270ab1SKenneth D. Merry 
690*ef270ab1SKenneth D. Merry 		/* Build FLOGI request */
691*ef270ab1SKenneth D. Merry 		flogi = els->els_req.virt;
692*ef270ab1SKenneth D. Merry 
693*ef270ab1SKenneth D. Merry 		ocs_memcpy(flogi, node->sport->service_params, sizeof(*flogi));
694*ef270ab1SKenneth D. Merry 		flogi->command_code = FC_ELS_CMD_FLOGI;
695*ef270ab1SKenneth D. Merry 		flogi->resv1 = 0;
696*ef270ab1SKenneth D. Merry 
697*ef270ab1SKenneth D. Merry 		/* Priority tagging support */
698*ef270ab1SKenneth D. Merry 		flogi->common_service_parameters[1] |= ocs_htobe32(1U << 23);
699*ef270ab1SKenneth D. Merry 
700*ef270ab1SKenneth D. Merry 		ocs_display_sparams(node->display_name, "flogi send req", 0, NULL, flogi->common_service_parameters);
701*ef270ab1SKenneth D. Merry 
702*ef270ab1SKenneth D. Merry 		els->hio_type = OCS_HW_ELS_REQ;
703*ef270ab1SKenneth D. Merry 		els->iparam.els.timeout = timeout_sec;
704*ef270ab1SKenneth D. Merry 		ocs_io_transition(els, __ocs_els_init, NULL);
705*ef270ab1SKenneth D. Merry 	}
706*ef270ab1SKenneth D. Merry 	return els;
707*ef270ab1SKenneth D. Merry }
708*ef270ab1SKenneth D. Merry 
709*ef270ab1SKenneth D. Merry /**
710*ef270ab1SKenneth D. Merry  * @ingroup els_api
711*ef270ab1SKenneth D. Merry  * @brief Format and send a FDISC ELS command.
712*ef270ab1SKenneth D. Merry  *
713*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
714*ef270ab1SKenneth D. Merry  * Construct an FDISC payload, and send to the \c node.
715*ef270ab1SKenneth D. Merry  *
716*ef270ab1SKenneth D. Merry  * @param node Node to which the FDISC is sent.
717*ef270ab1SKenneth D. Merry  * @param timeout_sec Command timeout, in seconds.
718*ef270ab1SKenneth D. Merry  * @param retries Number of times to retry errors before reporting a failure.
719*ef270ab1SKenneth D. Merry  * @param cb Callback function.
720*ef270ab1SKenneth D. Merry  * @param cbarg Callback function argument.
721*ef270ab1SKenneth D. Merry  *
722*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
723*ef270ab1SKenneth D. Merry  */
724*ef270ab1SKenneth D. Merry 
725*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_send_fdisc(ocs_node_t * node,uint32_t timeout_sec,uint32_t retries,els_cb_t cb,void * cbarg)726*ef270ab1SKenneth D. Merry ocs_send_fdisc(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
727*ef270ab1SKenneth D. Merry 	els_cb_t cb, void *cbarg)
728*ef270ab1SKenneth D. Merry {
729*ef270ab1SKenneth D. Merry 	ocs_io_t *els;
730*ef270ab1SKenneth D. Merry 	ocs_t *ocs;
731*ef270ab1SKenneth D. Merry 	fc_plogi_payload_t *fdisc;
732*ef270ab1SKenneth D. Merry 
733*ef270ab1SKenneth D. Merry 	ocs_assert(node, NULL);
734*ef270ab1SKenneth D. Merry 	ocs_assert(node->ocs, NULL);
735*ef270ab1SKenneth D. Merry 	ocs = node->ocs;
736*ef270ab1SKenneth D. Merry 
737*ef270ab1SKenneth D. Merry 	node_els_trace();
738*ef270ab1SKenneth D. Merry 
739*ef270ab1SKenneth D. Merry 	els = ocs_els_io_alloc(node, sizeof(*fdisc), OCS_ELS_ROLE_ORIGINATOR);
740*ef270ab1SKenneth D. Merry 	if (els == NULL) {
741*ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "IO alloc failed\n");
742*ef270ab1SKenneth D. Merry 	} else {
743*ef270ab1SKenneth D. Merry 		els->els_timeout_sec = timeout_sec;
744*ef270ab1SKenneth D. Merry 		els->els_retries_remaining = retries;
745*ef270ab1SKenneth D. Merry 		els->els_callback = cb;
746*ef270ab1SKenneth D. Merry 		els->els_callback_arg = cbarg;
747*ef270ab1SKenneth D. Merry 		els->display_name = "fdisc";
748*ef270ab1SKenneth D. Merry 
749*ef270ab1SKenneth D. Merry 		/* Build FDISC request */
750*ef270ab1SKenneth D. Merry 		fdisc = els->els_req.virt;
751*ef270ab1SKenneth D. Merry 
752*ef270ab1SKenneth D. Merry 		ocs_memcpy(fdisc, node->sport->service_params, sizeof(*fdisc));
753*ef270ab1SKenneth D. Merry 		fdisc->command_code = FC_ELS_CMD_FDISC;
754*ef270ab1SKenneth D. Merry 		fdisc->resv1 = 0;
755*ef270ab1SKenneth D. Merry 
756*ef270ab1SKenneth D. Merry 		ocs_display_sparams(node->display_name, "fdisc send req", 0, NULL, fdisc->common_service_parameters);
757*ef270ab1SKenneth D. Merry 
758*ef270ab1SKenneth D. Merry 		els->hio_type = OCS_HW_ELS_REQ;
759*ef270ab1SKenneth D. Merry 		els->iparam.els.timeout = timeout_sec;
760*ef270ab1SKenneth D. Merry 		ocs_io_transition(els, __ocs_els_init, NULL);
761*ef270ab1SKenneth D. Merry 	}
762*ef270ab1SKenneth D. Merry 	return els;
763*ef270ab1SKenneth D. Merry }
764*ef270ab1SKenneth D. Merry 
765*ef270ab1SKenneth D. Merry /**
766*ef270ab1SKenneth D. Merry  * @ingroup els_api
767*ef270ab1SKenneth D. Merry  * @brief Send a PRLI ELS command.
768*ef270ab1SKenneth D. Merry  *
769*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
770*ef270ab1SKenneth D. Merry  * Construct a PRLI ELS command, and send to the \c node.
771*ef270ab1SKenneth D. Merry  *
772*ef270ab1SKenneth D. Merry  * @param node Node to which the PRLI is sent.
773*ef270ab1SKenneth D. Merry  * @param timeout_sec Command timeout, in seconds.
774*ef270ab1SKenneth D. Merry  * @param retries Number of times to retry errors before reporting a failure.
775*ef270ab1SKenneth D. Merry  * @param cb Callback function.
776*ef270ab1SKenneth D. Merry  * @param cbarg Callback function argument.
777*ef270ab1SKenneth D. Merry  *
778*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
779*ef270ab1SKenneth D. Merry  */
780*ef270ab1SKenneth D. Merry 
781*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_send_prli(ocs_node_t * node,uint32_t timeout_sec,uint32_t retries,els_cb_t cb,void * cbarg)782*ef270ab1SKenneth D. Merry ocs_send_prli(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
783*ef270ab1SKenneth D. Merry 	els_cb_t cb, void *cbarg)
784*ef270ab1SKenneth D. Merry {
785*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
786*ef270ab1SKenneth D. Merry 	ocs_io_t *els;
787*ef270ab1SKenneth D. Merry 	fc_prli_payload_t *prli;
788*ef270ab1SKenneth D. Merry 
789*ef270ab1SKenneth D. Merry 	node_els_trace();
790*ef270ab1SKenneth D. Merry 
791*ef270ab1SKenneth D. Merry 	els = ocs_els_io_alloc(node, sizeof(*prli), OCS_ELS_ROLE_ORIGINATOR);
792*ef270ab1SKenneth D. Merry 	if (els == NULL) {
793*ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "IO alloc failed\n");
794*ef270ab1SKenneth D. Merry 	} else {
795*ef270ab1SKenneth D. Merry 		els->els_timeout_sec = timeout_sec;
796*ef270ab1SKenneth D. Merry 		els->els_retries_remaining = retries;
797*ef270ab1SKenneth D. Merry 		els->els_callback = cb;
798*ef270ab1SKenneth D. Merry 		els->els_callback_arg = cbarg;
799*ef270ab1SKenneth D. Merry 		els->display_name = "prli";
800*ef270ab1SKenneth D. Merry 
801*ef270ab1SKenneth D. Merry 		/* Build PRLI request */
802*ef270ab1SKenneth D. Merry 		prli = els->els_req.virt;
803*ef270ab1SKenneth D. Merry 
804*ef270ab1SKenneth D. Merry 		ocs_memset(prli, 0, sizeof(*prli));
805*ef270ab1SKenneth D. Merry 
806*ef270ab1SKenneth D. Merry 		prli->command_code = FC_ELS_CMD_PRLI;
807*ef270ab1SKenneth D. Merry 		prli->page_length = 16;
808*ef270ab1SKenneth D. Merry 		prli->payload_length = ocs_htobe16(sizeof(fc_prli_payload_t));
809*ef270ab1SKenneth D. Merry 		prli->type = FC_TYPE_FCP;
810*ef270ab1SKenneth D. Merry 		prli->type_ext = 0;
811*ef270ab1SKenneth D. Merry 		prli->flags = ocs_htobe16(FC_PRLI_ESTABLISH_IMAGE_PAIR);
812*ef270ab1SKenneth D. Merry 		prli->service_params = ocs_htobe16(FC_PRLI_READ_XRDY_DISABLED |
813*ef270ab1SKenneth D. Merry 			(node->sport->enable_ini ? FC_PRLI_INITIATOR_FUNCTION : 0) |
814*ef270ab1SKenneth D. Merry 			(node->sport->enable_tgt ? FC_PRLI_TARGET_FUNCTION : 0));
815*ef270ab1SKenneth D. Merry 
816*ef270ab1SKenneth D. Merry 		/* For Tape Drive support */
817*ef270ab1SKenneth D. Merry 		prli->service_params |= ocs_htobe16(FC_PRLI_CONFIRMED_COMPLETION | FC_PRLI_RETRY |
818*ef270ab1SKenneth D. Merry 				 FC_PRLI_TASK_RETRY_ID_REQ| FC_PRLI_REC_SUPPORT);
819*ef270ab1SKenneth D. Merry 
820*ef270ab1SKenneth D. Merry 		els->hio_type = OCS_HW_ELS_REQ;
821*ef270ab1SKenneth D. Merry 		els->iparam.els.timeout = timeout_sec;
822*ef270ab1SKenneth D. Merry 		ocs_io_transition(els, __ocs_els_init, NULL);
823*ef270ab1SKenneth D. Merry 	}
824*ef270ab1SKenneth D. Merry 
825*ef270ab1SKenneth D. Merry 	return els;
826*ef270ab1SKenneth D. Merry }
827*ef270ab1SKenneth D. Merry 
828*ef270ab1SKenneth D. Merry /**
829*ef270ab1SKenneth D. Merry  * @ingroup els_api
830*ef270ab1SKenneth D. Merry  * @brief Send a PRLO ELS command.
831*ef270ab1SKenneth D. Merry  *
832*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
833*ef270ab1SKenneth D. Merry  * Construct a PRLO ELS command, and send to the \c node.
834*ef270ab1SKenneth D. Merry  *
835*ef270ab1SKenneth D. Merry  * @param node Node to which the PRLO is sent.
836*ef270ab1SKenneth D. Merry  * @param timeout_sec Command timeout, in seconds.
837*ef270ab1SKenneth D. Merry  * @param retries Number of times to retry errors before reporting a failure.
838*ef270ab1SKenneth D. Merry  * @param cb Callback function.
839*ef270ab1SKenneth D. Merry  * @param cbarg Callback function argument.
840*ef270ab1SKenneth D. Merry  *
841*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
842*ef270ab1SKenneth D. Merry  */
843*ef270ab1SKenneth D. Merry 
844*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_send_prlo(ocs_node_t * node,uint32_t timeout_sec,uint32_t retries,els_cb_t cb,void * cbarg)845*ef270ab1SKenneth D. Merry ocs_send_prlo(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
846*ef270ab1SKenneth D. Merry 	els_cb_t cb, void *cbarg)
847*ef270ab1SKenneth D. Merry {
848*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
849*ef270ab1SKenneth D. Merry 	ocs_io_t *els;
850*ef270ab1SKenneth D. Merry 	fc_prlo_payload_t *prlo;
851*ef270ab1SKenneth D. Merry 
852*ef270ab1SKenneth D. Merry 	node_els_trace();
853*ef270ab1SKenneth D. Merry 
854*ef270ab1SKenneth D. Merry 	els = ocs_els_io_alloc(node, sizeof(*prlo), OCS_ELS_ROLE_ORIGINATOR);
855*ef270ab1SKenneth D. Merry 	if (els == NULL) {
856*ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "IO alloc failed\n");
857*ef270ab1SKenneth D. Merry 	} else {
858*ef270ab1SKenneth D. Merry 		els->els_timeout_sec = timeout_sec;
859*ef270ab1SKenneth D. Merry 		els->els_retries_remaining = retries;
860*ef270ab1SKenneth D. Merry 		els->els_callback = cb;
861*ef270ab1SKenneth D. Merry 		els->els_callback_arg = cbarg;
862*ef270ab1SKenneth D. Merry 		els->display_name = "prlo";
863*ef270ab1SKenneth D. Merry 
864*ef270ab1SKenneth D. Merry 		/* Build PRLO request */
865*ef270ab1SKenneth D. Merry 		prlo = els->els_req.virt;
866*ef270ab1SKenneth D. Merry 
867*ef270ab1SKenneth D. Merry 		ocs_memset(prlo, 0, sizeof(*prlo));
868*ef270ab1SKenneth D. Merry 		prlo->command_code = FC_ELS_CMD_PRLO;
869*ef270ab1SKenneth D. Merry 		prlo->page_length = 16;
870*ef270ab1SKenneth D. Merry 		prlo->payload_length = ocs_htobe16(sizeof(fc_prlo_payload_t));
871*ef270ab1SKenneth D. Merry 		prlo->type = FC_TYPE_FCP;
872*ef270ab1SKenneth D. Merry 		prlo->type_ext = 0;
873*ef270ab1SKenneth D. Merry 
874*ef270ab1SKenneth D. Merry 		els->hio_type = OCS_HW_ELS_REQ;
875*ef270ab1SKenneth D. Merry 		els->iparam.els.timeout = timeout_sec;
876*ef270ab1SKenneth D. Merry 		ocs_io_transition(els, __ocs_els_init, NULL);
877*ef270ab1SKenneth D. Merry 	}
878*ef270ab1SKenneth D. Merry 	return els;
879*ef270ab1SKenneth D. Merry }
880*ef270ab1SKenneth D. Merry 
881*ef270ab1SKenneth D. Merry /**
882*ef270ab1SKenneth D. Merry  * @ingroup els_api
883*ef270ab1SKenneth D. Merry  * @brief Send a LOGO ELS command.
884*ef270ab1SKenneth D. Merry  *
885*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
886*ef270ab1SKenneth D. Merry  * Format a LOGO, and send to the \c node.
887*ef270ab1SKenneth D. Merry  *
888*ef270ab1SKenneth D. Merry  * @param node Node to which the LOGO is sent.
889*ef270ab1SKenneth D. Merry  * @param timeout_sec Command timeout, in seconds.
890*ef270ab1SKenneth D. Merry  * @param retries Number of times to retry errors before reporting a failure.
891*ef270ab1SKenneth D. Merry  * @param cb Callback function.
892*ef270ab1SKenneth D. Merry  * @param cbarg Callback function argument.
893*ef270ab1SKenneth D. Merry  *
894*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
895*ef270ab1SKenneth D. Merry  */
896*ef270ab1SKenneth D. Merry 
897*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_send_logo(ocs_node_t * node,uint32_t timeout_sec,uint32_t retries,els_cb_t cb,void * cbarg)898*ef270ab1SKenneth D. Merry ocs_send_logo(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
899*ef270ab1SKenneth D. Merry 	els_cb_t cb, void *cbarg)
900*ef270ab1SKenneth D. Merry {
901*ef270ab1SKenneth D. Merry 	ocs_io_t *els;
902*ef270ab1SKenneth D. Merry 	ocs_t *ocs;
903*ef270ab1SKenneth D. Merry 	fc_logo_payload_t *logo;
904*ef270ab1SKenneth D. Merry 	fc_plogi_payload_t *sparams;
905*ef270ab1SKenneth D. Merry 
906*ef270ab1SKenneth D. Merry 	ocs = node->ocs;
907*ef270ab1SKenneth D. Merry 
908*ef270ab1SKenneth D. Merry 	node_els_trace();
909*ef270ab1SKenneth D. Merry 
910*ef270ab1SKenneth D. Merry 	sparams = (fc_plogi_payload_t*) node->sport->service_params;
911*ef270ab1SKenneth D. Merry 
912*ef270ab1SKenneth D. Merry 	els = ocs_els_io_alloc(node, sizeof(*logo), OCS_ELS_ROLE_ORIGINATOR);
913*ef270ab1SKenneth D. Merry 	if (els == NULL) {
914*ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "IO alloc failed\n");
915*ef270ab1SKenneth D. Merry 	} else {
916*ef270ab1SKenneth D. Merry 		els->els_timeout_sec = timeout_sec;
917*ef270ab1SKenneth D. Merry 		els->els_retries_remaining = retries;
918*ef270ab1SKenneth D. Merry 		els->els_callback = cb;
919*ef270ab1SKenneth D. Merry 		els->els_callback_arg = cbarg;
920*ef270ab1SKenneth D. Merry 		els->display_name = "logo";
921*ef270ab1SKenneth D. Merry 
922*ef270ab1SKenneth D. Merry 		/* Build LOGO request */
923*ef270ab1SKenneth D. Merry 
924*ef270ab1SKenneth D. Merry 		logo = els->els_req.virt;
925*ef270ab1SKenneth D. Merry 
926*ef270ab1SKenneth D. Merry 		ocs_memset(logo, 0, sizeof(*logo));
927*ef270ab1SKenneth D. Merry 		logo->command_code = FC_ELS_CMD_LOGO;
928*ef270ab1SKenneth D. Merry 		logo->resv1 = 0;
929*ef270ab1SKenneth D. Merry 		logo->port_id = fc_htobe24(node->rnode.sport->fc_id);
930*ef270ab1SKenneth D. Merry 		logo->port_name_hi = sparams->port_name_hi;
931*ef270ab1SKenneth D. Merry 		logo->port_name_lo = sparams->port_name_lo;
932*ef270ab1SKenneth D. Merry 
933*ef270ab1SKenneth D. Merry 		els->hio_type = OCS_HW_ELS_REQ;
934*ef270ab1SKenneth D. Merry 		els->iparam.els.timeout = timeout_sec;
935*ef270ab1SKenneth D. Merry 		ocs_io_transition(els, __ocs_els_init, NULL);
936*ef270ab1SKenneth D. Merry 	}
937*ef270ab1SKenneth D. Merry 	return els;
938*ef270ab1SKenneth D. Merry }
939*ef270ab1SKenneth D. Merry 
940*ef270ab1SKenneth D. Merry /**
941*ef270ab1SKenneth D. Merry  * @ingroup els_api
942*ef270ab1SKenneth D. Merry  * @brief Send an ADISC ELS command.
943*ef270ab1SKenneth D. Merry  *
944*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
945*ef270ab1SKenneth D. Merry  * Construct an ADISC ELS command, and send to the \c node.
946*ef270ab1SKenneth D. Merry  *
947*ef270ab1SKenneth D. Merry  * @param node Node to which the ADISC is sent.
948*ef270ab1SKenneth D. Merry  * @param timeout_sec Command timeout, in seconds.
949*ef270ab1SKenneth D. Merry  * @param retries Number of times to retry errors before reporting a failure.
950*ef270ab1SKenneth D. Merry  * @param cb Callback function.
951*ef270ab1SKenneth D. Merry  * @param cbarg Callback function argument.
952*ef270ab1SKenneth D. Merry  *
953*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
954*ef270ab1SKenneth D. Merry  */
955*ef270ab1SKenneth D. Merry 
956*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_send_adisc(ocs_node_t * node,uint32_t timeout_sec,uint32_t retries,els_cb_t cb,void * cbarg)957*ef270ab1SKenneth D. Merry ocs_send_adisc(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
958*ef270ab1SKenneth D. Merry 	els_cb_t cb, void *cbarg)
959*ef270ab1SKenneth D. Merry {
960*ef270ab1SKenneth D. Merry 	ocs_io_t *els;
961*ef270ab1SKenneth D. Merry 	ocs_t *ocs;
962*ef270ab1SKenneth D. Merry 	fc_adisc_payload_t *adisc;
963*ef270ab1SKenneth D. Merry 	fc_plogi_payload_t *sparams;
964*ef270ab1SKenneth D. Merry 	ocs_sport_t *sport = node->sport;
965*ef270ab1SKenneth D. Merry 
966*ef270ab1SKenneth D. Merry 	ocs = node->ocs;
967*ef270ab1SKenneth D. Merry 
968*ef270ab1SKenneth D. Merry 	node_els_trace();
969*ef270ab1SKenneth D. Merry 
970*ef270ab1SKenneth D. Merry 	sparams = (fc_plogi_payload_t*) node->sport->service_params;
971*ef270ab1SKenneth D. Merry 
972*ef270ab1SKenneth D. Merry 	els = ocs_els_io_alloc(node, sizeof(*adisc), OCS_ELS_ROLE_ORIGINATOR);
973*ef270ab1SKenneth D. Merry 	if (els == NULL) {
974*ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "IO alloc failed\n");
975*ef270ab1SKenneth D. Merry 	} else {
976*ef270ab1SKenneth D. Merry 		els->els_timeout_sec = timeout_sec;
977*ef270ab1SKenneth D. Merry 		els->els_retries_remaining = retries;
978*ef270ab1SKenneth D. Merry 		els->els_callback = cb;
979*ef270ab1SKenneth D. Merry 		els->els_callback_arg = cbarg;
980*ef270ab1SKenneth D. Merry 		els->display_name = "adisc";
981*ef270ab1SKenneth D. Merry 
982*ef270ab1SKenneth D. Merry 		/* Build ADISC request */
983*ef270ab1SKenneth D. Merry 
984*ef270ab1SKenneth D. Merry 		adisc = els->els_req.virt;
985*ef270ab1SKenneth D. Merry 		sparams = (fc_plogi_payload_t*) node->sport->service_params;
986*ef270ab1SKenneth D. Merry 
987*ef270ab1SKenneth D. Merry 		ocs_memset(adisc, 0, sizeof(*adisc));
988*ef270ab1SKenneth D. Merry 		adisc->command_code = FC_ELS_CMD_ADISC;
989*ef270ab1SKenneth D. Merry 		adisc->hard_address = fc_htobe24(sport->fc_id);
990*ef270ab1SKenneth D. Merry 		adisc->port_name_hi = sparams->port_name_hi;
991*ef270ab1SKenneth D. Merry 		adisc->port_name_lo = sparams->port_name_lo;
992*ef270ab1SKenneth D. Merry 		adisc->node_name_hi = sparams->node_name_hi;
993*ef270ab1SKenneth D. Merry 		adisc->node_name_lo = sparams->node_name_lo;
994*ef270ab1SKenneth D. Merry 		adisc->port_id = fc_htobe24(node->rnode.sport->fc_id);
995*ef270ab1SKenneth D. Merry 
996*ef270ab1SKenneth D. Merry 		els->hio_type = OCS_HW_ELS_REQ;
997*ef270ab1SKenneth D. Merry 		els->iparam.els.timeout = timeout_sec;
998*ef270ab1SKenneth D. Merry 		ocs_io_transition(els, __ocs_els_init, NULL);
999*ef270ab1SKenneth D. Merry 	}
1000*ef270ab1SKenneth D. Merry 	return els;
1001*ef270ab1SKenneth D. Merry }
1002*ef270ab1SKenneth D. Merry 
1003*ef270ab1SKenneth D. Merry /**
1004*ef270ab1SKenneth D. Merry  * @ingroup els_api
1005*ef270ab1SKenneth D. Merry  * @brief Send a PDISC ELS command.
1006*ef270ab1SKenneth D. Merry  *
1007*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1008*ef270ab1SKenneth D. Merry  * Construct a PDISC ELS command, and send to the \c node.
1009*ef270ab1SKenneth D. Merry  *
1010*ef270ab1SKenneth D. Merry  * @param node Node to which the PDISC is sent.
1011*ef270ab1SKenneth D. Merry  * @param timeout_sec Command timeout, in seconds.
1012*ef270ab1SKenneth D. Merry  * @param retries Number of times to retry errors before reporting a failure.
1013*ef270ab1SKenneth D. Merry  * @param cb Callback function.
1014*ef270ab1SKenneth D. Merry  * @param cbarg Callback function argument.
1015*ef270ab1SKenneth D. Merry  *
1016*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
1017*ef270ab1SKenneth D. Merry  */
1018*ef270ab1SKenneth D. Merry 
1019*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_send_pdisc(ocs_node_t * node,uint32_t timeout_sec,uint32_t retries,els_cb_t cb,void * cbarg)1020*ef270ab1SKenneth D. Merry ocs_send_pdisc(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
1021*ef270ab1SKenneth D. Merry 	els_cb_t cb, void *cbarg)
1022*ef270ab1SKenneth D. Merry {
1023*ef270ab1SKenneth D. Merry 	ocs_io_t *els;
1024*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
1025*ef270ab1SKenneth D. Merry 	fc_plogi_payload_t *pdisc;
1026*ef270ab1SKenneth D. Merry 
1027*ef270ab1SKenneth D. Merry 	node_els_trace();
1028*ef270ab1SKenneth D. Merry 
1029*ef270ab1SKenneth D. Merry 	els = ocs_els_io_alloc(node, sizeof(*pdisc), OCS_ELS_ROLE_ORIGINATOR);
1030*ef270ab1SKenneth D. Merry 	if (els == NULL) {
1031*ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "IO alloc failed\n");
1032*ef270ab1SKenneth D. Merry 	} else {
1033*ef270ab1SKenneth D. Merry 		els->els_timeout_sec = timeout_sec;
1034*ef270ab1SKenneth D. Merry 		els->els_retries_remaining = retries;
1035*ef270ab1SKenneth D. Merry 		els->els_callback = cb;
1036*ef270ab1SKenneth D. Merry 		els->els_callback_arg = cbarg;
1037*ef270ab1SKenneth D. Merry 		els->display_name = "pdisc";
1038*ef270ab1SKenneth D. Merry 
1039*ef270ab1SKenneth D. Merry 		pdisc = els->els_req.virt;
1040*ef270ab1SKenneth D. Merry 
1041*ef270ab1SKenneth D. Merry 		ocs_memcpy(pdisc, node->sport->service_params, sizeof(*pdisc));
1042*ef270ab1SKenneth D. Merry 
1043*ef270ab1SKenneth D. Merry 		pdisc->command_code = FC_ELS_CMD_PDISC;
1044*ef270ab1SKenneth D. Merry 		pdisc->resv1 = 0;
1045*ef270ab1SKenneth D. Merry 
1046*ef270ab1SKenneth D. Merry 		els->hio_type = OCS_HW_ELS_REQ;
1047*ef270ab1SKenneth D. Merry 		els->iparam.els.timeout = timeout_sec;
1048*ef270ab1SKenneth D. Merry 		ocs_io_transition(els, __ocs_els_init, NULL);
1049*ef270ab1SKenneth D. Merry 	}
1050*ef270ab1SKenneth D. Merry 	return els;
1051*ef270ab1SKenneth D. Merry }
1052*ef270ab1SKenneth D. Merry 
1053*ef270ab1SKenneth D. Merry /**
1054*ef270ab1SKenneth D. Merry  * @ingroup els_api
1055*ef270ab1SKenneth D. Merry  * @brief Send an SCR ELS command.
1056*ef270ab1SKenneth D. Merry  *
1057*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1058*ef270ab1SKenneth D. Merry  * Format an SCR, and send to the \c node.
1059*ef270ab1SKenneth D. Merry  *
1060*ef270ab1SKenneth D. Merry  * @param node Node to which the SCR is sent.
1061*ef270ab1SKenneth D. Merry  * @param timeout_sec Command timeout, in seconds.
1062*ef270ab1SKenneth D. Merry  * @param retries Number of times to retry errors before reporting a failure.
1063*ef270ab1SKenneth D. Merry  * @param cb Callback function
1064*ef270ab1SKenneth D. Merry  * @param cbarg Callback function arg
1065*ef270ab1SKenneth D. Merry  *
1066*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
1067*ef270ab1SKenneth D. Merry  */
1068*ef270ab1SKenneth D. Merry 
1069*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_send_scr(ocs_node_t * node,uint32_t timeout_sec,uint32_t retries,els_cb_t cb,void * cbarg)1070*ef270ab1SKenneth D. Merry ocs_send_scr(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
1071*ef270ab1SKenneth D. Merry 	els_cb_t cb, void *cbarg)
1072*ef270ab1SKenneth D. Merry {
1073*ef270ab1SKenneth D. Merry 	ocs_io_t *els;
1074*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
1075*ef270ab1SKenneth D. Merry 	fc_scr_payload_t *req;
1076*ef270ab1SKenneth D. Merry 
1077*ef270ab1SKenneth D. Merry 	node_els_trace();
1078*ef270ab1SKenneth D. Merry 
1079*ef270ab1SKenneth D. Merry 	els = ocs_els_io_alloc(node, sizeof(*req), OCS_ELS_ROLE_ORIGINATOR);
1080*ef270ab1SKenneth D. Merry 	if (els == NULL) {
1081*ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "IO alloc failed\n");
1082*ef270ab1SKenneth D. Merry 	} else {
1083*ef270ab1SKenneth D. Merry 		els->els_timeout_sec = timeout_sec;
1084*ef270ab1SKenneth D. Merry 		els->els_retries_remaining = retries;
1085*ef270ab1SKenneth D. Merry 		els->els_callback = cb;
1086*ef270ab1SKenneth D. Merry 		els->els_callback_arg = cbarg;
1087*ef270ab1SKenneth D. Merry 		els->display_name = "scr";
1088*ef270ab1SKenneth D. Merry 
1089*ef270ab1SKenneth D. Merry 		req = els->els_req.virt;
1090*ef270ab1SKenneth D. Merry 
1091*ef270ab1SKenneth D. Merry 		ocs_memset(req, 0, sizeof(*req));
1092*ef270ab1SKenneth D. Merry 		req->command_code = FC_ELS_CMD_SCR;
1093*ef270ab1SKenneth D. Merry 		req->function = FC_SCR_REG_FULL;
1094*ef270ab1SKenneth D. Merry 
1095*ef270ab1SKenneth D. Merry 		els->hio_type = OCS_HW_ELS_REQ;
1096*ef270ab1SKenneth D. Merry 		els->iparam.els.timeout = timeout_sec;
1097*ef270ab1SKenneth D. Merry 		ocs_io_transition(els, __ocs_els_init, NULL);
1098*ef270ab1SKenneth D. Merry 	}
1099*ef270ab1SKenneth D. Merry 	return els;
1100*ef270ab1SKenneth D. Merry }
1101*ef270ab1SKenneth D. Merry 
1102*ef270ab1SKenneth D. Merry /**
1103*ef270ab1SKenneth D. Merry  * @ingroup els_api
1104*ef270ab1SKenneth D. Merry  * @brief Send an RRQ ELS command.
1105*ef270ab1SKenneth D. Merry  *
1106*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1107*ef270ab1SKenneth D. Merry  * Format an RRQ, and send to the \c node.
1108*ef270ab1SKenneth D. Merry  *
1109*ef270ab1SKenneth D. Merry  * @param node Node to which the RRQ is sent.
1110*ef270ab1SKenneth D. Merry  * @param timeout_sec Command timeout, in seconds.
1111*ef270ab1SKenneth D. Merry  * @param retries Number of times to retry errors before reporting a failure.
1112*ef270ab1SKenneth D. Merry  * @param cb Callback function
1113*ef270ab1SKenneth D. Merry  * @param cbarg Callback function arg
1114*ef270ab1SKenneth D. Merry  *
1115*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
1116*ef270ab1SKenneth D. Merry  */
1117*ef270ab1SKenneth D. Merry 
1118*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_send_rrq(ocs_node_t * node,uint32_t timeout_sec,uint32_t retries,els_cb_t cb,void * cbarg)1119*ef270ab1SKenneth D. Merry ocs_send_rrq(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
1120*ef270ab1SKenneth D. Merry 	els_cb_t cb, void *cbarg)
1121*ef270ab1SKenneth D. Merry {
1122*ef270ab1SKenneth D. Merry 	ocs_io_t *els;
1123*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
1124*ef270ab1SKenneth D. Merry 	fc_scr_payload_t *req;
1125*ef270ab1SKenneth D. Merry 
1126*ef270ab1SKenneth D. Merry 	node_els_trace();
1127*ef270ab1SKenneth D. Merry 
1128*ef270ab1SKenneth D. Merry 	els = ocs_els_io_alloc(node, sizeof(*req), OCS_ELS_ROLE_ORIGINATOR);
1129*ef270ab1SKenneth D. Merry 	if (els == NULL) {
1130*ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "IO alloc failed\n");
1131*ef270ab1SKenneth D. Merry 	} else {
1132*ef270ab1SKenneth D. Merry 		els->els_timeout_sec = timeout_sec;
1133*ef270ab1SKenneth D. Merry 		els->els_retries_remaining = retries;
1134*ef270ab1SKenneth D. Merry 		els->els_callback = cb;
1135*ef270ab1SKenneth D. Merry 		els->els_callback_arg = cbarg;
1136*ef270ab1SKenneth D. Merry 		els->display_name = "scr";
1137*ef270ab1SKenneth D. Merry 
1138*ef270ab1SKenneth D. Merry 		req = els->els_req.virt;
1139*ef270ab1SKenneth D. Merry 
1140*ef270ab1SKenneth D. Merry 		ocs_memset(req, 0, sizeof(*req));
1141*ef270ab1SKenneth D. Merry 		req->command_code = FC_ELS_CMD_RRQ;
1142*ef270ab1SKenneth D. Merry 		req->function = FC_SCR_REG_FULL;
1143*ef270ab1SKenneth D. Merry 
1144*ef270ab1SKenneth D. Merry 		els->hio_type = OCS_HW_ELS_REQ;
1145*ef270ab1SKenneth D. Merry 		els->iparam.els.timeout = timeout_sec;
1146*ef270ab1SKenneth D. Merry 		ocs_io_transition(els, __ocs_els_init, NULL);
1147*ef270ab1SKenneth D. Merry 	}
1148*ef270ab1SKenneth D. Merry 	return els;
1149*ef270ab1SKenneth D. Merry }
1150*ef270ab1SKenneth D. Merry 
1151*ef270ab1SKenneth D. Merry /**
1152*ef270ab1SKenneth D. Merry  * @ingroup els_api
1153*ef270ab1SKenneth D. Merry  * @brief Send an RSCN ELS command.
1154*ef270ab1SKenneth D. Merry  *
1155*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1156*ef270ab1SKenneth D. Merry  * Format an RSCN, and send to the \c node.
1157*ef270ab1SKenneth D. Merry  *
1158*ef270ab1SKenneth D. Merry  * @param node Node to which the RRQ is sent.
1159*ef270ab1SKenneth D. Merry  * @param timeout_sec Command timeout, in seconds.
1160*ef270ab1SKenneth D. Merry  * @param retries Number of times to retry errors before reporting a failure.
1161*ef270ab1SKenneth D. Merry  * @param port_ids Pointer to port IDs
1162*ef270ab1SKenneth D. Merry  * @param port_ids_count Count of port IDs
1163*ef270ab1SKenneth D. Merry  * @param cb Callback function
1164*ef270ab1SKenneth D. Merry  * @param cbarg Callback function arg
1165*ef270ab1SKenneth D. Merry  *
1166*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
1167*ef270ab1SKenneth D. Merry  */
1168*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_send_rscn(ocs_node_t * node,uint32_t timeout_sec,uint32_t retries,void * port_ids,uint32_t port_ids_count,els_cb_t cb,void * cbarg)1169*ef270ab1SKenneth D. Merry ocs_send_rscn(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
1170*ef270ab1SKenneth D. Merry 	void *port_ids, uint32_t port_ids_count, els_cb_t cb, void *cbarg)
1171*ef270ab1SKenneth D. Merry {
1172*ef270ab1SKenneth D. Merry 	ocs_io_t *els;
1173*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
1174*ef270ab1SKenneth D. Merry 	fc_rscn_payload_t *req;
1175*ef270ab1SKenneth D. Merry 	uint32_t payload_length = sizeof(fc_rscn_affected_port_id_page_t)*(port_ids_count - 1) +
1176*ef270ab1SKenneth D. Merry 		sizeof(fc_rscn_payload_t);
1177*ef270ab1SKenneth D. Merry 
1178*ef270ab1SKenneth D. Merry 	node_els_trace();
1179*ef270ab1SKenneth D. Merry 
1180*ef270ab1SKenneth D. Merry 	els = ocs_els_io_alloc(node, payload_length, OCS_ELS_ROLE_ORIGINATOR);
1181*ef270ab1SKenneth D. Merry 	if (els == NULL) {
1182*ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "IO alloc failed\n");
1183*ef270ab1SKenneth D. Merry 	} else {
1184*ef270ab1SKenneth D. Merry 		els->els_timeout_sec = timeout_sec;
1185*ef270ab1SKenneth D. Merry 		els->els_retries_remaining = retries;
1186*ef270ab1SKenneth D. Merry 		els->els_callback = cb;
1187*ef270ab1SKenneth D. Merry 		els->els_callback_arg = cbarg;
1188*ef270ab1SKenneth D. Merry 		els->display_name = "rscn";
1189*ef270ab1SKenneth D. Merry 
1190*ef270ab1SKenneth D. Merry 		req = els->els_req.virt;
1191*ef270ab1SKenneth D. Merry 
1192*ef270ab1SKenneth D. Merry 		req->command_code = FC_ELS_CMD_RSCN;
1193*ef270ab1SKenneth D. Merry 		req->page_length = sizeof(fc_rscn_affected_port_id_page_t);
1194*ef270ab1SKenneth D. Merry 		req->payload_length = ocs_htobe16(sizeof(*req) +
1195*ef270ab1SKenneth D. Merry 			sizeof(fc_rscn_affected_port_id_page_t)*(port_ids_count-1));
1196*ef270ab1SKenneth D. Merry 
1197*ef270ab1SKenneth D. Merry 		els->hio_type = OCS_HW_ELS_REQ;
1198*ef270ab1SKenneth D. Merry 		els->iparam.els.timeout = timeout_sec;
1199*ef270ab1SKenneth D. Merry 
1200*ef270ab1SKenneth D. Merry 		/* copy in the payload */
1201*ef270ab1SKenneth D. Merry 		ocs_memcpy(req->port_list, port_ids, port_ids_count*sizeof(fc_rscn_affected_port_id_page_t));
1202*ef270ab1SKenneth D. Merry 
1203*ef270ab1SKenneth D. Merry 		/* Submit the request */
1204*ef270ab1SKenneth D. Merry 		ocs_io_transition(els, __ocs_els_init, NULL);
1205*ef270ab1SKenneth D. Merry 	}
1206*ef270ab1SKenneth D. Merry 	return els;
1207*ef270ab1SKenneth D. Merry }
1208*ef270ab1SKenneth D. Merry 
1209*ef270ab1SKenneth D. Merry /**
1210*ef270ab1SKenneth D. Merry  * @brief Send an LS_RJT ELS response.
1211*ef270ab1SKenneth D. Merry  *
1212*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1213*ef270ab1SKenneth D. Merry  * Send an LS_RJT ELS response.
1214*ef270ab1SKenneth D. Merry  *
1215*ef270ab1SKenneth D. Merry  * @param io Pointer to a SCSI IO object.
1216*ef270ab1SKenneth D. Merry  * @param ox_id Originator exchange ID being responded to.
1217*ef270ab1SKenneth D. Merry  * @param reason_code Reason code value for LS_RJT.
1218*ef270ab1SKenneth D. Merry  * @param reason_code_expl Reason code explanation value for LS_RJT.
1219*ef270ab1SKenneth D. Merry  * @param vendor_unique Vendor-unique value for LS_RJT.
1220*ef270ab1SKenneth D. Merry  * @param cb Callback function.
1221*ef270ab1SKenneth D. Merry  * @param cbarg Callback function argument.
1222*ef270ab1SKenneth D. Merry  *
1223*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
1224*ef270ab1SKenneth D. Merry  */
1225*ef270ab1SKenneth D. Merry 
1226*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_send_ls_rjt(ocs_io_t * io,uint32_t ox_id,uint32_t reason_code,uint32_t reason_code_expl,uint32_t vendor_unique,els_cb_t cb,void * cbarg)1227*ef270ab1SKenneth D. Merry ocs_send_ls_rjt(ocs_io_t *io, uint32_t ox_id, uint32_t reason_code, uint32_t reason_code_expl,
1228*ef270ab1SKenneth D. Merry 		uint32_t vendor_unique, els_cb_t cb, void *cbarg)
1229*ef270ab1SKenneth D. Merry {
1230*ef270ab1SKenneth D. Merry 	ocs_node_t *node = io->node;
1231*ef270ab1SKenneth D. Merry 	int32_t rc;
1232*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
1233*ef270ab1SKenneth D. Merry 	fc_ls_rjt_payload_t *rjt;
1234*ef270ab1SKenneth D. Merry 
1235*ef270ab1SKenneth D. Merry 	node_els_trace();
1236*ef270ab1SKenneth D. Merry 
1237*ef270ab1SKenneth D. Merry 	io->els_callback = cb;
1238*ef270ab1SKenneth D. Merry 	io->els_callback_arg = cbarg;
1239*ef270ab1SKenneth D. Merry 	io->display_name = "ls_rjt";
1240*ef270ab1SKenneth D. Merry 	io->init_task_tag = ox_id;
1241*ef270ab1SKenneth D. Merry 
1242*ef270ab1SKenneth D. Merry 	ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1243*ef270ab1SKenneth D. Merry 	io->iparam.els.ox_id = ox_id;
1244*ef270ab1SKenneth D. Merry 
1245*ef270ab1SKenneth D. Merry 	rjt = io->els_req.virt;
1246*ef270ab1SKenneth D. Merry 	ocs_memset(rjt, 0, sizeof(*rjt));
1247*ef270ab1SKenneth D. Merry 
1248*ef270ab1SKenneth D. Merry 	rjt->command_code = FC_ELS_CMD_RJT;
1249*ef270ab1SKenneth D. Merry 	rjt->reason_code = reason_code;
1250*ef270ab1SKenneth D. Merry 	rjt->reason_code_exp = reason_code_expl;
1251*ef270ab1SKenneth D. Merry 
1252*ef270ab1SKenneth D. Merry 	io->hio_type = OCS_HW_ELS_RSP;
1253*ef270ab1SKenneth D. Merry 	if ((rc = ocs_els_send_rsp(io, sizeof(*rjt)))) {
1254*ef270ab1SKenneth D. Merry 		ocs_els_io_free(io);
1255*ef270ab1SKenneth D. Merry 		io = NULL;
1256*ef270ab1SKenneth D. Merry 	}
1257*ef270ab1SKenneth D. Merry 
1258*ef270ab1SKenneth D. Merry 	return io;
1259*ef270ab1SKenneth D. Merry }
1260*ef270ab1SKenneth D. Merry 
1261*ef270ab1SKenneth D. Merry /**
1262*ef270ab1SKenneth D. Merry  * @ingroup els_api
1263*ef270ab1SKenneth D. Merry  * @brief Send a PLOGI accept response.
1264*ef270ab1SKenneth D. Merry  *
1265*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1266*ef270ab1SKenneth D. Merry  * Construct a PLOGI LS_ACC, and send to the \c node, using the originator exchange ID
1267*ef270ab1SKenneth D. Merry  * \c ox_id.
1268*ef270ab1SKenneth D. Merry  *
1269*ef270ab1SKenneth D. Merry  * @param io Pointer to a SCSI IO object.
1270*ef270ab1SKenneth D. Merry  * @param ox_id Originator exchange ID being responsed to.
1271*ef270ab1SKenneth D. Merry  * @param cb Callback function.
1272*ef270ab1SKenneth D. Merry  * @param cbarg Callback function argument.
1273*ef270ab1SKenneth D. Merry  *
1274*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
1275*ef270ab1SKenneth D. Merry  */
1276*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_send_plogi_acc(ocs_io_t * io,uint32_t ox_id,els_cb_t cb,void * cbarg)1277*ef270ab1SKenneth D. Merry ocs_send_plogi_acc(ocs_io_t *io, uint32_t ox_id, els_cb_t cb, void *cbarg)
1278*ef270ab1SKenneth D. Merry {
1279*ef270ab1SKenneth D. Merry 	ocs_node_t *node = io->node;
1280*ef270ab1SKenneth D. Merry 	int32_t rc;
1281*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
1282*ef270ab1SKenneth D. Merry 	fc_plogi_payload_t *plogi;
1283*ef270ab1SKenneth D. Merry 	fc_plogi_payload_t *req = (fc_plogi_payload_t *)node->service_params;
1284*ef270ab1SKenneth D. Merry 
1285*ef270ab1SKenneth D. Merry 	node_els_trace();
1286*ef270ab1SKenneth D. Merry 
1287*ef270ab1SKenneth D. Merry 	io->els_callback = cb;
1288*ef270ab1SKenneth D. Merry 	io->els_callback_arg = cbarg;
1289*ef270ab1SKenneth D. Merry 	io->display_name = "plog_acc";
1290*ef270ab1SKenneth D. Merry 	io->init_task_tag = ox_id;
1291*ef270ab1SKenneth D. Merry 
1292*ef270ab1SKenneth D. Merry 	ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1293*ef270ab1SKenneth D. Merry 	io->iparam.els.ox_id = ox_id;
1294*ef270ab1SKenneth D. Merry 
1295*ef270ab1SKenneth D. Merry 	plogi = io->els_req.virt;
1296*ef270ab1SKenneth D. Merry 
1297*ef270ab1SKenneth D. Merry 	/* copy our port's service parameters to payload */
1298*ef270ab1SKenneth D. Merry 	ocs_memcpy(plogi, node->sport->service_params, sizeof(*plogi));
1299*ef270ab1SKenneth D. Merry 	plogi->command_code = FC_ELS_CMD_ACC;
1300*ef270ab1SKenneth D. Merry 	plogi->resv1 = 0;
1301*ef270ab1SKenneth D. Merry 
1302*ef270ab1SKenneth D. Merry 	/* Set Application header support bit if requested */
1303*ef270ab1SKenneth D. Merry 	if (req->common_service_parameters[1] & ocs_htobe32(1U << 24)) {
1304*ef270ab1SKenneth D. Merry 		plogi->common_service_parameters[1] |= ocs_htobe32(1U << 24);
1305*ef270ab1SKenneth D. Merry 	}
1306*ef270ab1SKenneth D. Merry 
1307*ef270ab1SKenneth D. Merry 	/* Priority tagging support. */
1308*ef270ab1SKenneth D. Merry 	if (req->common_service_parameters[1] & ocs_htobe32(1U << 23)) {
1309*ef270ab1SKenneth D. Merry 		plogi->common_service_parameters[1] |= ocs_htobe32(1U << 23);
1310*ef270ab1SKenneth D. Merry 	}
1311*ef270ab1SKenneth D. Merry 
1312*ef270ab1SKenneth D. Merry 	ocs_display_sparams(node->display_name, "plogi send resp", 0, NULL, plogi->common_service_parameters);
1313*ef270ab1SKenneth D. Merry 
1314*ef270ab1SKenneth D. Merry 	io->hio_type = OCS_HW_ELS_RSP;
1315*ef270ab1SKenneth D. Merry 	if ((rc = ocs_els_send_rsp(io, sizeof(*plogi)))) {
1316*ef270ab1SKenneth D. Merry 		ocs_els_io_free(io);
1317*ef270ab1SKenneth D. Merry 		io = NULL;
1318*ef270ab1SKenneth D. Merry 	}
1319*ef270ab1SKenneth D. Merry 	return io;
1320*ef270ab1SKenneth D. Merry }
1321*ef270ab1SKenneth D. Merry 
1322*ef270ab1SKenneth D. Merry /**
1323*ef270ab1SKenneth D. Merry  * @ingroup els_api
1324*ef270ab1SKenneth D. Merry  * @brief Send an FLOGI accept response for point-to-point negotiation.
1325*ef270ab1SKenneth D. Merry  *
1326*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1327*ef270ab1SKenneth D. Merry  * Construct an FLOGI accept response, and send to the \c node using the originator
1328*ef270ab1SKenneth D. Merry  * exchange id \c ox_id. The \c s_id is used for the response frame source FC ID.
1329*ef270ab1SKenneth D. Merry  *
1330*ef270ab1SKenneth D. Merry  * @param io Pointer to a SCSI IO object.
1331*ef270ab1SKenneth D. Merry  * @param ox_id Originator exchange ID for the response.
1332*ef270ab1SKenneth D. Merry  * @param s_id Source FC ID to be used in the response frame.
1333*ef270ab1SKenneth D. Merry  * @param cb Callback function.
1334*ef270ab1SKenneth D. Merry  * @param cbarg Callback function argument.
1335*ef270ab1SKenneth D. Merry  *
1336*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
1337*ef270ab1SKenneth D. Merry  */
1338*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_send_flogi_p2p_acc(ocs_io_t * io,uint32_t ox_id,uint32_t s_id,els_cb_t cb,void * cbarg)1339*ef270ab1SKenneth D. Merry ocs_send_flogi_p2p_acc(ocs_io_t *io, uint32_t ox_id, uint32_t s_id, els_cb_t cb, void *cbarg)
1340*ef270ab1SKenneth D. Merry {
1341*ef270ab1SKenneth D. Merry 	ocs_node_t *node = io->node;
1342*ef270ab1SKenneth D. Merry 	int32_t rc;
1343*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
1344*ef270ab1SKenneth D. Merry 	fc_plogi_payload_t *flogi;
1345*ef270ab1SKenneth D. Merry 
1346*ef270ab1SKenneth D. Merry 	node_els_trace();
1347*ef270ab1SKenneth D. Merry 
1348*ef270ab1SKenneth D. Merry 	io->els_callback = cb;
1349*ef270ab1SKenneth D. Merry 	io->els_callback_arg = cbarg;
1350*ef270ab1SKenneth D. Merry 	io->display_name = "flogi_p2p_acc";
1351*ef270ab1SKenneth D. Merry 	io->init_task_tag = ox_id;
1352*ef270ab1SKenneth D. Merry 
1353*ef270ab1SKenneth D. Merry 	ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1354*ef270ab1SKenneth D. Merry 	io->iparam.els_sid.ox_id = ox_id;
1355*ef270ab1SKenneth D. Merry 	io->iparam.els_sid.s_id = s_id;
1356*ef270ab1SKenneth D. Merry 
1357*ef270ab1SKenneth D. Merry 	flogi = io->els_req.virt;
1358*ef270ab1SKenneth D. Merry 
1359*ef270ab1SKenneth D. Merry 	/* copy our port's service parameters to payload */
1360*ef270ab1SKenneth D. Merry 	ocs_memcpy(flogi, node->sport->service_params, sizeof(*flogi));
1361*ef270ab1SKenneth D. Merry 	flogi->command_code = FC_ELS_CMD_ACC;
1362*ef270ab1SKenneth D. Merry 	flogi->resv1 = 0;
1363*ef270ab1SKenneth D. Merry 	ocs_memset(flogi->class1_service_parameters, 0, sizeof(flogi->class1_service_parameters));
1364*ef270ab1SKenneth D. Merry 	ocs_memset(flogi->class2_service_parameters, 0, sizeof(flogi->class1_service_parameters));
1365*ef270ab1SKenneth D. Merry 	ocs_memset(flogi->class3_service_parameters, 0, sizeof(flogi->class1_service_parameters));
1366*ef270ab1SKenneth D. Merry 	ocs_memset(flogi->class4_service_parameters, 0, sizeof(flogi->class1_service_parameters));
1367*ef270ab1SKenneth D. Merry 
1368*ef270ab1SKenneth D. Merry 	io->hio_type = OCS_HW_ELS_RSP_SID;
1369*ef270ab1SKenneth D. Merry 	if ((rc = ocs_els_send_rsp(io, sizeof(*flogi)))) {
1370*ef270ab1SKenneth D. Merry 		ocs_els_io_free(io);
1371*ef270ab1SKenneth D. Merry 		io = NULL;
1372*ef270ab1SKenneth D. Merry 	}
1373*ef270ab1SKenneth D. Merry 
1374*ef270ab1SKenneth D. Merry 	return io;
1375*ef270ab1SKenneth D. Merry }
1376*ef270ab1SKenneth D. Merry 
1377*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_send_flogi_acc(ocs_io_t * io,uint32_t ox_id,uint32_t is_fport,els_cb_t cb,void * cbarg)1378*ef270ab1SKenneth D. Merry ocs_send_flogi_acc(ocs_io_t *io, uint32_t ox_id, uint32_t is_fport, els_cb_t cb, void *cbarg)
1379*ef270ab1SKenneth D. Merry {
1380*ef270ab1SKenneth D. Merry 	ocs_node_t *node = io->node;
1381*ef270ab1SKenneth D. Merry 	int32_t rc;
1382*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
1383*ef270ab1SKenneth D. Merry 	fc_plogi_payload_t *flogi;
1384*ef270ab1SKenneth D. Merry 
1385*ef270ab1SKenneth D. Merry 	node_els_trace();
1386*ef270ab1SKenneth D. Merry 
1387*ef270ab1SKenneth D. Merry 	io->els_callback = cb;
1388*ef270ab1SKenneth D. Merry 	io->els_callback_arg = cbarg;
1389*ef270ab1SKenneth D. Merry 	io->display_name = "flogi_acc";
1390*ef270ab1SKenneth D. Merry 	io->init_task_tag = ox_id;
1391*ef270ab1SKenneth D. Merry 
1392*ef270ab1SKenneth D. Merry 	ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1393*ef270ab1SKenneth D. Merry 	io->iparam.els_sid.ox_id = ox_id;
1394*ef270ab1SKenneth D. Merry 	io->iparam.els_sid.s_id = io->node->sport->fc_id;
1395*ef270ab1SKenneth D. Merry 
1396*ef270ab1SKenneth D. Merry 	flogi = io->els_req.virt;
1397*ef270ab1SKenneth D. Merry 
1398*ef270ab1SKenneth D. Merry 	/* copy our port's service parameters to payload */
1399*ef270ab1SKenneth D. Merry 	ocs_memcpy(flogi, node->sport->service_params, sizeof(*flogi));
1400*ef270ab1SKenneth D. Merry 
1401*ef270ab1SKenneth D. Merry 	/* Set F_port */
1402*ef270ab1SKenneth D. Merry 	if (is_fport) {
1403*ef270ab1SKenneth D. Merry 		/* Set F_PORT and Multiple N_PORT_ID Assignment */
1404*ef270ab1SKenneth D. Merry 		flogi->common_service_parameters[1] |= ocs_be32toh(3U << 28);
1405*ef270ab1SKenneth D. Merry 	}
1406*ef270ab1SKenneth D. Merry 
1407*ef270ab1SKenneth D. Merry 	flogi->command_code = FC_ELS_CMD_ACC;
1408*ef270ab1SKenneth D. Merry 	flogi->resv1 = 0;
1409*ef270ab1SKenneth D. Merry 
1410*ef270ab1SKenneth D. Merry 	ocs_display_sparams(node->display_name, "flogi send resp", 0, NULL, flogi->common_service_parameters);
1411*ef270ab1SKenneth D. Merry 
1412*ef270ab1SKenneth D. Merry 	ocs_memset(flogi->class1_service_parameters, 0, sizeof(flogi->class1_service_parameters));
1413*ef270ab1SKenneth D. Merry 	ocs_memset(flogi->class2_service_parameters, 0, sizeof(flogi->class1_service_parameters));
1414*ef270ab1SKenneth D. Merry 	ocs_memset(flogi->class3_service_parameters, 0, sizeof(flogi->class1_service_parameters));
1415*ef270ab1SKenneth D. Merry 	ocs_memset(flogi->class4_service_parameters, 0, sizeof(flogi->class1_service_parameters));
1416*ef270ab1SKenneth D. Merry 
1417*ef270ab1SKenneth D. Merry 	io->hio_type = OCS_HW_ELS_RSP_SID;
1418*ef270ab1SKenneth D. Merry 	if ((rc = ocs_els_send_rsp(io, sizeof(*flogi)))) {
1419*ef270ab1SKenneth D. Merry 		ocs_els_io_free(io);
1420*ef270ab1SKenneth D. Merry 		io = NULL;
1421*ef270ab1SKenneth D. Merry 	}
1422*ef270ab1SKenneth D. Merry 
1423*ef270ab1SKenneth D. Merry 	return io;
1424*ef270ab1SKenneth D. Merry }
1425*ef270ab1SKenneth D. Merry 
1426*ef270ab1SKenneth D. Merry /**
1427*ef270ab1SKenneth D. Merry  * @ingroup els_api
1428*ef270ab1SKenneth D. Merry  * @brief Send a PRLI accept response
1429*ef270ab1SKenneth D. Merry  *
1430*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1431*ef270ab1SKenneth D. Merry  * Construct a PRLI LS_ACC response, and send to the \c node, using the originator
1432*ef270ab1SKenneth D. Merry  * \c ox_id exchange ID.
1433*ef270ab1SKenneth D. Merry  *
1434*ef270ab1SKenneth D. Merry  * @param io Pointer to a SCSI IO object.
1435*ef270ab1SKenneth D. Merry  * @param ox_id Originator exchange ID.
1436*ef270ab1SKenneth D. Merry  * @param cb Callback function.
1437*ef270ab1SKenneth D. Merry  * @param cbarg Callback function argument.
1438*ef270ab1SKenneth D. Merry  *
1439*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
1440*ef270ab1SKenneth D. Merry  */
1441*ef270ab1SKenneth D. Merry 
1442*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_send_prli_acc(ocs_io_t * io,uint32_t ox_id,uint8_t fc_type,els_cb_t cb,void * cbarg)1443*ef270ab1SKenneth D. Merry ocs_send_prli_acc(ocs_io_t *io, uint32_t ox_id, uint8_t fc_type, els_cb_t cb, void *cbarg)
1444*ef270ab1SKenneth D. Merry {
1445*ef270ab1SKenneth D. Merry 	ocs_node_t *node = io->node;
1446*ef270ab1SKenneth D. Merry 	int32_t rc;
1447*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
1448*ef270ab1SKenneth D. Merry 	fc_prli_payload_t *prli;
1449*ef270ab1SKenneth D. Merry 
1450*ef270ab1SKenneth D. Merry 	node_els_trace();
1451*ef270ab1SKenneth D. Merry 
1452*ef270ab1SKenneth D. Merry 	io->els_callback = cb;
1453*ef270ab1SKenneth D. Merry 	io->els_callback_arg = cbarg;
1454*ef270ab1SKenneth D. Merry 	io->display_name = "prli_acc";
1455*ef270ab1SKenneth D. Merry 	io->init_task_tag = ox_id;
1456*ef270ab1SKenneth D. Merry 
1457*ef270ab1SKenneth D. Merry 	ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1458*ef270ab1SKenneth D. Merry 	io->iparam.els.ox_id = ox_id;
1459*ef270ab1SKenneth D. Merry 
1460*ef270ab1SKenneth D. Merry 	prli = io->els_req.virt;
1461*ef270ab1SKenneth D. Merry 	ocs_memset(prli, 0, sizeof(*prli));
1462*ef270ab1SKenneth D. Merry 
1463*ef270ab1SKenneth D. Merry 	prli->command_code = FC_ELS_CMD_ACC;
1464*ef270ab1SKenneth D. Merry 	prli->page_length = 16;
1465*ef270ab1SKenneth D. Merry 	prli->payload_length = ocs_htobe16(sizeof(fc_prli_payload_t));
1466*ef270ab1SKenneth D. Merry 	prli->type = fc_type;
1467*ef270ab1SKenneth D. Merry 	prli->type_ext = 0;
1468*ef270ab1SKenneth D. Merry 	prli->flags = ocs_htobe16(FC_PRLI_ESTABLISH_IMAGE_PAIR | FC_PRLI_REQUEST_EXECUTED);
1469*ef270ab1SKenneth D. Merry 
1470*ef270ab1SKenneth D. Merry 	prli->service_params = ocs_htobe16(FC_PRLI_READ_XRDY_DISABLED |
1471*ef270ab1SKenneth D. Merry 				(node->sport->enable_ini ? FC_PRLI_INITIATOR_FUNCTION : 0) |
1472*ef270ab1SKenneth D. Merry 				(node->sport->enable_tgt ? FC_PRLI_TARGET_FUNCTION : 0));
1473*ef270ab1SKenneth D. Merry 
1474*ef270ab1SKenneth D. Merry 	io->hio_type = OCS_HW_ELS_RSP;
1475*ef270ab1SKenneth D. Merry 	if ((rc = ocs_els_send_rsp(io, sizeof(*prli)))) {
1476*ef270ab1SKenneth D. Merry 		ocs_els_io_free(io);
1477*ef270ab1SKenneth D. Merry 		io = NULL;
1478*ef270ab1SKenneth D. Merry 	}
1479*ef270ab1SKenneth D. Merry 
1480*ef270ab1SKenneth D. Merry 	return io;
1481*ef270ab1SKenneth D. Merry }
1482*ef270ab1SKenneth D. Merry 
1483*ef270ab1SKenneth D. Merry /**
1484*ef270ab1SKenneth D. Merry  * @ingroup els_api
1485*ef270ab1SKenneth D. Merry  * @brief Send a PRLO accept response.
1486*ef270ab1SKenneth D. Merry  *
1487*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1488*ef270ab1SKenneth D. Merry  * Construct a PRLO LS_ACC response, and send to the \c node, using the originator
1489*ef270ab1SKenneth D. Merry  * exchange ID \c ox_id.
1490*ef270ab1SKenneth D. Merry  *
1491*ef270ab1SKenneth D. Merry  * @param io Pointer to a SCSI IO object.
1492*ef270ab1SKenneth D. Merry  * @param ox_id Originator exchange ID.
1493*ef270ab1SKenneth D. Merry  * @param cb Callback function.
1494*ef270ab1SKenneth D. Merry  * @param cbarg Callback function argument.
1495*ef270ab1SKenneth D. Merry  *
1496*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
1497*ef270ab1SKenneth D. Merry  */
1498*ef270ab1SKenneth D. Merry 
1499*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_send_prlo_acc(ocs_io_t * io,uint32_t ox_id,uint8_t fc_type,els_cb_t cb,void * cbarg)1500*ef270ab1SKenneth D. Merry ocs_send_prlo_acc(ocs_io_t *io, uint32_t ox_id, uint8_t fc_type, els_cb_t cb, void *cbarg)
1501*ef270ab1SKenneth D. Merry {
1502*ef270ab1SKenneth D. Merry 	ocs_node_t *node = io->node;
1503*ef270ab1SKenneth D. Merry 	int32_t rc;
1504*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
1505*ef270ab1SKenneth D. Merry 	fc_prlo_acc_payload_t *prlo_acc;
1506*ef270ab1SKenneth D. Merry 
1507*ef270ab1SKenneth D. Merry 	node_els_trace();
1508*ef270ab1SKenneth D. Merry 
1509*ef270ab1SKenneth D. Merry 	io->els_callback = cb;
1510*ef270ab1SKenneth D. Merry 	io->els_callback_arg = cbarg;
1511*ef270ab1SKenneth D. Merry 	io->display_name = "prlo_acc";
1512*ef270ab1SKenneth D. Merry 	io->init_task_tag = ox_id;
1513*ef270ab1SKenneth D. Merry 
1514*ef270ab1SKenneth D. Merry 	ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1515*ef270ab1SKenneth D. Merry 	io->iparam.els.ox_id = ox_id;
1516*ef270ab1SKenneth D. Merry 
1517*ef270ab1SKenneth D. Merry 	prlo_acc = io->els_req.virt;
1518*ef270ab1SKenneth D. Merry 	ocs_memset(prlo_acc, 0, sizeof(*prlo_acc));
1519*ef270ab1SKenneth D. Merry 
1520*ef270ab1SKenneth D. Merry 	prlo_acc->command_code = FC_ELS_CMD_ACC;
1521*ef270ab1SKenneth D. Merry 	prlo_acc->page_length = 16;
1522*ef270ab1SKenneth D. Merry 	prlo_acc->payload_length = ocs_htobe16(sizeof(fc_prlo_acc_payload_t));
1523*ef270ab1SKenneth D. Merry 	prlo_acc->type = fc_type;
1524*ef270ab1SKenneth D. Merry 	prlo_acc->type_ext = 0;
1525*ef270ab1SKenneth D. Merry 	prlo_acc->response_code = FC_PRLO_REQUEST_EXECUTED;
1526*ef270ab1SKenneth D. Merry 
1527*ef270ab1SKenneth D. Merry 	io->hio_type = OCS_HW_ELS_RSP;
1528*ef270ab1SKenneth D. Merry 	if ((rc = ocs_els_send_rsp(io, sizeof(*prlo_acc)))) {
1529*ef270ab1SKenneth D. Merry 		ocs_els_io_free(io);
1530*ef270ab1SKenneth D. Merry 		io = NULL;
1531*ef270ab1SKenneth D. Merry 	}
1532*ef270ab1SKenneth D. Merry 
1533*ef270ab1SKenneth D. Merry 	return io;
1534*ef270ab1SKenneth D. Merry }
1535*ef270ab1SKenneth D. Merry 
1536*ef270ab1SKenneth D. Merry /**
1537*ef270ab1SKenneth D. Merry  * @ingroup els_api
1538*ef270ab1SKenneth D. Merry  * @brief Send a generic LS_ACC response without a payload.
1539*ef270ab1SKenneth D. Merry  *
1540*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1541*ef270ab1SKenneth D. Merry  * A generic LS_ACC response is sent to the \c node using the originator exchange ID
1542*ef270ab1SKenneth D. Merry  * \c ox_id.
1543*ef270ab1SKenneth D. Merry  *
1544*ef270ab1SKenneth D. Merry  * @param io Pointer to a SCSI IO object.
1545*ef270ab1SKenneth D. Merry  * @param ox_id Originator exchange id.
1546*ef270ab1SKenneth D. Merry  * @param cb Callback function.
1547*ef270ab1SKenneth D. Merry  * @param cbarg Callback function argument.
1548*ef270ab1SKenneth D. Merry  *
1549*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
1550*ef270ab1SKenneth D. Merry  */
1551*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_send_ls_acc(ocs_io_t * io,uint32_t ox_id,els_cb_t cb,void * cbarg)1552*ef270ab1SKenneth D. Merry ocs_send_ls_acc(ocs_io_t *io, uint32_t ox_id, els_cb_t cb, void *cbarg)
1553*ef270ab1SKenneth D. Merry {
1554*ef270ab1SKenneth D. Merry 	ocs_node_t *node = io->node;
1555*ef270ab1SKenneth D. Merry 	int32_t rc;
1556*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
1557*ef270ab1SKenneth D. Merry 	fc_acc_payload_t *acc;
1558*ef270ab1SKenneth D. Merry 
1559*ef270ab1SKenneth D. Merry 	node_els_trace();
1560*ef270ab1SKenneth D. Merry 
1561*ef270ab1SKenneth D. Merry 	io->els_callback = cb;
1562*ef270ab1SKenneth D. Merry 	io->els_callback_arg = cbarg;
1563*ef270ab1SKenneth D. Merry 	io->display_name = "ls_acc";
1564*ef270ab1SKenneth D. Merry 	io->init_task_tag = ox_id;
1565*ef270ab1SKenneth D. Merry 
1566*ef270ab1SKenneth D. Merry 	ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1567*ef270ab1SKenneth D. Merry 	io->iparam.els.ox_id = ox_id;
1568*ef270ab1SKenneth D. Merry 
1569*ef270ab1SKenneth D. Merry 	acc = io->els_req.virt;
1570*ef270ab1SKenneth D. Merry 	ocs_memset(acc, 0, sizeof(*acc));
1571*ef270ab1SKenneth D. Merry 
1572*ef270ab1SKenneth D. Merry 	acc->command_code = FC_ELS_CMD_ACC;
1573*ef270ab1SKenneth D. Merry 
1574*ef270ab1SKenneth D. Merry 	io->hio_type = OCS_HW_ELS_RSP;
1575*ef270ab1SKenneth D. Merry 	if ((rc = ocs_els_send_rsp(io, sizeof(*acc)))) {
1576*ef270ab1SKenneth D. Merry 		ocs_els_io_free(io);
1577*ef270ab1SKenneth D. Merry 		io = NULL;
1578*ef270ab1SKenneth D. Merry 	}
1579*ef270ab1SKenneth D. Merry 
1580*ef270ab1SKenneth D. Merry 	return io;
1581*ef270ab1SKenneth D. Merry }
1582*ef270ab1SKenneth D. Merry 
1583*ef270ab1SKenneth D. Merry /**
1584*ef270ab1SKenneth D. Merry  * @ingroup els_api
1585*ef270ab1SKenneth D. Merry  * @brief Send a LOGO accept response.
1586*ef270ab1SKenneth D. Merry  *
1587*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1588*ef270ab1SKenneth D. Merry  * Construct a LOGO LS_ACC response, and send to the \c node, using the originator
1589*ef270ab1SKenneth D. Merry  * exchange ID \c ox_id.
1590*ef270ab1SKenneth D. Merry  *
1591*ef270ab1SKenneth D. Merry  * @param io Pointer to a SCSI IO object.
1592*ef270ab1SKenneth D. Merry  * @param ox_id Originator exchange ID.
1593*ef270ab1SKenneth D. Merry  * @param cb Callback function.
1594*ef270ab1SKenneth D. Merry  * @param cbarg Callback function argument.
1595*ef270ab1SKenneth D. Merry  *
1596*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
1597*ef270ab1SKenneth D. Merry  */
1598*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_send_logo_acc(ocs_io_t * io,uint32_t ox_id,els_cb_t cb,void * cbarg)1599*ef270ab1SKenneth D. Merry ocs_send_logo_acc(ocs_io_t *io, uint32_t ox_id, els_cb_t cb, void *cbarg)
1600*ef270ab1SKenneth D. Merry {
1601*ef270ab1SKenneth D. Merry 	ocs_node_t *node = io->node;
1602*ef270ab1SKenneth D. Merry 	int32_t rc;
1603*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
1604*ef270ab1SKenneth D. Merry 	fc_acc_payload_t *logo;
1605*ef270ab1SKenneth D. Merry 
1606*ef270ab1SKenneth D. Merry 	node_els_trace();
1607*ef270ab1SKenneth D. Merry 
1608*ef270ab1SKenneth D. Merry 	io->els_callback = cb;
1609*ef270ab1SKenneth D. Merry 	io->els_callback_arg = cbarg;
1610*ef270ab1SKenneth D. Merry 	io->display_name = "logo_acc";
1611*ef270ab1SKenneth D. Merry 	io->init_task_tag = ox_id;
1612*ef270ab1SKenneth D. Merry 
1613*ef270ab1SKenneth D. Merry 	ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1614*ef270ab1SKenneth D. Merry 	io->iparam.els.ox_id = ox_id;
1615*ef270ab1SKenneth D. Merry 
1616*ef270ab1SKenneth D. Merry 	logo = io->els_req.virt;
1617*ef270ab1SKenneth D. Merry 	ocs_memset(logo, 0, sizeof(*logo));
1618*ef270ab1SKenneth D. Merry 
1619*ef270ab1SKenneth D. Merry 	logo->command_code = FC_ELS_CMD_ACC;
1620*ef270ab1SKenneth D. Merry 	logo->resv1 = 0;
1621*ef270ab1SKenneth D. Merry 
1622*ef270ab1SKenneth D. Merry 	io->hio_type = OCS_HW_ELS_RSP;
1623*ef270ab1SKenneth D. Merry 	if ((rc = ocs_els_send_rsp(io, sizeof(*logo)))) {
1624*ef270ab1SKenneth D. Merry 		ocs_els_io_free(io);
1625*ef270ab1SKenneth D. Merry 		io = NULL;
1626*ef270ab1SKenneth D. Merry 	}
1627*ef270ab1SKenneth D. Merry 
1628*ef270ab1SKenneth D. Merry 	return io;
1629*ef270ab1SKenneth D. Merry }
1630*ef270ab1SKenneth D. Merry 
1631*ef270ab1SKenneth D. Merry /**
1632*ef270ab1SKenneth D. Merry  * @ingroup els_api
1633*ef270ab1SKenneth D. Merry  * @brief Send an ADISC accept response.
1634*ef270ab1SKenneth D. Merry  *
1635*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1636*ef270ab1SKenneth D. Merry  * Construct an ADISC LS__ACC, and send to the \c node, using the originator
1637*ef270ab1SKenneth D. Merry  * exchange id \c ox_id.
1638*ef270ab1SKenneth D. Merry  *
1639*ef270ab1SKenneth D. Merry  * @param io Pointer to a SCSI IO object.
1640*ef270ab1SKenneth D. Merry  * @param ox_id Originator exchange ID.
1641*ef270ab1SKenneth D. Merry  * @param cb Callback function.
1642*ef270ab1SKenneth D. Merry  * @param cbarg Callback function argument.
1643*ef270ab1SKenneth D. Merry  *
1644*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
1645*ef270ab1SKenneth D. Merry  */
1646*ef270ab1SKenneth D. Merry 
1647*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_send_adisc_acc(ocs_io_t * io,uint32_t ox_id,els_cb_t cb,void * cbarg)1648*ef270ab1SKenneth D. Merry ocs_send_adisc_acc(ocs_io_t *io, uint32_t ox_id, els_cb_t cb, void *cbarg)
1649*ef270ab1SKenneth D. Merry {
1650*ef270ab1SKenneth D. Merry 	ocs_node_t *node = io->node;
1651*ef270ab1SKenneth D. Merry 	int32_t rc;
1652*ef270ab1SKenneth D. Merry 	fc_adisc_payload_t *adisc;
1653*ef270ab1SKenneth D. Merry 	fc_plogi_payload_t *sparams;
1654*ef270ab1SKenneth D. Merry 	ocs_t *ocs;
1655*ef270ab1SKenneth D. Merry 
1656*ef270ab1SKenneth D. Merry 	ocs_assert(node, NULL);
1657*ef270ab1SKenneth D. Merry 	ocs_assert(node->ocs, NULL);
1658*ef270ab1SKenneth D. Merry 	ocs = node->ocs;
1659*ef270ab1SKenneth D. Merry 
1660*ef270ab1SKenneth D. Merry 	node_els_trace();
1661*ef270ab1SKenneth D. Merry 
1662*ef270ab1SKenneth D. Merry 	io->els_callback = cb;
1663*ef270ab1SKenneth D. Merry 	io->els_callback_arg = cbarg;
1664*ef270ab1SKenneth D. Merry 	io->display_name = "adisc_acc";
1665*ef270ab1SKenneth D. Merry 	io->init_task_tag = ox_id;
1666*ef270ab1SKenneth D. Merry 
1667*ef270ab1SKenneth D. Merry 	/* Go ahead and send the ELS_ACC */
1668*ef270ab1SKenneth D. Merry 	ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1669*ef270ab1SKenneth D. Merry 	io->iparam.els.ox_id = ox_id;
1670*ef270ab1SKenneth D. Merry 
1671*ef270ab1SKenneth D. Merry 	sparams = (fc_plogi_payload_t*) node->sport->service_params;
1672*ef270ab1SKenneth D. Merry 	adisc = io->els_req.virt;
1673*ef270ab1SKenneth D. Merry 	ocs_memset(adisc, 0, sizeof(fc_adisc_payload_t));
1674*ef270ab1SKenneth D. Merry 	adisc->command_code = FC_ELS_CMD_ACC;
1675*ef270ab1SKenneth D. Merry 	adisc->hard_address = 0;
1676*ef270ab1SKenneth D. Merry 	adisc->port_name_hi = sparams->port_name_hi;
1677*ef270ab1SKenneth D. Merry 	adisc->port_name_lo = sparams->port_name_lo;
1678*ef270ab1SKenneth D. Merry 	adisc->node_name_hi = sparams->node_name_hi;
1679*ef270ab1SKenneth D. Merry 	adisc->node_name_lo = sparams->node_name_lo;
1680*ef270ab1SKenneth D. Merry 	adisc->port_id = fc_htobe24(node->rnode.sport->fc_id);
1681*ef270ab1SKenneth D. Merry 
1682*ef270ab1SKenneth D. Merry 	io->hio_type = OCS_HW_ELS_RSP;
1683*ef270ab1SKenneth D. Merry 	if ((rc = ocs_els_send_rsp(io, sizeof(*adisc)))) {
1684*ef270ab1SKenneth D. Merry 		ocs_els_io_free(io);
1685*ef270ab1SKenneth D. Merry 		io = NULL;
1686*ef270ab1SKenneth D. Merry 	}
1687*ef270ab1SKenneth D. Merry 
1688*ef270ab1SKenneth D. Merry 	return io;
1689*ef270ab1SKenneth D. Merry }
1690*ef270ab1SKenneth D. Merry 
1691*ef270ab1SKenneth D. Merry /**
1692*ef270ab1SKenneth D. Merry  * @ingroup els_api
1693*ef270ab1SKenneth D. Merry  * @brief Send a RFTID CT request.
1694*ef270ab1SKenneth D. Merry  *
1695*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1696*ef270ab1SKenneth D. Merry  * Construct an RFTID CT request, and send to the \c node.
1697*ef270ab1SKenneth D. Merry  *
1698*ef270ab1SKenneth D. Merry  * @param node Node to which the RFTID request is sent.
1699*ef270ab1SKenneth D. Merry  * @param timeout_sec Time, in seconds, to wait before timing out the ELS.
1700*ef270ab1SKenneth D. Merry  * @param retries Number of times to retry errors before reporting a failure.
1701*ef270ab1SKenneth D. Merry  * @param cb Callback function.
1702*ef270ab1SKenneth D. Merry  * @param cbarg Callback function argument.
1703*ef270ab1SKenneth D. Merry  *
1704*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
1705*ef270ab1SKenneth D. Merry  */
1706*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_ns_send_rftid(ocs_node_t * node,uint32_t timeout_sec,uint32_t retries,els_cb_t cb,void * cbarg)1707*ef270ab1SKenneth D. Merry ocs_ns_send_rftid(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
1708*ef270ab1SKenneth D. Merry 	els_cb_t cb, void *cbarg)
1709*ef270ab1SKenneth D. Merry {
1710*ef270ab1SKenneth D. Merry 	ocs_io_t *els;
1711*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
1712*ef270ab1SKenneth D. Merry 	fcct_rftid_req_t *rftid;
1713*ef270ab1SKenneth D. Merry 
1714*ef270ab1SKenneth D. Merry 	node_els_trace();
1715*ef270ab1SKenneth D. Merry 
1716*ef270ab1SKenneth D. Merry 	els = ocs_els_io_alloc(node, sizeof(*rftid), OCS_ELS_ROLE_ORIGINATOR);
1717*ef270ab1SKenneth D. Merry 	if (els == NULL) {
1718*ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "IO alloc failed\n");
1719*ef270ab1SKenneth D. Merry 	} else {
1720*ef270ab1SKenneth D. Merry 		els->iparam.fc_ct.r_ctl = FC_RCTL_ELS;
1721*ef270ab1SKenneth D. Merry 		els->iparam.fc_ct.type = FC_TYPE_GS;
1722*ef270ab1SKenneth D. Merry 		els->iparam.fc_ct.df_ctl = 0;
1723*ef270ab1SKenneth D. Merry 		els->iparam.fc_ct.timeout = timeout_sec;
1724*ef270ab1SKenneth D. Merry 
1725*ef270ab1SKenneth D. Merry 		els->els_callback = cb;
1726*ef270ab1SKenneth D. Merry 		els->els_callback_arg = cbarg;
1727*ef270ab1SKenneth D. Merry 		els->display_name = "rftid";
1728*ef270ab1SKenneth D. Merry 
1729*ef270ab1SKenneth D. Merry 		rftid = els->els_req.virt;
1730*ef270ab1SKenneth D. Merry 
1731*ef270ab1SKenneth D. Merry 		ocs_memset(rftid, 0, sizeof(*rftid));
1732*ef270ab1SKenneth D. Merry 		fcct_build_req_header(&rftid->hdr, FC_GS_NAMESERVER_RFT_ID, (OCS_ELS_RSP_LEN - sizeof(rftid->hdr)));
1733*ef270ab1SKenneth D. Merry 		rftid->port_id = ocs_htobe32(node->rnode.sport->fc_id);
1734*ef270ab1SKenneth D. Merry 		rftid->fc4_types[FC_GS_TYPE_WORD(FC_TYPE_FCP)] = ocs_htobe32(1 << FC_GS_TYPE_BIT(FC_TYPE_FCP));
1735*ef270ab1SKenneth D. Merry 
1736*ef270ab1SKenneth D. Merry 		els->hio_type = OCS_HW_FC_CT;
1737*ef270ab1SKenneth D. Merry 
1738*ef270ab1SKenneth D. Merry 		ocs_io_transition(els, __ocs_els_init, NULL);
1739*ef270ab1SKenneth D. Merry 	}
1740*ef270ab1SKenneth D. Merry 	return els;
1741*ef270ab1SKenneth D. Merry }
1742*ef270ab1SKenneth D. Merry 
1743*ef270ab1SKenneth D. Merry /**
1744*ef270ab1SKenneth D. Merry  * @ingroup els_api
1745*ef270ab1SKenneth D. Merry  * @brief Send a RFFID CT request.
1746*ef270ab1SKenneth D. Merry  *
1747*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1748*ef270ab1SKenneth D. Merry  * Construct an RFFID CT request, and send to the \c node.
1749*ef270ab1SKenneth D. Merry  *
1750*ef270ab1SKenneth D. Merry  * @param node Node to which the RFFID request is sent.
1751*ef270ab1SKenneth D. Merry  * @param timeout_sec Time, in seconds, to wait before timing out the ELS.
1752*ef270ab1SKenneth D. Merry  * @param retries Number of times to retry errors before reporting a failure.
1753*ef270ab1SKenneth D. Merry  * @param cb Callback function
1754*ef270ab1SKenneth D. Merry  * @param cbarg Callback function argument.
1755*ef270ab1SKenneth D. Merry  *
1756*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
1757*ef270ab1SKenneth D. Merry  */
1758*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_ns_send_rffid(ocs_node_t * node,uint32_t timeout_sec,uint32_t retries,els_cb_t cb,void * cbarg)1759*ef270ab1SKenneth D. Merry ocs_ns_send_rffid(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
1760*ef270ab1SKenneth D. Merry 	els_cb_t cb, void *cbarg)
1761*ef270ab1SKenneth D. Merry {
1762*ef270ab1SKenneth D. Merry 	ocs_io_t *els;
1763*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
1764*ef270ab1SKenneth D. Merry 	fcct_rffid_req_t *rffid;
1765*ef270ab1SKenneth D. Merry 
1766*ef270ab1SKenneth D. Merry 	node_els_trace();
1767*ef270ab1SKenneth D. Merry 
1768*ef270ab1SKenneth D. Merry 	els = ocs_els_io_alloc(node, sizeof(*rffid), OCS_ELS_ROLE_ORIGINATOR);
1769*ef270ab1SKenneth D. Merry 	if (els == NULL) {
1770*ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "IO alloc failed\n");
1771*ef270ab1SKenneth D. Merry 	} else {
1772*ef270ab1SKenneth D. Merry 		els->iparam.fc_ct.r_ctl = FC_RCTL_ELS;
1773*ef270ab1SKenneth D. Merry 		els->iparam.fc_ct.type = FC_TYPE_GS;
1774*ef270ab1SKenneth D. Merry 		els->iparam.fc_ct.df_ctl = 0;
1775*ef270ab1SKenneth D. Merry 		els->iparam.fc_ct.timeout = timeout_sec;
1776*ef270ab1SKenneth D. Merry 
1777*ef270ab1SKenneth D. Merry 		els->els_callback = cb;
1778*ef270ab1SKenneth D. Merry 		els->els_callback_arg = cbarg;
1779*ef270ab1SKenneth D. Merry 		els->display_name = "rffid";
1780*ef270ab1SKenneth D. Merry 
1781*ef270ab1SKenneth D. Merry 		rffid = els->els_req.virt;
1782*ef270ab1SKenneth D. Merry 
1783*ef270ab1SKenneth D. Merry 		ocs_memset(rffid, 0, sizeof(*rffid));
1784*ef270ab1SKenneth D. Merry 
1785*ef270ab1SKenneth D. Merry 		fcct_build_req_header(&rffid->hdr, FC_GS_NAMESERVER_RFF_ID, (OCS_ELS_RSP_LEN - sizeof(rffid->hdr)));
1786*ef270ab1SKenneth D. Merry 		rffid->port_id = ocs_htobe32(node->rnode.sport->fc_id);
1787*ef270ab1SKenneth D. Merry 		if (node->sport->enable_ini) {
1788*ef270ab1SKenneth D. Merry 			rffid->fc4_feature_bits |= FC4_FEATURE_INITIATOR;
1789*ef270ab1SKenneth D. Merry 		}
1790*ef270ab1SKenneth D. Merry 		if (node->sport->enable_tgt) {
1791*ef270ab1SKenneth D. Merry 			rffid->fc4_feature_bits |= FC4_FEATURE_TARGET;
1792*ef270ab1SKenneth D. Merry 		}
1793*ef270ab1SKenneth D. Merry 		rffid->type = FC_TYPE_FCP;
1794*ef270ab1SKenneth D. Merry 
1795*ef270ab1SKenneth D. Merry 		els->hio_type = OCS_HW_FC_CT;
1796*ef270ab1SKenneth D. Merry 
1797*ef270ab1SKenneth D. Merry 		ocs_io_transition(els, __ocs_els_init, NULL);
1798*ef270ab1SKenneth D. Merry 	}
1799*ef270ab1SKenneth D. Merry 	return els;
1800*ef270ab1SKenneth D. Merry }
1801*ef270ab1SKenneth D. Merry 
1802*ef270ab1SKenneth D. Merry /**
1803*ef270ab1SKenneth D. Merry  * @ingroup els_api
1804*ef270ab1SKenneth D. Merry  * @brief Send a GIDPT CT request.
1805*ef270ab1SKenneth D. Merry  *
1806*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1807*ef270ab1SKenneth D. Merry  * Construct a GIDPT CT request, and send to the \c node.
1808*ef270ab1SKenneth D. Merry  *
1809*ef270ab1SKenneth D. Merry  * @param node Node to which the GIDPT request is sent.
1810*ef270ab1SKenneth D. Merry  * @param timeout_sec Time, in seconds, to wait before timing out the ELS.
1811*ef270ab1SKenneth D. Merry  * @param retries Number of times to retry errors before reporting a failure.
1812*ef270ab1SKenneth D. Merry  * @param cb Callback function.
1813*ef270ab1SKenneth D. Merry  * @param cbarg Callback function argument.
1814*ef270ab1SKenneth D. Merry  *
1815*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
1816*ef270ab1SKenneth D. Merry  */
1817*ef270ab1SKenneth D. Merry 
1818*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_ns_send_gidpt(ocs_node_t * node,uint32_t timeout_sec,uint32_t retries,els_cb_t cb,void * cbarg)1819*ef270ab1SKenneth D. Merry ocs_ns_send_gidpt(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
1820*ef270ab1SKenneth D. Merry 	els_cb_t cb, void *cbarg)
1821*ef270ab1SKenneth D. Merry {
1822*ef270ab1SKenneth D. Merry 	ocs_io_t *els;
1823*ef270ab1SKenneth D. Merry 	ocs_t *ocs = node->ocs;
1824*ef270ab1SKenneth D. Merry 	fcct_gidpt_req_t *gidpt;
1825*ef270ab1SKenneth D. Merry 
1826*ef270ab1SKenneth D. Merry 	node_els_trace();
1827*ef270ab1SKenneth D. Merry 
1828*ef270ab1SKenneth D. Merry 	els = ocs_els_io_alloc_size(node, sizeof(*gidpt), OCS_ELS_GID_PT_RSP_LEN, OCS_ELS_ROLE_ORIGINATOR);
1829*ef270ab1SKenneth D. Merry 	if (els == NULL) {
1830*ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "IO alloc failed\n");
1831*ef270ab1SKenneth D. Merry 	} else {
1832*ef270ab1SKenneth D. Merry 		els->iparam.fc_ct.r_ctl = FC_RCTL_ELS;
1833*ef270ab1SKenneth D. Merry 		els->iparam.fc_ct.type = FC_TYPE_GS;
1834*ef270ab1SKenneth D. Merry 		els->iparam.fc_ct.df_ctl = 0;
1835*ef270ab1SKenneth D. Merry 		els->iparam.fc_ct.timeout = timeout_sec;
1836*ef270ab1SKenneth D. Merry 
1837*ef270ab1SKenneth D. Merry 		els->els_callback = cb;
1838*ef270ab1SKenneth D. Merry 		els->els_callback_arg = cbarg;
1839*ef270ab1SKenneth D. Merry 		els->display_name = "gidpt";
1840*ef270ab1SKenneth D. Merry 
1841*ef270ab1SKenneth D. Merry 		gidpt = els->els_req.virt;
1842*ef270ab1SKenneth D. Merry 
1843*ef270ab1SKenneth D. Merry 		ocs_memset(gidpt, 0, sizeof(*gidpt));
1844*ef270ab1SKenneth D. Merry 		fcct_build_req_header(&gidpt->hdr, FC_GS_NAMESERVER_GID_PT, (OCS_ELS_GID_PT_RSP_LEN - sizeof(gidpt->hdr)) );
1845*ef270ab1SKenneth D. Merry 		gidpt->domain_id_scope = 0;
1846*ef270ab1SKenneth D. Merry 		gidpt->area_id_scope = 0;
1847*ef270ab1SKenneth D. Merry 		gidpt->port_type = 0x7f;
1848*ef270ab1SKenneth D. Merry 
1849*ef270ab1SKenneth D. Merry 		els->hio_type = OCS_HW_FC_CT;
1850*ef270ab1SKenneth D. Merry 
1851*ef270ab1SKenneth D. Merry 		ocs_io_transition(els, __ocs_els_init, NULL);
1852*ef270ab1SKenneth D. Merry 	}
1853*ef270ab1SKenneth D. Merry 	return els;
1854*ef270ab1SKenneth D. Merry }
1855*ef270ab1SKenneth D. Merry 
1856*ef270ab1SKenneth D. Merry /**
1857*ef270ab1SKenneth D. Merry  * @ingroup els_api
1858*ef270ab1SKenneth D. Merry  * @brief Send a BA_ACC given the request's FC header
1859*ef270ab1SKenneth D. Merry  *
1860*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1861*ef270ab1SKenneth D. Merry  * Using the S_ID/D_ID from the request's FC header, generate a BA_ACC.
1862*ef270ab1SKenneth D. Merry  *
1863*ef270ab1SKenneth D. Merry  * @param io Pointer to a SCSI IO object.
1864*ef270ab1SKenneth D. Merry  * @param hdr Pointer to the FC header.
1865*ef270ab1SKenneth D. Merry  *
1866*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
1867*ef270ab1SKenneth D. Merry  */
1868*ef270ab1SKenneth D. Merry 
1869*ef270ab1SKenneth D. Merry ocs_io_t *
ocs_bls_send_acc_hdr(ocs_io_t * io,fc_header_t * hdr)1870*ef270ab1SKenneth D. Merry ocs_bls_send_acc_hdr(ocs_io_t *io, fc_header_t *hdr)
1871*ef270ab1SKenneth D. Merry {
1872*ef270ab1SKenneth D. Merry 	uint16_t ox_id = ocs_be16toh(hdr->ox_id);
1873*ef270ab1SKenneth D. Merry 	uint16_t rx_id = ocs_be16toh(hdr->rx_id);
1874*ef270ab1SKenneth D. Merry 	uint32_t d_id = fc_be24toh(hdr->d_id);
1875*ef270ab1SKenneth D. Merry 
1876*ef270ab1SKenneth D. Merry 	return ocs_bls_send_acc(io, d_id, ox_id, rx_id);
1877*ef270ab1SKenneth D. Merry }
1878*ef270ab1SKenneth D. Merry 
1879*ef270ab1SKenneth D. Merry /**
1880*ef270ab1SKenneth D. Merry  * @ingroup els_api
1881*ef270ab1SKenneth D. Merry  * @brief Send a BLS BA_ACC response.
1882*ef270ab1SKenneth D. Merry  *
1883*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1884*ef270ab1SKenneth D. Merry  * Construct a BLS BA_ACC response, and send to the \c node.
1885*ef270ab1SKenneth D. Merry  *
1886*ef270ab1SKenneth D. Merry  * @param io Pointer to a SCSI IO object.
1887*ef270ab1SKenneth D. Merry  * @param s_id S_ID to use for the response. If UINT32_MAX, then use our SLI port
1888*ef270ab1SKenneth D. Merry  * (sport) S_ID.
1889*ef270ab1SKenneth D. Merry  * @param ox_id Originator exchange ID.
1890*ef270ab1SKenneth D. Merry  * @param rx_id Responder exchange ID.
1891*ef270ab1SKenneth D. Merry  *
1892*ef270ab1SKenneth D. Merry  * @return Returns pointer to IO object, or NULL if error.
1893*ef270ab1SKenneth D. Merry  */
1894*ef270ab1SKenneth D. Merry 
1895*ef270ab1SKenneth D. Merry static ocs_io_t *
ocs_bls_send_acc(ocs_io_t * io,uint32_t s_id,uint16_t ox_id,uint16_t rx_id)1896*ef270ab1SKenneth D. Merry ocs_bls_send_acc(ocs_io_t *io, uint32_t s_id, uint16_t ox_id, uint16_t rx_id)
1897*ef270ab1SKenneth D. Merry {
1898*ef270ab1SKenneth D. Merry 	ocs_node_t *node = io->node;
1899*ef270ab1SKenneth D. Merry 	int32_t rc;
1900*ef270ab1SKenneth D. Merry 	fc_ba_acc_payload_t *acc;
1901*ef270ab1SKenneth D. Merry 	ocs_t *ocs;
1902*ef270ab1SKenneth D. Merry 
1903*ef270ab1SKenneth D. Merry 	ocs_assert(node, NULL);
1904*ef270ab1SKenneth D. Merry 	ocs_assert(node->ocs, NULL);
1905*ef270ab1SKenneth D. Merry 	ocs = node->ocs;
1906*ef270ab1SKenneth D. Merry 
1907*ef270ab1SKenneth D. Merry 	if (node->rnode.sport->fc_id == s_id) {
1908*ef270ab1SKenneth D. Merry 		s_id = UINT32_MAX;
1909*ef270ab1SKenneth D. Merry 	}
1910*ef270ab1SKenneth D. Merry 
1911*ef270ab1SKenneth D. Merry 	/* fill out generic fields */
1912*ef270ab1SKenneth D. Merry 	io->ocs = ocs;
1913*ef270ab1SKenneth D. Merry 	io->node = node;
1914*ef270ab1SKenneth D. Merry 	io->cmd_tgt = TRUE;
1915*ef270ab1SKenneth D. Merry 
1916*ef270ab1SKenneth D. Merry 	/* fill out BLS Response-specific fields */
1917*ef270ab1SKenneth D. Merry 	io->io_type = OCS_IO_TYPE_BLS_RESP;
1918*ef270ab1SKenneth D. Merry 	io->display_name = "ba_acc";
1919*ef270ab1SKenneth D. Merry 	io->hio_type = OCS_HW_BLS_ACC_SID;
1920*ef270ab1SKenneth D. Merry 	io->init_task_tag = ox_id;
1921*ef270ab1SKenneth D. Merry 
1922*ef270ab1SKenneth D. Merry 	/* fill out iparam fields */
1923*ef270ab1SKenneth D. Merry 	ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1924*ef270ab1SKenneth D. Merry 	io->iparam.bls_sid.s_id = s_id;
1925*ef270ab1SKenneth D. Merry 	io->iparam.bls_sid.ox_id = ox_id;
1926*ef270ab1SKenneth D. Merry 	io->iparam.bls_sid.rx_id = rx_id;
1927*ef270ab1SKenneth D. Merry 
1928*ef270ab1SKenneth D. Merry 	acc = (void *)io->iparam.bls_sid.payload;
1929*ef270ab1SKenneth D. Merry 
1930*ef270ab1SKenneth D. Merry 	ocs_memset(io->iparam.bls_sid.payload, 0, sizeof(io->iparam.bls_sid.payload));
1931*ef270ab1SKenneth D. Merry 	acc->ox_id = io->iparam.bls_sid.ox_id;
1932*ef270ab1SKenneth D. Merry 	acc->rx_id = io->iparam.bls_sid.rx_id;
1933*ef270ab1SKenneth D. Merry 	acc->high_seq_cnt = UINT16_MAX;
1934*ef270ab1SKenneth D. Merry 
1935*ef270ab1SKenneth D. Merry 	if ((rc = ocs_scsi_io_dispatch(io, ocs_bls_send_acc_cb))) {
1936*ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "ocs_scsi_io_dispatch() failed: %d\n", rc);
1937*ef270ab1SKenneth D. Merry 		ocs_scsi_io_free(io);
1938*ef270ab1SKenneth D. Merry 		io = NULL;
1939*ef270ab1SKenneth D. Merry 	}
1940*ef270ab1SKenneth D. Merry 	return io;
1941*ef270ab1SKenneth D. Merry }
1942*ef270ab1SKenneth D. Merry 
1943*ef270ab1SKenneth D. Merry /**
1944*ef270ab1SKenneth D. Merry  * @brief Handle the BLS accept completion.
1945*ef270ab1SKenneth D. Merry  *
1946*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1947*ef270ab1SKenneth D. Merry  * Upon completion of sending a BA_ACC, this callback is invoked by the HW.
1948*ef270ab1SKenneth D. Merry  *
1949*ef270ab1SKenneth D. Merry  * @param hio Pointer to the HW IO object.
1950*ef270ab1SKenneth D. Merry  * @param rnode Pointer to the HW remote node.
1951*ef270ab1SKenneth D. Merry  * @param length Length of the response payload, in bytes.
1952*ef270ab1SKenneth D. Merry  * @param status Completion status.
1953*ef270ab1SKenneth D. Merry  * @param ext_status Extended completion status.
1954*ef270ab1SKenneth D. Merry  * @param app Callback private argument.
1955*ef270ab1SKenneth D. Merry  *
1956*ef270ab1SKenneth D. Merry  * @return Returns 0 on success; or a negative error value on failure.
1957*ef270ab1SKenneth D. Merry  */
1958*ef270ab1SKenneth D. Merry 
1959*ef270ab1SKenneth D. Merry static int32_t
ocs_bls_send_acc_cb(ocs_hw_io_t * hio,ocs_remote_node_t * rnode,uint32_t length,int32_t status,uint32_t ext_status,void * app)1960*ef270ab1SKenneth D. Merry ocs_bls_send_acc_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *app)
1961*ef270ab1SKenneth D. Merry {
1962*ef270ab1SKenneth D. Merry 	ocs_io_t *io = app;
1963*ef270ab1SKenneth D. Merry 
1964*ef270ab1SKenneth D. Merry 	ocs_assert(io, -1);
1965*ef270ab1SKenneth D. Merry 
1966*ef270ab1SKenneth D. Merry 	ocs_scsi_io_free(io);
1967*ef270ab1SKenneth D. Merry 	return 0;
1968*ef270ab1SKenneth D. Merry }
1969*ef270ab1SKenneth D. Merry 
1970*ef270ab1SKenneth D. Merry /**
1971*ef270ab1SKenneth D. Merry  * @brief ELS abort callback.
1972*ef270ab1SKenneth D. Merry  *
1973*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
1974*ef270ab1SKenneth D. Merry  * This callback is invoked by the HW when an ELS IO is aborted.
1975*ef270ab1SKenneth D. Merry  *
1976*ef270ab1SKenneth D. Merry  * @param hio Pointer to the HW IO object.
1977*ef270ab1SKenneth D. Merry  * @param rnode Pointer to the HW remote node.
1978*ef270ab1SKenneth D. Merry  * @param length Length of the response payload, in bytes.
1979*ef270ab1SKenneth D. Merry  * @param status Completion status.
1980*ef270ab1SKenneth D. Merry  * @param ext_status Extended completion status.
1981*ef270ab1SKenneth D. Merry  * @param app Callback private argument.
1982*ef270ab1SKenneth D. Merry  *
1983*ef270ab1SKenneth D. Merry  * @return Returns 0 on success; or a negative error value on failure.
1984*ef270ab1SKenneth D. Merry  */
1985*ef270ab1SKenneth D. Merry 
1986*ef270ab1SKenneth D. Merry static int32_t
ocs_els_abort_cb(ocs_hw_io_t * hio,ocs_remote_node_t * rnode,uint32_t length,int32_t status,uint32_t ext_status,void * app)1987*ef270ab1SKenneth D. Merry ocs_els_abort_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *app)
1988*ef270ab1SKenneth D. Merry {
1989*ef270ab1SKenneth D. Merry 	ocs_io_t *els;
1990*ef270ab1SKenneth D. Merry 	ocs_io_t *abort_io = NULL; /* IO structure used to abort ELS */
1991*ef270ab1SKenneth D. Merry 	ocs_t *ocs;
1992*ef270ab1SKenneth D. Merry 
1993*ef270ab1SKenneth D. Merry 	ocs_assert(app, -1);
1994*ef270ab1SKenneth D. Merry 	abort_io = app;
1995*ef270ab1SKenneth D. Merry 	els = abort_io->io_to_abort;
1996*ef270ab1SKenneth D. Merry 	ocs_assert(els->node, -1);
1997*ef270ab1SKenneth D. Merry 	ocs_assert(els->node->ocs, -1);
1998*ef270ab1SKenneth D. Merry 
1999*ef270ab1SKenneth D. Merry 	ocs = els->node->ocs;
2000*ef270ab1SKenneth D. Merry 
2001*ef270ab1SKenneth D. Merry 	if (status != 0) {
2002*ef270ab1SKenneth D. Merry 		ocs_log_warn(ocs, "status x%x ext x%x\n", status, ext_status);
2003*ef270ab1SKenneth D. Merry 	}
2004*ef270ab1SKenneth D. Merry 
2005*ef270ab1SKenneth D. Merry 	/* now free the abort IO */
2006*ef270ab1SKenneth D. Merry 	ocs_io_free(ocs, abort_io);
2007*ef270ab1SKenneth D. Merry 
2008*ef270ab1SKenneth D. Merry 	/* send completion event to indicate abort process is complete
2009*ef270ab1SKenneth D. Merry 	 * Note: The ELS SM will already be receiving ELS_REQ_OK/FAIL/RJT/ABORTED
2010*ef270ab1SKenneth D. Merry 	 */
2011*ef270ab1SKenneth D. Merry 	ocs_els_post_event(els, OCS_EVT_ELS_ABORT_CMPL, NULL);
2012*ef270ab1SKenneth D. Merry 
2013*ef270ab1SKenneth D. Merry 	/* done with ELS IO to abort */
2014*ef270ab1SKenneth D. Merry 	ocs_ref_put(&els->ref); /* ocs_ref_get(): ocs_els_abort_io() */
2015*ef270ab1SKenneth D. Merry 	return 0;
2016*ef270ab1SKenneth D. Merry }
2017*ef270ab1SKenneth D. Merry 
2018*ef270ab1SKenneth D. Merry /**
2019*ef270ab1SKenneth D. Merry  * @brief Abort an ELS IO.
2020*ef270ab1SKenneth D. Merry  *
2021*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
2022*ef270ab1SKenneth D. Merry  * The ELS IO is aborted by making a HW abort IO request,
2023*ef270ab1SKenneth D. Merry  * optionally requesting that an ABTS is sent.
2024*ef270ab1SKenneth D. Merry  *
2025*ef270ab1SKenneth D. Merry  * \b Note: This function allocates a HW IO, and associates the HW IO
2026*ef270ab1SKenneth D. Merry  * with the ELS IO that it is aborting. It does not associate
2027*ef270ab1SKenneth D. Merry  * the HW IO with the node directly, like for ELS requests. The
2028*ef270ab1SKenneth D. Merry  * abort completion is propagated up to the node once the
2029*ef270ab1SKenneth D. Merry  * original WQE and the abort WQE are complete (the original WQE
2030*ef270ab1SKenneth D. Merry  * completion is not propagated up to node).
2031*ef270ab1SKenneth D. Merry  *
2032*ef270ab1SKenneth D. Merry  * @param els Pointer to the ELS IO.
2033*ef270ab1SKenneth D. Merry  * @param send_abts Boolean to indicate if hardware will automatically generate an ABTS.
2034*ef270ab1SKenneth D. Merry  *
2035*ef270ab1SKenneth D. Merry  * @return Returns pointer to Abort IO object, or NULL if error.
2036*ef270ab1SKenneth D. Merry  */
2037*ef270ab1SKenneth D. Merry 
2038*ef270ab1SKenneth D. Merry static ocs_io_t *
ocs_els_abort_io(ocs_io_t * els,int send_abts)2039*ef270ab1SKenneth D. Merry ocs_els_abort_io(ocs_io_t *els, int send_abts)
2040*ef270ab1SKenneth D. Merry {
2041*ef270ab1SKenneth D. Merry 	ocs_t *ocs;
2042*ef270ab1SKenneth D. Merry 	ocs_xport_t *xport;
2043*ef270ab1SKenneth D. Merry 	int32_t rc;
2044*ef270ab1SKenneth D. Merry 	ocs_io_t *abort_io = NULL;
2045*ef270ab1SKenneth D. Merry 
2046*ef270ab1SKenneth D. Merry 	ocs_assert(els, NULL);
2047*ef270ab1SKenneth D. Merry 	ocs_assert(els->node, NULL);
2048*ef270ab1SKenneth D. Merry 	ocs_assert(els->node->ocs, NULL);
2049*ef270ab1SKenneth D. Merry 
2050*ef270ab1SKenneth D. Merry 	ocs = els->node->ocs;
2051*ef270ab1SKenneth D. Merry 	ocs_assert(ocs->xport, NULL);
2052*ef270ab1SKenneth D. Merry 	xport = ocs->xport;
2053*ef270ab1SKenneth D. Merry 
2054*ef270ab1SKenneth D. Merry 	/* take a reference on IO being aborted */
2055*ef270ab1SKenneth D. Merry 	if ((ocs_ref_get_unless_zero(&els->ref) == 0)) {
2056*ef270ab1SKenneth D. Merry 		/* command no longer active */
2057*ef270ab1SKenneth D. Merry 		ocs_log_debug(ocs, "els no longer active\n");
2058*ef270ab1SKenneth D. Merry 		return NULL;
2059*ef270ab1SKenneth D. Merry 	}
2060*ef270ab1SKenneth D. Merry 
2061*ef270ab1SKenneth D. Merry 	/* allocate IO structure to send abort */
2062*ef270ab1SKenneth D. Merry 	abort_io = ocs_io_alloc(ocs);
2063*ef270ab1SKenneth D. Merry 	if (abort_io == NULL) {
2064*ef270ab1SKenneth D. Merry 		ocs_atomic_add_return(&xport->io_alloc_failed_count, 1);
2065*ef270ab1SKenneth D. Merry 	} else {
2066*ef270ab1SKenneth D. Merry 		ocs_assert(abort_io->hio == NULL, NULL);
2067*ef270ab1SKenneth D. Merry 
2068*ef270ab1SKenneth D. Merry 		/* set generic fields */
2069*ef270ab1SKenneth D. Merry 		abort_io->ocs = ocs;
2070*ef270ab1SKenneth D. Merry 		abort_io->node = els->node;
2071*ef270ab1SKenneth D. Merry 		abort_io->cmd_ini = TRUE;
2072*ef270ab1SKenneth D. Merry 
2073*ef270ab1SKenneth D. Merry 		/* set type and ABORT-specific fields */
2074*ef270ab1SKenneth D. Merry 		abort_io->io_type = OCS_IO_TYPE_ABORT;
2075*ef270ab1SKenneth D. Merry 		abort_io->display_name = "abort_els";
2076*ef270ab1SKenneth D. Merry 		abort_io->io_to_abort = els;
2077*ef270ab1SKenneth D. Merry 		abort_io->send_abts = send_abts;
2078*ef270ab1SKenneth D. Merry 
2079*ef270ab1SKenneth D. Merry 		/* now dispatch IO */
2080*ef270ab1SKenneth D. Merry 		if ((rc = ocs_scsi_io_dispatch_abort(abort_io, ocs_els_abort_cb))) {
2081*ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "ocs_scsi_io_dispatch failed: %d\n", rc);
2082*ef270ab1SKenneth D. Merry 			ocs_io_free(ocs, abort_io);
2083*ef270ab1SKenneth D. Merry 			abort_io = NULL;
2084*ef270ab1SKenneth D. Merry 		}
2085*ef270ab1SKenneth D. Merry 	}
2086*ef270ab1SKenneth D. Merry 
2087*ef270ab1SKenneth D. Merry 	/* if something failed, put reference on ELS to abort */
2088*ef270ab1SKenneth D. Merry 	if (abort_io == NULL) {
2089*ef270ab1SKenneth D. Merry 		ocs_ref_put(&els->ref); /* ocs_ref_get(): same function */
2090*ef270ab1SKenneth D. Merry 	}
2091*ef270ab1SKenneth D. Merry 	return abort_io;
2092*ef270ab1SKenneth D. Merry }
2093*ef270ab1SKenneth D. Merry 
2094*ef270ab1SKenneth D. Merry /*
2095*ef270ab1SKenneth D. Merry  * ELS IO State Machine
2096*ef270ab1SKenneth D. Merry  */
2097*ef270ab1SKenneth D. Merry 
2098*ef270ab1SKenneth D. Merry #define std_els_state_decl(...) \
2099*ef270ab1SKenneth D. Merry 	ocs_io_t *els = NULL; \
2100*ef270ab1SKenneth D. Merry 	ocs_node_t *node = NULL; \
2101*ef270ab1SKenneth D. Merry 	ocs_t *ocs = NULL; \
2102*ef270ab1SKenneth D. Merry 	ocs_assert(ctx != NULL, NULL); \
2103*ef270ab1SKenneth D. Merry 	els = ctx->app; \
2104*ef270ab1SKenneth D. Merry 	ocs_assert(els != NULL, NULL); \
2105*ef270ab1SKenneth D. Merry 	node = els->node; \
2106*ef270ab1SKenneth D. Merry 	ocs_assert(node != NULL, NULL); \
2107*ef270ab1SKenneth D. Merry 	ocs = node->ocs; \
2108*ef270ab1SKenneth D. Merry 	ocs_assert(ocs != NULL, NULL);
2109*ef270ab1SKenneth D. Merry 
2110*ef270ab1SKenneth D. Merry #define els_sm_trace(...) \
2111*ef270ab1SKenneth D. Merry 	do { \
2112*ef270ab1SKenneth D. Merry 		if (OCS_LOG_ENABLE_ELS_TRACE(ocs)) \
2113*ef270ab1SKenneth D. Merry 			ocs_log_info(ocs, "[%s] %-8s %-20s %-20s\n", node->display_name, els->display_name, \
2114*ef270ab1SKenneth D. Merry 				__func__, ocs_sm_event_name(evt)); \
2115*ef270ab1SKenneth D. Merry 	} while (0)
2116*ef270ab1SKenneth D. Merry 
2117*ef270ab1SKenneth D. Merry /**
2118*ef270ab1SKenneth D. Merry  * @brief Cleanup an ELS IO
2119*ef270ab1SKenneth D. Merry  *
2120*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
2121*ef270ab1SKenneth D. Merry  * Cleans up an ELS IO by posting the requested event to the owning node object;
2122*ef270ab1SKenneth D. Merry  * invoking the callback, if one is provided; and then freeing the
2123*ef270ab1SKenneth D. Merry  * ELS IO object.
2124*ef270ab1SKenneth D. Merry  *
2125*ef270ab1SKenneth D. Merry  * @param els Pointer to the ELS IO.
2126*ef270ab1SKenneth D. Merry  * @param node_evt Node SM event to post.
2127*ef270ab1SKenneth D. Merry  * @param arg Node SM event argument.
2128*ef270ab1SKenneth D. Merry  *
2129*ef270ab1SKenneth D. Merry  * @return None.
2130*ef270ab1SKenneth D. Merry  */
2131*ef270ab1SKenneth D. Merry 
2132*ef270ab1SKenneth D. Merry void
ocs_els_io_cleanup(ocs_io_t * els,ocs_sm_event_t node_evt,void * arg)2133*ef270ab1SKenneth D. Merry ocs_els_io_cleanup(ocs_io_t *els, ocs_sm_event_t node_evt, void *arg)
2134*ef270ab1SKenneth D. Merry {
2135*ef270ab1SKenneth D. Merry 	ocs_assert(els);
2136*ef270ab1SKenneth D. Merry 
2137*ef270ab1SKenneth D. Merry 	/* don't want further events that could come; e.g. abort requests
2138*ef270ab1SKenneth D. Merry 	 * from the node state machine; thus, disable state machine
2139*ef270ab1SKenneth D. Merry 	 */
2140*ef270ab1SKenneth D. Merry 	ocs_sm_disable(&els->els_sm);
2141*ef270ab1SKenneth D. Merry 	ocs_node_post_event(els->node, node_evt, arg);
2142*ef270ab1SKenneth D. Merry 
2143*ef270ab1SKenneth D. Merry 	/* If this IO has a callback, invoke it */
2144*ef270ab1SKenneth D. Merry 	if (els->els_callback) {
2145*ef270ab1SKenneth D. Merry 		(*els->els_callback)(els->node, arg, els->els_callback_arg);
2146*ef270ab1SKenneth D. Merry 	}
2147*ef270ab1SKenneth D. Merry 	els->els_req_free = 1;
2148*ef270ab1SKenneth D. Merry }
2149*ef270ab1SKenneth D. Merry 
2150*ef270ab1SKenneth D. Merry /**
2151*ef270ab1SKenneth D. Merry  * @brief Common event handler for the ELS IO state machine.
2152*ef270ab1SKenneth D. Merry  *
2153*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
2154*ef270ab1SKenneth D. Merry  * Provide handler for events for which default actions are desired.
2155*ef270ab1SKenneth D. Merry  *
2156*ef270ab1SKenneth D. Merry  * @param funcname Name of the calling function (for logging).
2157*ef270ab1SKenneth D. Merry  * @param ctx Remote node SM context.
2158*ef270ab1SKenneth D. Merry  * @param evt Event to process.
2159*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
2160*ef270ab1SKenneth D. Merry  *
2161*ef270ab1SKenneth D. Merry  * @return Returns NULL.
2162*ef270ab1SKenneth D. Merry  */
2163*ef270ab1SKenneth D. Merry 
2164*ef270ab1SKenneth D. Merry void *
__ocs_els_common(const char * funcname,ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)2165*ef270ab1SKenneth D. Merry __ocs_els_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
2166*ef270ab1SKenneth D. Merry {
2167*ef270ab1SKenneth D. Merry 	std_els_state_decl();
2168*ef270ab1SKenneth D. Merry 
2169*ef270ab1SKenneth D. Merry 	switch(evt) {
2170*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
2171*ef270ab1SKenneth D. Merry 	case OCS_EVT_REENTER:
2172*ef270ab1SKenneth D. Merry 	case OCS_EVT_EXIT:
2173*ef270ab1SKenneth D. Merry 		break;
2174*ef270ab1SKenneth D. Merry 
2175*ef270ab1SKenneth D. Merry 	/* If ELS_REQ_FAIL is not handled in state, then we'll terminate this ELS and
2176*ef270ab1SKenneth D. Merry 	 * pass the event to the node
2177*ef270ab1SKenneth D. Merry 	 */
2178*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_FAIL:
2179*ef270ab1SKenneth D. Merry 		ocs_log_warn(els->node->ocs, "[%s] %-20s %-20s not handled - terminating ELS\n", node->display_name, funcname,
2180*ef270ab1SKenneth D. Merry 			ocs_sm_event_name(evt));
2181*ef270ab1SKenneth D. Merry 		ocs_els_io_cleanup(els, OCS_EVT_SRRS_ELS_REQ_FAIL, arg);
2182*ef270ab1SKenneth D. Merry 		break;
2183*ef270ab1SKenneth D. Merry 	default:
2184*ef270ab1SKenneth D. Merry 		ocs_log_warn(els->node->ocs, "[%s] %-20s %-20s not handled\n", node->display_name, funcname,
2185*ef270ab1SKenneth D. Merry 			ocs_sm_event_name(evt));
2186*ef270ab1SKenneth D. Merry 		break;
2187*ef270ab1SKenneth D. Merry 	}
2188*ef270ab1SKenneth D. Merry 	return NULL;
2189*ef270ab1SKenneth D. Merry }
2190*ef270ab1SKenneth D. Merry 
2191*ef270ab1SKenneth D. Merry /**
2192*ef270ab1SKenneth D. Merry  * @brief Initial ELS IO state
2193*ef270ab1SKenneth D. Merry  *
2194*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
2195*ef270ab1SKenneth D. Merry  * This is the initial ELS IO state. Upon entry, the requested ELS/CT is submitted to
2196*ef270ab1SKenneth D. Merry  * the hardware.
2197*ef270ab1SKenneth D. Merry  *
2198*ef270ab1SKenneth D. Merry  * @param ctx Remote node SM context.
2199*ef270ab1SKenneth D. Merry  * @param evt Event to process.
2200*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
2201*ef270ab1SKenneth D. Merry  *
2202*ef270ab1SKenneth D. Merry  * @return Returns NULL.
2203*ef270ab1SKenneth D. Merry  */
2204*ef270ab1SKenneth D. Merry 
2205*ef270ab1SKenneth D. Merry void *
__ocs_els_init(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)2206*ef270ab1SKenneth D. Merry __ocs_els_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
2207*ef270ab1SKenneth D. Merry {
2208*ef270ab1SKenneth D. Merry 	int32_t rc = 0;
2209*ef270ab1SKenneth D. Merry 	std_els_state_decl();
2210*ef270ab1SKenneth D. Merry 
2211*ef270ab1SKenneth D. Merry 	els_sm_trace();
2212*ef270ab1SKenneth D. Merry 
2213*ef270ab1SKenneth D. Merry 	switch(evt) {
2214*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER: {
2215*ef270ab1SKenneth D. Merry 		rc = ocs_els_send(els, els->els_req.size, els->els_timeout_sec, ocs_els_req_cb);
2216*ef270ab1SKenneth D. Merry 		if (rc) {
2217*ef270ab1SKenneth D. Merry 			ocs_node_cb_t cbdata;
2218*ef270ab1SKenneth D. Merry 			cbdata.status = cbdata.ext_status = (~0);
2219*ef270ab1SKenneth D. Merry 			cbdata.els = els;
2220*ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "ocs_els_send failed: %d\n", rc);
2221*ef270ab1SKenneth D. Merry 			ocs_els_io_cleanup(els, OCS_EVT_SRRS_ELS_REQ_FAIL, &cbdata);
2222*ef270ab1SKenneth D. Merry 		} else {
2223*ef270ab1SKenneth D. Merry 			ocs_io_transition(els, __ocs_els_wait_resp, NULL);
2224*ef270ab1SKenneth D. Merry 		}
2225*ef270ab1SKenneth D. Merry 		break;
2226*ef270ab1SKenneth D. Merry 	}
2227*ef270ab1SKenneth D. Merry 	default:
2228*ef270ab1SKenneth D. Merry 		__ocs_els_common(__func__, ctx, evt, arg);
2229*ef270ab1SKenneth D. Merry 		break;
2230*ef270ab1SKenneth D. Merry 	}
2231*ef270ab1SKenneth D. Merry 
2232*ef270ab1SKenneth D. Merry 	return NULL;
2233*ef270ab1SKenneth D. Merry }
2234*ef270ab1SKenneth D. Merry 
2235*ef270ab1SKenneth D. Merry /**
2236*ef270ab1SKenneth D. Merry  * @brief Wait for the ELS request to complete.
2237*ef270ab1SKenneth D. Merry  *
2238*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
2239*ef270ab1SKenneth D. Merry  * This is the ELS IO state that waits for the submitted ELS event to complete.
2240*ef270ab1SKenneth D. Merry  * If an error completion event is received, the requested ELS is aborted.
2241*ef270ab1SKenneth D. Merry  *
2242*ef270ab1SKenneth D. Merry  * @param ctx Remote node SM context.
2243*ef270ab1SKenneth D. Merry  * @param evt Event to process.
2244*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
2245*ef270ab1SKenneth D. Merry  *
2246*ef270ab1SKenneth D. Merry  * @return Returns NULL.
2247*ef270ab1SKenneth D. Merry  */
2248*ef270ab1SKenneth D. Merry 
2249*ef270ab1SKenneth D. Merry void *
__ocs_els_wait_resp(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)2250*ef270ab1SKenneth D. Merry __ocs_els_wait_resp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
2251*ef270ab1SKenneth D. Merry {
2252*ef270ab1SKenneth D. Merry 	ocs_io_t *io;
2253*ef270ab1SKenneth D. Merry 	std_els_state_decl();
2254*ef270ab1SKenneth D. Merry 
2255*ef270ab1SKenneth D. Merry 	els_sm_trace();
2256*ef270ab1SKenneth D. Merry 
2257*ef270ab1SKenneth D. Merry 	switch(evt) {
2258*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_OK: {
2259*ef270ab1SKenneth D. Merry 		ocs_els_io_cleanup(els, OCS_EVT_SRRS_ELS_REQ_OK, arg);
2260*ef270ab1SKenneth D. Merry 		break;
2261*ef270ab1SKenneth D. Merry 	}
2262*ef270ab1SKenneth D. Merry 
2263*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_FAIL: {
2264*ef270ab1SKenneth D. Merry 		ocs_els_io_cleanup(els, OCS_EVT_SRRS_ELS_REQ_FAIL, arg);
2265*ef270ab1SKenneth D. Merry 		break;
2266*ef270ab1SKenneth D. Merry 	}
2267*ef270ab1SKenneth D. Merry 
2268*ef270ab1SKenneth D. Merry 	case OCS_EVT_ELS_REQ_TIMEOUT: {
2269*ef270ab1SKenneth D. Merry 		els_io_printf(els, "Timed out, retry (%d tries remaining)\n",
2270*ef270ab1SKenneth D. Merry 				els->els_retries_remaining-1);
2271*ef270ab1SKenneth D. Merry 		ocs_io_transition(els, __ocs_els_retry, NULL);
2272*ef270ab1SKenneth D. Merry 		break;
2273*ef270ab1SKenneth D. Merry 	}
2274*ef270ab1SKenneth D. Merry 
2275*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_RJT: {
2276*ef270ab1SKenneth D. Merry 		ocs_node_cb_t *cbdata = arg;
2277*ef270ab1SKenneth D. Merry 		uint32_t reason_code = (cbdata->ext_status >> 16) & 0xff;
2278*ef270ab1SKenneth D. Merry 
2279*ef270ab1SKenneth D. Merry 		/* delay and retry if reason code is Logical Busy */
2280*ef270ab1SKenneth D. Merry 		switch (reason_code) {
2281*ef270ab1SKenneth D. Merry 		case FC_REASON_LOGICAL_BUSY:
2282*ef270ab1SKenneth D. Merry 			els->node->els_req_cnt--;
2283*ef270ab1SKenneth D. Merry 			els_io_printf(els, "LS_RJT Logical Busy response, delay and retry\n");
2284*ef270ab1SKenneth D. Merry 			ocs_io_transition(els, __ocs_els_delay_retry, NULL);
2285*ef270ab1SKenneth D. Merry 			break;
2286*ef270ab1SKenneth D. Merry 		default:
2287*ef270ab1SKenneth D. Merry 			ocs_els_io_cleanup(els, evt, arg);
2288*ef270ab1SKenneth D. Merry 			break;
2289*ef270ab1SKenneth D. Merry 		}
2290*ef270ab1SKenneth D. Merry 		break;
2291*ef270ab1SKenneth D. Merry 	}
2292*ef270ab1SKenneth D. Merry 
2293*ef270ab1SKenneth D. Merry 	case OCS_EVT_ABORT_ELS: {
2294*ef270ab1SKenneth D. Merry 		/* request to abort this ELS without an ABTS */
2295*ef270ab1SKenneth D. Merry 		els_io_printf(els, "ELS abort requested\n");
2296*ef270ab1SKenneth D. Merry 		els->els_retries_remaining = 0;		/* Set retries to zero, we are done */
2297*ef270ab1SKenneth D. Merry 		io = ocs_els_abort_io(els, FALSE);
2298*ef270ab1SKenneth D. Merry 		if (io == NULL) {
2299*ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "ocs_els_send failed\n");
2300*ef270ab1SKenneth D. Merry 			ocs_els_io_cleanup(els, OCS_EVT_SRRS_ELS_REQ_FAIL, arg);
2301*ef270ab1SKenneth D. Merry 		} else {
2302*ef270ab1SKenneth D. Merry 			ocs_io_transition(els, __ocs_els_aborting, NULL);
2303*ef270ab1SKenneth D. Merry 		}
2304*ef270ab1SKenneth D. Merry 		break;
2305*ef270ab1SKenneth D. Merry 	}
2306*ef270ab1SKenneth D. Merry 
2307*ef270ab1SKenneth D. Merry 	default:
2308*ef270ab1SKenneth D. Merry 		__ocs_els_common(__func__, ctx, evt, arg);
2309*ef270ab1SKenneth D. Merry 		break;
2310*ef270ab1SKenneth D. Merry 	}
2311*ef270ab1SKenneth D. Merry 	return NULL;
2312*ef270ab1SKenneth D. Merry }
2313*ef270ab1SKenneth D. Merry 
2314*ef270ab1SKenneth D. Merry /**
2315*ef270ab1SKenneth D. Merry  * @brief Wait for the ELS IO abort request to complete, and retry the ELS.
2316*ef270ab1SKenneth D. Merry  *
2317*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
2318*ef270ab1SKenneth D. Merry  * This state is entered when waiting for an abort of an ELS
2319*ef270ab1SKenneth D. Merry  * request to complete so the request can be retried.
2320*ef270ab1SKenneth D. Merry  *
2321*ef270ab1SKenneth D. Merry  * @param ctx Remote node SM context.
2322*ef270ab1SKenneth D. Merry  * @param evt Event to process.
2323*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
2324*ef270ab1SKenneth D. Merry  *
2325*ef270ab1SKenneth D. Merry  * @return Returns NULL.
2326*ef270ab1SKenneth D. Merry  */
2327*ef270ab1SKenneth D. Merry 
2328*ef270ab1SKenneth D. Merry void *
__ocs_els_retry(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)2329*ef270ab1SKenneth D. Merry __ocs_els_retry(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
2330*ef270ab1SKenneth D. Merry {
2331*ef270ab1SKenneth D. Merry 	int32_t rc = 0;
2332*ef270ab1SKenneth D. Merry 	std_els_state_decl();
2333*ef270ab1SKenneth D. Merry 
2334*ef270ab1SKenneth D. Merry 	els_sm_trace();
2335*ef270ab1SKenneth D. Merry 
2336*ef270ab1SKenneth D. Merry 	switch(evt) {
2337*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER: {
2338*ef270ab1SKenneth D. Merry 		/* handle event for ABORT_XRI WQE
2339*ef270ab1SKenneth D. Merry 		 * once abort is complete, retry if retries left;
2340*ef270ab1SKenneth D. Merry 		 * don't need to wait for OCS_EVT_SRRS_ELS_REQ_* event because we got
2341*ef270ab1SKenneth D. Merry 		 * by receiving OCS_EVT_ELS_REQ_TIMEOUT
2342*ef270ab1SKenneth D. Merry 		 */
2343*ef270ab1SKenneth D. Merry 		ocs_node_cb_t node_cbdata;
2344*ef270ab1SKenneth D. Merry 		node_cbdata.status = node_cbdata.ext_status = (~0);
2345*ef270ab1SKenneth D. Merry 		node_cbdata.els = els;
2346*ef270ab1SKenneth D. Merry 		if (els->els_retries_remaining && --els->els_retries_remaining) {
2347*ef270ab1SKenneth D. Merry 			/* Use a different XRI for the retry (would like a new oxid),
2348*ef270ab1SKenneth D. Merry 			 * so free the HW IO (dispatch will allocate a new one). It's an
2349*ef270ab1SKenneth D. Merry 			 * optimization to only free the HW IO here and not the ocs_io_t;
2350*ef270ab1SKenneth D. Merry 			 * Freeing the ocs_io_t object would require copying all the necessary
2351*ef270ab1SKenneth D. Merry 			 * info from the old ocs_io_t object to the * new one; and allocating
2352*ef270ab1SKenneth D. Merry 			 * a new ocs_io_t could fail.
2353*ef270ab1SKenneth D. Merry 			 */
2354*ef270ab1SKenneth D. Merry 			ocs_assert(els->hio, NULL);
2355*ef270ab1SKenneth D. Merry 			ocs_hw_io_free(&ocs->hw, els->hio);
2356*ef270ab1SKenneth D. Merry 			els->hio = NULL;
2357*ef270ab1SKenneth D. Merry 
2358*ef270ab1SKenneth D. Merry 			/* result isn't propagated up to node sm, need to decrement req cnt */
2359*ef270ab1SKenneth D. Merry 			ocs_assert(els->node->els_req_cnt, NULL);
2360*ef270ab1SKenneth D. Merry 			els->node->els_req_cnt--;
2361*ef270ab1SKenneth D. Merry 			rc = ocs_els_send(els, els->els_req.size, els->els_timeout_sec, ocs_els_req_cb);
2362*ef270ab1SKenneth D. Merry 			if (rc) {
2363*ef270ab1SKenneth D. Merry 				ocs_log_err(ocs, "ocs_els_send failed: %d\n", rc);
2364*ef270ab1SKenneth D. Merry 				ocs_els_io_cleanup(els, OCS_EVT_SRRS_ELS_REQ_FAIL, &node_cbdata);
2365*ef270ab1SKenneth D. Merry 			}
2366*ef270ab1SKenneth D. Merry 			ocs_io_transition(els, __ocs_els_wait_resp, NULL);
2367*ef270ab1SKenneth D. Merry 		} else {
2368*ef270ab1SKenneth D. Merry 			els_io_printf(els, "Retries exhausted\n");
2369*ef270ab1SKenneth D. Merry 			ocs_els_io_cleanup(els, OCS_EVT_SRRS_ELS_REQ_FAIL, &node_cbdata);
2370*ef270ab1SKenneth D. Merry 		}
2371*ef270ab1SKenneth D. Merry 		break;
2372*ef270ab1SKenneth D. Merry 	}
2373*ef270ab1SKenneth D. Merry 
2374*ef270ab1SKenneth D. Merry 	default:
2375*ef270ab1SKenneth D. Merry 		__ocs_els_common(__func__, ctx, evt, arg);
2376*ef270ab1SKenneth D. Merry 		break;
2377*ef270ab1SKenneth D. Merry 	}
2378*ef270ab1SKenneth D. Merry 	return NULL;
2379*ef270ab1SKenneth D. Merry }
2380*ef270ab1SKenneth D. Merry 
2381*ef270ab1SKenneth D. Merry /**
2382*ef270ab1SKenneth D. Merry  * @brief Wait for a retry timer to expire having received an abort request
2383*ef270ab1SKenneth D. Merry  *
2384*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
2385*ef270ab1SKenneth D. Merry  * This state is entered when waiting for a timer event, after having received
2386*ef270ab1SKenneth D. Merry  * an abort request, to avoid a race condition with the timer handler
2387*ef270ab1SKenneth D. Merry  *
2388*ef270ab1SKenneth D. Merry  * @param ctx Remote node SM context.
2389*ef270ab1SKenneth D. Merry  * @param evt Event to process.
2390*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
2391*ef270ab1SKenneth D. Merry  *
2392*ef270ab1SKenneth D. Merry  * @return Returns NULL.
2393*ef270ab1SKenneth D. Merry  */
2394*ef270ab1SKenneth D. Merry void *
__ocs_els_aborted_delay_retry(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)2395*ef270ab1SKenneth D. Merry __ocs_els_aborted_delay_retry(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
2396*ef270ab1SKenneth D. Merry {
2397*ef270ab1SKenneth D. Merry 	std_els_state_decl();
2398*ef270ab1SKenneth D. Merry 
2399*ef270ab1SKenneth D. Merry 	els_sm_trace();
2400*ef270ab1SKenneth D. Merry 
2401*ef270ab1SKenneth D. Merry 	switch(evt) {
2402*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
2403*ef270ab1SKenneth D. Merry 		/* mod/resched the timer for a short duration */
2404*ef270ab1SKenneth D. Merry 		ocs_mod_timer(&els->delay_timer, 1);
2405*ef270ab1SKenneth D. Merry 		break;
2406*ef270ab1SKenneth D. Merry 	case OCS_EVT_TIMER_EXPIRED:
2407*ef270ab1SKenneth D. Merry 		/* Cancel the timer, skip post node event, and free the io */
2408*ef270ab1SKenneth D. Merry 		node->els_req_cnt++;
2409*ef270ab1SKenneth D. Merry 		ocs_els_io_cleanup(els, OCS_EVT_SRRS_ELS_REQ_FAIL, arg);
2410*ef270ab1SKenneth D. Merry 		break;
2411*ef270ab1SKenneth D. Merry 	default:
2412*ef270ab1SKenneth D. Merry 		__ocs_els_common(__func__, ctx, evt, arg);
2413*ef270ab1SKenneth D. Merry 		break;
2414*ef270ab1SKenneth D. Merry 	}
2415*ef270ab1SKenneth D. Merry 	return NULL;
2416*ef270ab1SKenneth D. Merry }
2417*ef270ab1SKenneth D. Merry 
2418*ef270ab1SKenneth D. Merry /**
2419*ef270ab1SKenneth D. Merry  * @brief Wait for a retry timer to expire
2420*ef270ab1SKenneth D. Merry  *
2421*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
2422*ef270ab1SKenneth D. Merry  * This state is entered when waiting for a timer event, so that
2423*ef270ab1SKenneth D. Merry  * the ELS request can be retried.
2424*ef270ab1SKenneth D. Merry  *
2425*ef270ab1SKenneth D. Merry  * @param ctx Remote node SM context.
2426*ef270ab1SKenneth D. Merry  * @param evt Event to process.
2427*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
2428*ef270ab1SKenneth D. Merry  *
2429*ef270ab1SKenneth D. Merry  * @return Returns NULL.
2430*ef270ab1SKenneth D. Merry  */
2431*ef270ab1SKenneth D. Merry void *
__ocs_els_delay_retry(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)2432*ef270ab1SKenneth D. Merry __ocs_els_delay_retry(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
2433*ef270ab1SKenneth D. Merry {
2434*ef270ab1SKenneth D. Merry 	std_els_state_decl();
2435*ef270ab1SKenneth D. Merry 
2436*ef270ab1SKenneth D. Merry 	els_sm_trace();
2437*ef270ab1SKenneth D. Merry 
2438*ef270ab1SKenneth D. Merry 	switch(evt) {
2439*ef270ab1SKenneth D. Merry 	case OCS_EVT_ENTER:
2440*ef270ab1SKenneth D. Merry 		ocs_setup_timer(ocs, &els->delay_timer, ocs_els_delay_timer_cb, els, 5000);
2441*ef270ab1SKenneth D. Merry 		break;
2442*ef270ab1SKenneth D. Merry 	case OCS_EVT_TIMER_EXPIRED:
2443*ef270ab1SKenneth D. Merry 		/* Retry delay timer expired, retry the ELS request, Free the HW IO so
2444*ef270ab1SKenneth D. Merry 		 * that a new oxid is used.
2445*ef270ab1SKenneth D. Merry 		 */
2446*ef270ab1SKenneth D. Merry 		if (els->hio != NULL) {
2447*ef270ab1SKenneth D. Merry 			ocs_hw_io_free(&ocs->hw, els->hio);
2448*ef270ab1SKenneth D. Merry 			els->hio = NULL;
2449*ef270ab1SKenneth D. Merry 		}
2450*ef270ab1SKenneth D. Merry 		ocs_io_transition(els, __ocs_els_init, NULL);
2451*ef270ab1SKenneth D. Merry 		break;
2452*ef270ab1SKenneth D. Merry 	case OCS_EVT_ABORT_ELS:
2453*ef270ab1SKenneth D. Merry 		ocs_io_transition(els, __ocs_els_aborted_delay_retry, NULL);
2454*ef270ab1SKenneth D. Merry 		break;
2455*ef270ab1SKenneth D. Merry 	default:
2456*ef270ab1SKenneth D. Merry 		__ocs_els_common(__func__, ctx, evt, arg);
2457*ef270ab1SKenneth D. Merry 		break;
2458*ef270ab1SKenneth D. Merry 	}
2459*ef270ab1SKenneth D. Merry 	return NULL;
2460*ef270ab1SKenneth D. Merry }
2461*ef270ab1SKenneth D. Merry 
2462*ef270ab1SKenneth D. Merry /**
2463*ef270ab1SKenneth D. Merry  * @brief Wait for the ELS IO abort request to complete.
2464*ef270ab1SKenneth D. Merry  *
2465*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
2466*ef270ab1SKenneth D. Merry  * This state is entered after we abort an ELS WQE and are
2467*ef270ab1SKenneth D. Merry  * waiting for either the original ELS WQE request or the abort
2468*ef270ab1SKenneth D. Merry  * to complete.
2469*ef270ab1SKenneth D. Merry  *
2470*ef270ab1SKenneth D. Merry  * @param ctx Remote node SM context.
2471*ef270ab1SKenneth D. Merry  * @param evt Event to process.
2472*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
2473*ef270ab1SKenneth D. Merry  *
2474*ef270ab1SKenneth D. Merry  * @return Returns NULL.
2475*ef270ab1SKenneth D. Merry  */
2476*ef270ab1SKenneth D. Merry 
2477*ef270ab1SKenneth D. Merry void *
__ocs_els_aborting(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)2478*ef270ab1SKenneth D. Merry __ocs_els_aborting(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
2479*ef270ab1SKenneth D. Merry {
2480*ef270ab1SKenneth D. Merry 	std_els_state_decl();
2481*ef270ab1SKenneth D. Merry 
2482*ef270ab1SKenneth D. Merry 	els_sm_trace();
2483*ef270ab1SKenneth D. Merry 
2484*ef270ab1SKenneth D. Merry 	switch(evt) {
2485*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_OK:
2486*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_FAIL:
2487*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_RJT:
2488*ef270ab1SKenneth D. Merry 	case OCS_EVT_ELS_REQ_TIMEOUT:
2489*ef270ab1SKenneth D. Merry 	case OCS_EVT_ELS_REQ_ABORTED: {
2490*ef270ab1SKenneth D. Merry 		/* completion for ELS received first, transition to wait for abort cmpl */
2491*ef270ab1SKenneth D. Merry 		els_io_printf(els, "request cmpl evt=%s\n", ocs_sm_event_name(evt));
2492*ef270ab1SKenneth D. Merry 		ocs_io_transition(els, __ocs_els_aborting_wait_abort_cmpl, NULL);
2493*ef270ab1SKenneth D. Merry 		break;
2494*ef270ab1SKenneth D. Merry 	}
2495*ef270ab1SKenneth D. Merry 	case OCS_EVT_ELS_ABORT_CMPL: {
2496*ef270ab1SKenneth D. Merry 		/* completion for abort was received first, transition to wait for req cmpl */
2497*ef270ab1SKenneth D. Merry 		els_io_printf(els, "abort cmpl evt=%s\n", ocs_sm_event_name(evt));
2498*ef270ab1SKenneth D. Merry 		ocs_io_transition(els, __ocs_els_aborting_wait_req_cmpl, NULL);
2499*ef270ab1SKenneth D. Merry 		break;
2500*ef270ab1SKenneth D. Merry 	}
2501*ef270ab1SKenneth D. Merry 	case OCS_EVT_ABORT_ELS:
2502*ef270ab1SKenneth D. Merry 		/* nothing we can do but wait */
2503*ef270ab1SKenneth D. Merry 		break;
2504*ef270ab1SKenneth D. Merry 
2505*ef270ab1SKenneth D. Merry 	default:
2506*ef270ab1SKenneth D. Merry 		__ocs_els_common(__func__, ctx, evt, arg);
2507*ef270ab1SKenneth D. Merry 		break;
2508*ef270ab1SKenneth D. Merry 	}
2509*ef270ab1SKenneth D. Merry 	return NULL;
2510*ef270ab1SKenneth D. Merry }
2511*ef270ab1SKenneth D. Merry 
2512*ef270ab1SKenneth D. Merry /**
2513*ef270ab1SKenneth D. Merry  * @brief cleanup ELS after abort
2514*ef270ab1SKenneth D. Merry  *
2515*ef270ab1SKenneth D. Merry  * @param els ELS IO to cleanup
2516*ef270ab1SKenneth D. Merry  *
2517*ef270ab1SKenneth D. Merry  * @return Returns None.
2518*ef270ab1SKenneth D. Merry  */
2519*ef270ab1SKenneth D. Merry 
2520*ef270ab1SKenneth D. Merry static void
ocs_els_abort_cleanup(ocs_io_t * els)2521*ef270ab1SKenneth D. Merry ocs_els_abort_cleanup(ocs_io_t *els)
2522*ef270ab1SKenneth D. Merry {
2523*ef270ab1SKenneth D. Merry 	/* handle event for ABORT_WQE
2524*ef270ab1SKenneth D. Merry 	 * whatever state ELS happened to be in, propagate aborted event up
2525*ef270ab1SKenneth D. Merry 	 * to node state machine in lieu of OCS_EVT_SRRS_ELS_* event
2526*ef270ab1SKenneth D. Merry 	 */
2527*ef270ab1SKenneth D. Merry 	ocs_node_cb_t cbdata;
2528*ef270ab1SKenneth D. Merry 	cbdata.status = cbdata.ext_status = 0;
2529*ef270ab1SKenneth D. Merry 	cbdata.els = els;
2530*ef270ab1SKenneth D. Merry 	els_io_printf(els, "Request aborted\n");
2531*ef270ab1SKenneth D. Merry 	ocs_els_io_cleanup(els, OCS_EVT_ELS_REQ_ABORTED, &cbdata);
2532*ef270ab1SKenneth D. Merry }
2533*ef270ab1SKenneth D. Merry 
2534*ef270ab1SKenneth D. Merry /**
2535*ef270ab1SKenneth D. Merry  * @brief Wait for the ELS IO abort request to complete.
2536*ef270ab1SKenneth D. Merry  *
2537*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
2538*ef270ab1SKenneth D. Merry  * This state is entered after we abort an ELS WQE, we received
2539*ef270ab1SKenneth D. Merry  * the abort completion first and are waiting for the original
2540*ef270ab1SKenneth D. Merry  * ELS WQE request to complete.
2541*ef270ab1SKenneth D. Merry  *
2542*ef270ab1SKenneth D. Merry  * @param ctx Remote node SM context.
2543*ef270ab1SKenneth D. Merry  * @param evt Event to process.
2544*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
2545*ef270ab1SKenneth D. Merry  *
2546*ef270ab1SKenneth D. Merry  * @return Returns NULL.
2547*ef270ab1SKenneth D. Merry  */
2548*ef270ab1SKenneth D. Merry 
2549*ef270ab1SKenneth D. Merry void *
__ocs_els_aborting_wait_req_cmpl(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)2550*ef270ab1SKenneth D. Merry __ocs_els_aborting_wait_req_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
2551*ef270ab1SKenneth D. Merry {
2552*ef270ab1SKenneth D. Merry 	std_els_state_decl();
2553*ef270ab1SKenneth D. Merry 
2554*ef270ab1SKenneth D. Merry 	els_sm_trace();
2555*ef270ab1SKenneth D. Merry 
2556*ef270ab1SKenneth D. Merry 	switch(evt) {
2557*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_OK:
2558*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_FAIL:
2559*ef270ab1SKenneth D. Merry 	case OCS_EVT_SRRS_ELS_REQ_RJT:
2560*ef270ab1SKenneth D. Merry 	case OCS_EVT_ELS_REQ_TIMEOUT:
2561*ef270ab1SKenneth D. Merry 	case OCS_EVT_ELS_REQ_ABORTED: {
2562*ef270ab1SKenneth D. Merry 		/* completion for ELS that was aborted */
2563*ef270ab1SKenneth D. Merry 		ocs_els_abort_cleanup(els);
2564*ef270ab1SKenneth D. Merry 		break;
2565*ef270ab1SKenneth D. Merry 	}
2566*ef270ab1SKenneth D. Merry 	case OCS_EVT_ABORT_ELS:
2567*ef270ab1SKenneth D. Merry 		/* nothing we can do but wait */
2568*ef270ab1SKenneth D. Merry 		break;
2569*ef270ab1SKenneth D. Merry 
2570*ef270ab1SKenneth D. Merry 	default:
2571*ef270ab1SKenneth D. Merry 		__ocs_els_common(__func__, ctx, evt, arg);
2572*ef270ab1SKenneth D. Merry 		break;
2573*ef270ab1SKenneth D. Merry 	}
2574*ef270ab1SKenneth D. Merry 	return NULL;
2575*ef270ab1SKenneth D. Merry }
2576*ef270ab1SKenneth D. Merry 
2577*ef270ab1SKenneth D. Merry /**
2578*ef270ab1SKenneth D. Merry  * @brief Wait for the ELS IO abort request to complete.
2579*ef270ab1SKenneth D. Merry  *
2580*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
2581*ef270ab1SKenneth D. Merry  * This state is entered after we abort an ELS WQE, we received
2582*ef270ab1SKenneth D. Merry  * the original ELS WQE request completion first and are waiting
2583*ef270ab1SKenneth D. Merry  * for the abort to complete.
2584*ef270ab1SKenneth D. Merry  *
2585*ef270ab1SKenneth D. Merry  * @param ctx Remote node SM context.
2586*ef270ab1SKenneth D. Merry  * @param evt Event to process.
2587*ef270ab1SKenneth D. Merry  * @param arg Per event optional argument.
2588*ef270ab1SKenneth D. Merry  *
2589*ef270ab1SKenneth D. Merry  * @return Returns NULL.
2590*ef270ab1SKenneth D. Merry  */
2591*ef270ab1SKenneth D. Merry 
2592*ef270ab1SKenneth D. Merry void *
__ocs_els_aborting_wait_abort_cmpl(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)2593*ef270ab1SKenneth D. Merry __ocs_els_aborting_wait_abort_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
2594*ef270ab1SKenneth D. Merry {
2595*ef270ab1SKenneth D. Merry 	std_els_state_decl();
2596*ef270ab1SKenneth D. Merry 
2597*ef270ab1SKenneth D. Merry 	els_sm_trace();
2598*ef270ab1SKenneth D. Merry 
2599*ef270ab1SKenneth D. Merry 	switch(evt) {
2600*ef270ab1SKenneth D. Merry 	case OCS_EVT_ELS_ABORT_CMPL: {
2601*ef270ab1SKenneth D. Merry 		ocs_els_abort_cleanup(els);
2602*ef270ab1SKenneth D. Merry 		break;
2603*ef270ab1SKenneth D. Merry 	}
2604*ef270ab1SKenneth D. Merry 	case OCS_EVT_ABORT_ELS:
2605*ef270ab1SKenneth D. Merry 		/* nothing we can do but wait */
2606*ef270ab1SKenneth D. Merry 		break;
2607*ef270ab1SKenneth D. Merry 
2608*ef270ab1SKenneth D. Merry 	default:
2609*ef270ab1SKenneth D. Merry 		__ocs_els_common(__func__, ctx, evt, arg);
2610*ef270ab1SKenneth D. Merry 		break;
2611*ef270ab1SKenneth D. Merry 	}
2612*ef270ab1SKenneth D. Merry 	return NULL;
2613*ef270ab1SKenneth D. Merry }
2614*ef270ab1SKenneth D. Merry 
2615*ef270ab1SKenneth D. Merry /**
2616*ef270ab1SKenneth D. Merry  * @brief Generate ELS context ddump data.
2617*ef270ab1SKenneth D. Merry  *
2618*ef270ab1SKenneth D. Merry  * <h3 class="desc">Description</h3>
2619*ef270ab1SKenneth D. Merry  * Generate the ddump data for an ELS context.
2620*ef270ab1SKenneth D. Merry  *
2621*ef270ab1SKenneth D. Merry  * @param textbuf Pointer to the text buffer.
2622*ef270ab1SKenneth D. Merry  * @param els Pointer to the ELS context.
2623*ef270ab1SKenneth D. Merry  *
2624*ef270ab1SKenneth D. Merry  * @return None.
2625*ef270ab1SKenneth D. Merry  */
2626*ef270ab1SKenneth D. Merry 
2627*ef270ab1SKenneth D. Merry void
ocs_ddump_els(ocs_textbuf_t * textbuf,ocs_io_t * els)2628*ef270ab1SKenneth D. Merry ocs_ddump_els(ocs_textbuf_t *textbuf, ocs_io_t *els)
2629*ef270ab1SKenneth D. Merry {
2630*ef270ab1SKenneth D. Merry 	ocs_ddump_section(textbuf, "els", -1);
2631*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "req_free", "%d", els->els_req_free);
2632*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "evtdepth", "%d", els->els_evtdepth);
2633*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "pend", "%d", els->els_pend);
2634*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "active", "%d", els->els_active);
2635*ef270ab1SKenneth D. Merry 	ocs_ddump_io(textbuf, els);
2636*ef270ab1SKenneth D. Merry 	ocs_ddump_endsection(textbuf, "els", -1);
2637*ef270ab1SKenneth D. Merry }
2638*ef270ab1SKenneth D. Merry 
2639*ef270ab1SKenneth D. Merry /**
2640*ef270ab1SKenneth D. Merry  * @brief return TRUE if given ELS list is empty (while taking proper locks)
2641*ef270ab1SKenneth D. Merry  *
2642*ef270ab1SKenneth D. Merry  * Test if given ELS list is empty while holding the node->active_ios_lock.
2643*ef270ab1SKenneth D. Merry  *
2644*ef270ab1SKenneth D. Merry  * @param node pointer to node object
2645*ef270ab1SKenneth D. Merry  * @param list pointer to list
2646*ef270ab1SKenneth D. Merry  *
2647*ef270ab1SKenneth D. Merry  * @return TRUE if els_io_list is empty
2648*ef270ab1SKenneth D. Merry  */
2649*ef270ab1SKenneth D. Merry 
2650*ef270ab1SKenneth D. Merry int32_t
ocs_els_io_list_empty(ocs_node_t * node,ocs_list_t * list)2651*ef270ab1SKenneth D. Merry ocs_els_io_list_empty(ocs_node_t *node, ocs_list_t *list)
2652*ef270ab1SKenneth D. Merry {
2653*ef270ab1SKenneth D. Merry 	int empty;
2654*ef270ab1SKenneth D. Merry 	ocs_lock(&node->active_ios_lock);
2655*ef270ab1SKenneth D. Merry 		empty = ocs_list_empty(list);
2656*ef270ab1SKenneth D. Merry 	ocs_unlock(&node->active_ios_lock);
2657*ef270ab1SKenneth D. Merry 	return empty;
2658*ef270ab1SKenneth D. Merry }
2659*ef270ab1SKenneth D. Merry 
2660*ef270ab1SKenneth D. Merry /**
2661*ef270ab1SKenneth D. Merry  * @brief Handle CT send response completion
2662*ef270ab1SKenneth D. Merry  *
2663*ef270ab1SKenneth D. Merry  * Called when CT response completes, free IO
2664*ef270ab1SKenneth D. Merry  *
2665*ef270ab1SKenneth D. Merry  * @param hio Pointer to the HW IO context that completed.
2666*ef270ab1SKenneth D. Merry  * @param rnode Pointer to the remote node.
2667*ef270ab1SKenneth D. Merry  * @param length Length of the returned payload data.
2668*ef270ab1SKenneth D. Merry  * @param status Status of the completion.
2669*ef270ab1SKenneth D. Merry  * @param ext_status Extended status of the completion.
2670*ef270ab1SKenneth D. Merry  * @param arg Application-specific argument (generally a pointer to the ELS IO context).
2671*ef270ab1SKenneth D. Merry  *
2672*ef270ab1SKenneth D. Merry  * @return returns 0
2673*ef270ab1SKenneth D. Merry  */
2674*ef270ab1SKenneth D. Merry static int32_t
ocs_ct_acc_cb(ocs_hw_io_t * hio,ocs_remote_node_t * rnode,uint32_t length,int32_t status,uint32_t ext_status,void * arg)2675*ef270ab1SKenneth D. Merry ocs_ct_acc_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *arg)
2676*ef270ab1SKenneth D. Merry {
2677*ef270ab1SKenneth D. Merry 	ocs_io_t *io = arg;
2678*ef270ab1SKenneth D. Merry 
2679*ef270ab1SKenneth D. Merry 	ocs_els_io_free(io);
2680*ef270ab1SKenneth D. Merry 
2681*ef270ab1SKenneth D. Merry 	return 0;
2682*ef270ab1SKenneth D. Merry }
2683*ef270ab1SKenneth D. Merry 
2684*ef270ab1SKenneth D. Merry /**
2685*ef270ab1SKenneth D. Merry  * @brief Send CT response
2686*ef270ab1SKenneth D. Merry  *
2687*ef270ab1SKenneth D. Merry  * Sends a CT response frame with payload
2688*ef270ab1SKenneth D. Merry  *
2689*ef270ab1SKenneth D. Merry  * @param io Pointer to the IO context.
2690*ef270ab1SKenneth D. Merry  * @param ox_id Originator exchange ID
2691*ef270ab1SKenneth D. Merry  * @param ct_hdr Pointer to the CT IU
2692*ef270ab1SKenneth D. Merry  * @param cmd_rsp_code CT response code
2693*ef270ab1SKenneth D. Merry  * @param reason_code Reason code
2694*ef270ab1SKenneth D. Merry  * @param reason_code_explanation Reason code explanation
2695*ef270ab1SKenneth D. Merry  *
2696*ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
2697*ef270ab1SKenneth D. Merry  */
2698*ef270ab1SKenneth D. Merry int32_t
ocs_send_ct_rsp(ocs_io_t * io,uint32_t ox_id,fcct_iu_header_t * ct_hdr,uint32_t cmd_rsp_code,uint32_t reason_code,uint32_t reason_code_explanation)2699*ef270ab1SKenneth D. Merry ocs_send_ct_rsp(ocs_io_t *io, uint32_t ox_id, fcct_iu_header_t *ct_hdr, uint32_t cmd_rsp_code, uint32_t reason_code, uint32_t reason_code_explanation)
2700*ef270ab1SKenneth D. Merry {
2701*ef270ab1SKenneth D. Merry 	fcct_iu_header_t *rsp = io->els_rsp.virt;
2702*ef270ab1SKenneth D. Merry 
2703*ef270ab1SKenneth D. Merry 	io->io_type = OCS_IO_TYPE_CT_RESP;
2704*ef270ab1SKenneth D. Merry 
2705*ef270ab1SKenneth D. Merry 	*rsp = *ct_hdr;
2706*ef270ab1SKenneth D. Merry 
2707*ef270ab1SKenneth D. Merry 	fcct_build_req_header(rsp, cmd_rsp_code, 0);
2708*ef270ab1SKenneth D. Merry 	rsp->reason_code = reason_code;
2709*ef270ab1SKenneth D. Merry 	rsp->reason_code_explanation = reason_code_explanation;
2710*ef270ab1SKenneth D. Merry 
2711*ef270ab1SKenneth D. Merry 	io->display_name = "ct response";
2712*ef270ab1SKenneth D. Merry 	io->init_task_tag = ox_id;
2713*ef270ab1SKenneth D. Merry 	io->wire_len += sizeof(*rsp);
2714*ef270ab1SKenneth D. Merry 
2715*ef270ab1SKenneth D. Merry 	ocs_memset(&io->iparam, 0, sizeof(io->iparam));
2716*ef270ab1SKenneth D. Merry 
2717*ef270ab1SKenneth D. Merry 	io->io_type = OCS_IO_TYPE_CT_RESP;
2718*ef270ab1SKenneth D. Merry 	io->hio_type = OCS_HW_FC_CT_RSP;
2719*ef270ab1SKenneth D. Merry 	io->iparam.fc_ct_rsp.ox_id = ocs_htobe16(ox_id);
2720*ef270ab1SKenneth D. Merry 	io->iparam.fc_ct_rsp.r_ctl = 3;
2721*ef270ab1SKenneth D. Merry 	io->iparam.fc_ct_rsp.type = FC_TYPE_GS;
2722*ef270ab1SKenneth D. Merry 	io->iparam.fc_ct_rsp.df_ctl = 0;
2723*ef270ab1SKenneth D. Merry 	io->iparam.fc_ct_rsp.timeout = 5;
2724*ef270ab1SKenneth D. Merry 
2725*ef270ab1SKenneth D. Merry 	if (ocs_scsi_io_dispatch(io, ocs_ct_acc_cb) < 0) {
2726*ef270ab1SKenneth D. Merry 		ocs_els_io_free(io);
2727*ef270ab1SKenneth D. Merry 		return -1;
2728*ef270ab1SKenneth D. Merry 	}
2729*ef270ab1SKenneth D. Merry 	return 0;
2730*ef270ab1SKenneth D. Merry }
2731*ef270ab1SKenneth D. Merry 
2732*ef270ab1SKenneth D. Merry /**
2733*ef270ab1SKenneth D. Merry  * @brief Handle delay retry timeout
2734*ef270ab1SKenneth D. Merry  *
2735*ef270ab1SKenneth D. Merry  * Callback is invoked when the delay retry timer expires.
2736*ef270ab1SKenneth D. Merry  *
2737*ef270ab1SKenneth D. Merry  * @param arg pointer to the ELS IO object
2738*ef270ab1SKenneth D. Merry  *
2739*ef270ab1SKenneth D. Merry  * @return none
2740*ef270ab1SKenneth D. Merry  */
2741*ef270ab1SKenneth D. Merry static void
ocs_els_delay_timer_cb(void * arg)2742*ef270ab1SKenneth D. Merry ocs_els_delay_timer_cb(void *arg)
2743*ef270ab1SKenneth D. Merry {
2744*ef270ab1SKenneth D. Merry 	ocs_io_t *els = arg;
2745*ef270ab1SKenneth D. Merry 	ocs_node_t *node = els->node;
2746*ef270ab1SKenneth D. Merry 
2747*ef270ab1SKenneth D. Merry 	/*
2748*ef270ab1SKenneth D. Merry 	 * There is a potential deadlock here since is Linux executes timers
2749*ef270ab1SKenneth D. Merry 	 * in a soft IRQ context. The lock may be aready locked by the interrupt
2750*ef270ab1SKenneth D. Merry 	 * thread. Handle this case by attempting to take the node lock and reset the
2751*ef270ab1SKenneth D. Merry 	 * timer if we fail to acquire the lock.
2752*ef270ab1SKenneth D. Merry 	 *
2753*ef270ab1SKenneth D. Merry 	 * Note: This code relies on the fact that the node lock is recursive.
2754*ef270ab1SKenneth D. Merry 	 */
2755*ef270ab1SKenneth D. Merry 	if (ocs_node_lock_try(node)) {
2756*ef270ab1SKenneth D. Merry 		ocs_els_post_event(els, OCS_EVT_TIMER_EXPIRED, NULL);
2757*ef270ab1SKenneth D. Merry 		ocs_node_unlock(node);
2758*ef270ab1SKenneth D. Merry 	} else {
2759*ef270ab1SKenneth D. Merry 		ocs_setup_timer(els->ocs, &els->delay_timer, ocs_els_delay_timer_cb, els, 1);
2760*ef270ab1SKenneth D. Merry 	}
2761*ef270ab1SKenneth D. Merry }
2762