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