1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
4 * Copyright (c) 2014- QLogic Corporation.
5 * All rights reserved
6 * www.qlogic.com
7 *
8 * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
9 */
10
11/*
12 *  fcpim.c - FCP initiator mode i-t nexus state machine
13 */
14
15#include "bfad_drv.h"
16#include "bfa_fcs.h"
17#include "bfa_fcbuild.h"
18#include "bfad_im.h"
19#include "bfa_fcpim.h"
20
21BFA_TRC_FILE(FCS, FCPIM);
22
23/*
24 * forward declarations
25 */
26static void	bfa_fcs_itnim_timeout(void *arg);
27static void	bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim);
28static void	bfa_fcs_itnim_send_prli(void *itnim_cbarg,
29					struct bfa_fcxp_s *fcxp_alloced);
30static void	bfa_fcs_itnim_prli_response(void *fcsarg,
31			 struct bfa_fcxp_s *fcxp, void *cbarg,
32			    bfa_status_t req_status, u32 rsp_len,
33			    u32 resid_len, struct fchs_s *rsp_fchs);
34static void	bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
35			enum bfa_itnim_aen_event event);
36
37static void	bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
38					 enum bfa_fcs_itnim_event event);
39static void	bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim,
40					   enum bfa_fcs_itnim_event event);
41static void	bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
42				      enum bfa_fcs_itnim_event event);
43static void	bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
44					    enum bfa_fcs_itnim_event event);
45static void	bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
46					    enum bfa_fcs_itnim_event event);
47static void	bfa_fcs_itnim_sm_hal_rport_online(struct bfa_fcs_itnim_s *itnim,
48					enum bfa_fcs_itnim_event event);
49static void	bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
50					enum bfa_fcs_itnim_event event);
51static void	bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim,
52					     enum bfa_fcs_itnim_event event);
53static void	bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
54					   enum bfa_fcs_itnim_event event);
55
56struct bfa_fcs_itnim_sm_table_s {
57	bfa_fcs_itnim_sm_t sm;		/*  state machine function	*/
58	enum bfa_itnim_state state;	/*  state machine encoding	*/
59	char		*name;		/*  state name for display	*/
60};
61
62static inline enum bfa_itnim_state
63bfa_fcs_itnim_sm_to_state(struct bfa_fcs_itnim_sm_table_s *smt, bfa_fcs_itnim_sm_t sm)
64{
65	int i = 0;
66
67	while (smt[i].sm && smt[i].sm != sm)
68		i++;
69	return smt[i].state;
70}
71
72static struct bfa_fcs_itnim_sm_table_s itnim_sm_table[] = {
73	{BFA_SM(bfa_fcs_itnim_sm_offline), BFA_ITNIM_OFFLINE},
74	{BFA_SM(bfa_fcs_itnim_sm_prli_send), BFA_ITNIM_PRLI_SEND},
75	{BFA_SM(bfa_fcs_itnim_sm_prli), BFA_ITNIM_PRLI_SENT},
76	{BFA_SM(bfa_fcs_itnim_sm_prli_retry), BFA_ITNIM_PRLI_RETRY},
77	{BFA_SM(bfa_fcs_itnim_sm_hcb_online), BFA_ITNIM_HCB_ONLINE},
78	{BFA_SM(bfa_fcs_itnim_sm_online), BFA_ITNIM_ONLINE},
79	{BFA_SM(bfa_fcs_itnim_sm_hcb_offline), BFA_ITNIM_HCB_OFFLINE},
80	{BFA_SM(bfa_fcs_itnim_sm_initiator), BFA_ITNIM_INITIATIOR},
81};
82
83/*
84 *  fcs_itnim_sm FCS itnim state machine
85 */
86
87static void
88bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
89		 enum bfa_fcs_itnim_event event)
90{
91	bfa_trc(itnim->fcs, itnim->rport->pwwn);
92	bfa_trc(itnim->fcs, event);
93
94	switch (event) {
95	case BFA_FCS_ITNIM_SM_FCS_ONLINE:
96		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send);
97		itnim->prli_retries = 0;
98		bfa_fcs_itnim_send_prli(itnim, NULL);
99		break;
100
101	case BFA_FCS_ITNIM_SM_OFFLINE:
102		bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
103		break;
104
105	case BFA_FCS_ITNIM_SM_INITIATOR:
106		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
107		break;
108
109	case BFA_FCS_ITNIM_SM_DELETE:
110		bfa_fcs_itnim_free(itnim);
111		break;
112
113	default:
114		bfa_sm_fault(itnim->fcs, event);
115	}
116
117}
118
119static void
120bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim,
121		 enum bfa_fcs_itnim_event event)
122{
123	bfa_trc(itnim->fcs, itnim->rport->pwwn);
124	bfa_trc(itnim->fcs, event);
125
126	switch (event) {
127	case BFA_FCS_ITNIM_SM_FRMSENT:
128		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli);
129		break;
130
131	case BFA_FCS_ITNIM_SM_INITIATOR:
132		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
133		bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe);
134		bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_FCS_ONLINE);
135		break;
136
137	case BFA_FCS_ITNIM_SM_OFFLINE:
138		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
139		bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe);
140		bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
141		break;
142
143	case BFA_FCS_ITNIM_SM_DELETE:
144		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
145		bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe);
146		bfa_fcs_itnim_free(itnim);
147		break;
148
149	default:
150		bfa_sm_fault(itnim->fcs, event);
151	}
152}
153
154static void
155bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
156		 enum bfa_fcs_itnim_event event)
157{
158	bfa_trc(itnim->fcs, itnim->rport->pwwn);
159	bfa_trc(itnim->fcs, event);
160
161	switch (event) {
162	case BFA_FCS_ITNIM_SM_RSP_OK:
163		if (itnim->rport->scsi_function == BFA_RPORT_INITIATOR)
164			bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
165		else
166			bfa_sm_set_state(itnim,
167				bfa_fcs_itnim_sm_hal_rport_online);
168
169		bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_FCS_ONLINE);
170		break;
171
172	case BFA_FCS_ITNIM_SM_RSP_ERROR:
173		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_retry);
174		bfa_timer_start(itnim->fcs->bfa, &itnim->timer,
175				bfa_fcs_itnim_timeout, itnim,
176				BFA_FCS_RETRY_TIMEOUT);
177		break;
178
179	case BFA_FCS_ITNIM_SM_RSP_NOT_SUPP:
180		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
181		break;
182
183	case BFA_FCS_ITNIM_SM_OFFLINE:
184		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
185		bfa_fcxp_discard(itnim->fcxp);
186		bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
187		break;
188
189	case BFA_FCS_ITNIM_SM_INITIATOR:
190		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
191		bfa_fcxp_discard(itnim->fcxp);
192		bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_FCS_ONLINE);
193		break;
194
195	case BFA_FCS_ITNIM_SM_DELETE:
196		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
197		bfa_fcxp_discard(itnim->fcxp);
198		bfa_fcs_itnim_free(itnim);
199		break;
200
201	default:
202		bfa_sm_fault(itnim->fcs, event);
203	}
204}
205
206static void
207bfa_fcs_itnim_sm_hal_rport_online(struct bfa_fcs_itnim_s *itnim,
208				enum bfa_fcs_itnim_event event)
209{
210	bfa_trc(itnim->fcs, itnim->rport->pwwn);
211	bfa_trc(itnim->fcs, event);
212
213	switch (event) {
214	case BFA_FCS_ITNIM_SM_HAL_ONLINE:
215		if (!itnim->bfa_itnim)
216			itnim->bfa_itnim = bfa_itnim_create(itnim->fcs->bfa,
217					itnim->rport->bfa_rport, itnim);
218
219		if (itnim->bfa_itnim) {
220			bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_online);
221			bfa_itnim_online(itnim->bfa_itnim, itnim->seq_rec);
222		} else {
223			bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
224			bfa_sm_send_event(itnim->rport, RPSM_EVENT_DELETE);
225		}
226
227		break;
228
229	case BFA_FCS_ITNIM_SM_OFFLINE:
230		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
231		bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
232		break;
233
234	case BFA_FCS_ITNIM_SM_DELETE:
235		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
236		bfa_fcs_itnim_free(itnim);
237		break;
238
239	default:
240		bfa_sm_fault(itnim->fcs, event);
241	}
242}
243
244static void
245bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
246			    enum bfa_fcs_itnim_event event)
247{
248	bfa_trc(itnim->fcs, itnim->rport->pwwn);
249	bfa_trc(itnim->fcs, event);
250
251	switch (event) {
252	case BFA_FCS_ITNIM_SM_TIMEOUT:
253		if (itnim->prli_retries < BFA_FCS_RPORT_MAX_RETRIES) {
254			itnim->prli_retries++;
255			bfa_trc(itnim->fcs, itnim->prli_retries);
256			bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send);
257			bfa_fcs_itnim_send_prli(itnim, NULL);
258		} else {
259			/* invoke target offline */
260			bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
261			bfa_sm_send_event(itnim->rport, RPSM_EVENT_LOGO_IMP);
262		}
263		break;
264
265
266	case BFA_FCS_ITNIM_SM_OFFLINE:
267		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
268		bfa_timer_stop(&itnim->timer);
269		bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
270		break;
271
272	case BFA_FCS_ITNIM_SM_INITIATOR:
273		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
274		bfa_timer_stop(&itnim->timer);
275		bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_FCS_ONLINE);
276		break;
277
278	case BFA_FCS_ITNIM_SM_DELETE:
279		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
280		bfa_timer_stop(&itnim->timer);
281		bfa_fcs_itnim_free(itnim);
282		break;
283
284	default:
285		bfa_sm_fault(itnim->fcs, event);
286	}
287}
288
289static void
290bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
291			    enum bfa_fcs_itnim_event event)
292{
293	struct bfad_s *bfad = (struct bfad_s *)itnim->fcs->bfad;
294	char	lpwwn_buf[BFA_STRING_32];
295	char	rpwwn_buf[BFA_STRING_32];
296
297	bfa_trc(itnim->fcs, itnim->rport->pwwn);
298	bfa_trc(itnim->fcs, event);
299
300	switch (event) {
301	case BFA_FCS_ITNIM_SM_HCB_ONLINE:
302		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_online);
303		bfa_fcb_itnim_online(itnim->itnim_drv);
304		wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port));
305		wwn2str(rpwwn_buf, itnim->rport->pwwn);
306		BFA_LOG(KERN_INFO, bfad, bfa_log_level,
307		"Target (WWN = %s) is online for initiator (WWN = %s)\n",
308		rpwwn_buf, lpwwn_buf);
309		bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_ONLINE);
310		break;
311
312	case BFA_FCS_ITNIM_SM_OFFLINE:
313		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_offline);
314		bfa_itnim_offline(itnim->bfa_itnim);
315		break;
316
317	case BFA_FCS_ITNIM_SM_DELETE:
318		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
319		bfa_fcs_itnim_free(itnim);
320		break;
321
322	default:
323		bfa_sm_fault(itnim->fcs, event);
324	}
325}
326
327static void
328bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
329		 enum bfa_fcs_itnim_event event)
330{
331	struct bfad_s *bfad = (struct bfad_s *)itnim->fcs->bfad;
332	char	lpwwn_buf[BFA_STRING_32];
333	char	rpwwn_buf[BFA_STRING_32];
334
335	bfa_trc(itnim->fcs, itnim->rport->pwwn);
336	bfa_trc(itnim->fcs, event);
337
338	switch (event) {
339	case BFA_FCS_ITNIM_SM_OFFLINE:
340		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_offline);
341		bfa_fcb_itnim_offline(itnim->itnim_drv);
342		bfa_itnim_offline(itnim->bfa_itnim);
343		wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port));
344		wwn2str(rpwwn_buf, itnim->rport->pwwn);
345		if (bfa_fcs_lport_is_online(itnim->rport->port) == BFA_TRUE) {
346			BFA_LOG(KERN_ERR, bfad, bfa_log_level,
347			"Target (WWN = %s) connectivity lost for "
348			"initiator (WWN = %s)\n", rpwwn_buf, lpwwn_buf);
349			bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_DISCONNECT);
350		} else {
351			BFA_LOG(KERN_INFO, bfad, bfa_log_level,
352			"Target (WWN = %s) offlined by initiator (WWN = %s)\n",
353			rpwwn_buf, lpwwn_buf);
354			bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_OFFLINE);
355		}
356		break;
357
358	case BFA_FCS_ITNIM_SM_DELETE:
359		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
360		bfa_fcs_itnim_free(itnim);
361		break;
362
363	default:
364		bfa_sm_fault(itnim->fcs, event);
365	}
366}
367
368static void
369bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim,
370			     enum bfa_fcs_itnim_event event)
371{
372	bfa_trc(itnim->fcs, itnim->rport->pwwn);
373	bfa_trc(itnim->fcs, event);
374
375	switch (event) {
376	case BFA_FCS_ITNIM_SM_HCB_OFFLINE:
377		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
378		bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
379		break;
380
381	case BFA_FCS_ITNIM_SM_DELETE:
382		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
383		bfa_fcs_itnim_free(itnim);
384		break;
385
386	default:
387		bfa_sm_fault(itnim->fcs, event);
388	}
389}
390
391/*
392 * This state is set when a discovered rport is also in intiator mode.
393 * This ITN is marked as no_op and is not active and will not be truned into
394 * online state.
395 */
396static void
397bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
398		 enum bfa_fcs_itnim_event event)
399{
400	bfa_trc(itnim->fcs, itnim->rport->pwwn);
401	bfa_trc(itnim->fcs, event);
402
403	switch (event) {
404	case BFA_FCS_ITNIM_SM_OFFLINE:
405		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
406		bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
407		break;
408
409	/*
410	 * fcs_online is expected here for well known initiator ports
411	 */
412	case BFA_FCS_ITNIM_SM_FCS_ONLINE:
413		bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_FCS_ONLINE);
414		break;
415
416	case BFA_FCS_ITNIM_SM_RSP_ERROR:
417	case BFA_FCS_ITNIM_SM_INITIATOR:
418		break;
419
420	case BFA_FCS_ITNIM_SM_DELETE:
421		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
422		bfa_fcs_itnim_free(itnim);
423		break;
424
425	default:
426		bfa_sm_fault(itnim->fcs, event);
427	}
428}
429
430static void
431bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
432			enum bfa_itnim_aen_event event)
433{
434	struct bfa_fcs_rport_s *rport = itnim->rport;
435	struct bfad_s *bfad = (struct bfad_s *)itnim->fcs->bfad;
436	struct bfa_aen_entry_s	*aen_entry;
437
438	/* Don't post events for well known addresses */
439	if (BFA_FCS_PID_IS_WKA(rport->pid))
440		return;
441
442	bfad_get_aen_entry(bfad, aen_entry);
443	if (!aen_entry)
444		return;
445
446	aen_entry->aen_data.itnim.vf_id = rport->port->fabric->vf_id;
447	aen_entry->aen_data.itnim.ppwwn = bfa_fcs_lport_get_pwwn(
448					bfa_fcs_get_base_port(itnim->fcs));
449	aen_entry->aen_data.itnim.lpwwn = bfa_fcs_lport_get_pwwn(rport->port);
450	aen_entry->aen_data.itnim.rpwwn = rport->pwwn;
451
452	/* Send the AEN notification */
453	bfad_im_post_vendor_event(aen_entry, bfad, ++rport->fcs->fcs_aen_seq,
454				  BFA_AEN_CAT_ITNIM, event);
455}
456
457static void
458bfa_fcs_itnim_send_prli(void *itnim_cbarg, struct bfa_fcxp_s *fcxp_alloced)
459{
460	struct bfa_fcs_itnim_s *itnim = itnim_cbarg;
461	struct bfa_fcs_rport_s *rport = itnim->rport;
462	struct bfa_fcs_lport_s *port = rport->port;
463	struct fchs_s	fchs;
464	struct bfa_fcxp_s *fcxp;
465	int		len;
466
467	bfa_trc(itnim->fcs, itnim->rport->pwwn);
468
469	fcxp = fcxp_alloced ? fcxp_alloced :
470	       bfa_fcs_fcxp_alloc(port->fcs, BFA_TRUE);
471	if (!fcxp) {
472		itnim->stats.fcxp_alloc_wait++;
473		bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &itnim->fcxp_wqe,
474				bfa_fcs_itnim_send_prli, itnim, BFA_TRUE);
475		return;
476	}
477	itnim->fcxp = fcxp;
478
479	len = fc_prli_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
480			    itnim->rport->pid, bfa_fcs_lport_get_fcid(port), 0);
481
482	bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id, port->lp_tag,
483		      BFA_FALSE, FC_CLASS_3, len, &fchs,
484		      bfa_fcs_itnim_prli_response, (void *)itnim,
485		      FC_MAX_PDUSZ, FC_ELS_TOV);
486
487	itnim->stats.prli_sent++;
488	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_FRMSENT);
489}
490
491static void
492bfa_fcs_itnim_prli_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
493			    bfa_status_t req_status, u32 rsp_len,
494			    u32 resid_len, struct fchs_s *rsp_fchs)
495{
496	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cbarg;
497	struct fc_els_cmd_s *els_cmd;
498	struct fc_prli_s *prli_resp;
499	struct fc_ls_rjt_s *ls_rjt;
500	struct fc_prli_params_s *sparams;
501
502	bfa_trc(itnim->fcs, req_status);
503
504	/*
505	 * Sanity Checks
506	 */
507	if (req_status != BFA_STATUS_OK) {
508		itnim->stats.prli_rsp_err++;
509		bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR);
510		return;
511	}
512
513	els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);
514
515	if (els_cmd->els_code == FC_ELS_ACC) {
516		prli_resp = (struct fc_prli_s *) els_cmd;
517
518		if (fc_prli_rsp_parse(prli_resp, rsp_len) != FC_PARSE_OK) {
519			bfa_trc(itnim->fcs, rsp_len);
520			/*
521			 * Check if this  r-port is also in Initiator mode.
522			 * If so, we need to set this ITN as a no-op.
523			 */
524			if (prli_resp->parampage.servparams.initiator) {
525				bfa_trc(itnim->fcs, prli_resp->parampage.type);
526				itnim->rport->scsi_function =
527						BFA_RPORT_INITIATOR;
528				itnim->stats.prli_rsp_acc++;
529				itnim->stats.initiator++;
530				bfa_sm_send_event(itnim,
531						  BFA_FCS_ITNIM_SM_RSP_OK);
532				return;
533			}
534
535			itnim->stats.prli_rsp_parse_err++;
536			return;
537		}
538		itnim->rport->scsi_function = BFA_RPORT_TARGET;
539
540		sparams = &prli_resp->parampage.servparams;
541		itnim->seq_rec	     = sparams->retry;
542		itnim->rec_support   = sparams->rec_support;
543		itnim->task_retry_id = sparams->task_retry_id;
544		itnim->conf_comp     = sparams->confirm;
545
546		itnim->stats.prli_rsp_acc++;
547		bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_OK);
548	} else {
549		ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);
550
551		bfa_trc(itnim->fcs, ls_rjt->reason_code);
552		bfa_trc(itnim->fcs, ls_rjt->reason_code_expl);
553
554		itnim->stats.prli_rsp_rjt++;
555		if (ls_rjt->reason_code == FC_LS_RJT_RSN_CMD_NOT_SUPP) {
556			bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_NOT_SUPP);
557			return;
558		}
559		bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR);
560	}
561}
562
563static void
564bfa_fcs_itnim_timeout(void *arg)
565{
566	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) arg;
567
568	itnim->stats.timeout++;
569	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_TIMEOUT);
570}
571
572static void
573bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim)
574{
575	if (itnim->bfa_itnim) {
576		bfa_itnim_delete(itnim->bfa_itnim);
577		itnim->bfa_itnim = NULL;
578	}
579
580	bfa_fcb_itnim_free(itnim->fcs->bfad, itnim->itnim_drv);
581}
582
583
584
585/*
586 *  itnim_public FCS ITNIM public interfaces
587 */
588
589/*
590 *	Called by rport when a new rport is created.
591 *
592 * @param[in] rport	-  remote port.
593 */
594struct bfa_fcs_itnim_s *
595bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport)
596{
597	struct bfa_fcs_lport_s *port = rport->port;
598	struct bfa_fcs_itnim_s *itnim;
599	struct bfad_itnim_s   *itnim_drv;
600	int ret;
601
602	/*
603	 * call bfad to allocate the itnim
604	 */
605	ret = bfa_fcb_itnim_alloc(port->fcs->bfad, &itnim, &itnim_drv);
606	if (ret) {
607		bfa_trc(port->fcs, rport->pwwn);
608		return NULL;
609	}
610
611	/*
612	 * Initialize itnim
613	 */
614	itnim->rport = rport;
615	itnim->fcs = rport->fcs;
616	itnim->itnim_drv = itnim_drv;
617
618	itnim->bfa_itnim     = NULL;
619	itnim->seq_rec	     = BFA_FALSE;
620	itnim->rec_support   = BFA_FALSE;
621	itnim->conf_comp     = BFA_FALSE;
622	itnim->task_retry_id = BFA_FALSE;
623
624	/*
625	 * Set State machine
626	 */
627	bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
628
629	return itnim;
630}
631
632/*
633 *	Called by rport to delete  the instance of FCPIM.
634 *
635 * @param[in] rport	-  remote port.
636 */
637void
638bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim)
639{
640	bfa_trc(itnim->fcs, itnim->rport->pid);
641	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_DELETE);
642}
643
644/*
645 * Notification from rport that PLOGI is complete to initiate FC-4 session.
646 */
647void
648bfa_fcs_itnim_brp_online(struct bfa_fcs_itnim_s *itnim)
649{
650	itnim->stats.onlines++;
651
652	if (!BFA_FCS_PID_IS_WKA(itnim->rport->pid))
653		bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HAL_ONLINE);
654}
655
656/*
657 * Called by rport to handle a remote device offline.
658 */
659void
660bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim)
661{
662	itnim->stats.offlines++;
663	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_OFFLINE);
664}
665
666/*
667 * Called by rport when remote port is known to be an initiator from
668 * PRLI received.
669 */
670void
671bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim)
672{
673	bfa_trc(itnim->fcs, itnim->rport->pid);
674	itnim->stats.initiator++;
675	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR);
676}
677
678/*
679 * Called by rport to check if the itnim is online.
680 */
681bfa_status_t
682bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim)
683{
684	bfa_trc(itnim->fcs, itnim->rport->pid);
685	switch (bfa_fcs_itnim_sm_to_state(itnim_sm_table, itnim->sm)) {
686	case BFA_ITNIM_ONLINE:
687	case BFA_ITNIM_INITIATIOR:
688		return BFA_STATUS_OK;
689
690	default:
691		return BFA_STATUS_NO_FCPIM_NEXUS;
692	}
693}
694
695/*
696 * BFA completion callback for bfa_itnim_online().
697 */
698void
699bfa_cb_itnim_online(void *cbarg)
700{
701	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cbarg;
702
703	bfa_trc(itnim->fcs, itnim->rport->pwwn);
704	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_ONLINE);
705}
706
707/*
708 * BFA completion callback for bfa_itnim_offline().
709 */
710void
711bfa_cb_itnim_offline(void *cb_arg)
712{
713	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
714
715	bfa_trc(itnim->fcs, itnim->rport->pwwn);
716	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_OFFLINE);
717}
718
719/*
720 * Mark the beginning of PATH TOV handling. IO completion callbacks
721 * are still pending.
722 */
723void
724bfa_cb_itnim_tov_begin(void *cb_arg)
725{
726	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
727
728	bfa_trc(itnim->fcs, itnim->rport->pwwn);
729}
730
731/*
732 * Mark the end of PATH TOV handling. All pending IOs are already cleaned up.
733 */
734void
735bfa_cb_itnim_tov(void *cb_arg)
736{
737	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
738	struct bfad_itnim_s *itnim_drv = itnim->itnim_drv;
739
740	bfa_trc(itnim->fcs, itnim->rport->pwwn);
741	itnim_drv->state = ITNIM_STATE_TIMEOUT;
742}
743
744/*
745 *		BFA notification to FCS/driver for second level error recovery.
746 *
747 * Atleast one I/O request has timedout and target is unresponsive to
748 * repeated abort requests. Second level error recovery should be initiated
749 * by starting implicit logout and recovery procedures.
750 */
751void
752bfa_cb_itnim_sler(void *cb_arg)
753{
754	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
755
756	itnim->stats.sler++;
757	bfa_trc(itnim->fcs, itnim->rport->pwwn);
758	bfa_sm_send_event(itnim->rport, RPSM_EVENT_LOGO_IMP);
759}
760
761struct bfa_fcs_itnim_s *
762bfa_fcs_itnim_lookup(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
763{
764	struct bfa_fcs_rport_s *rport;
765	rport = bfa_fcs_rport_lookup(port, rpwwn);
766
767	if (!rport)
768		return NULL;
769
770	WARN_ON(rport->itnim == NULL);
771	return rport->itnim;
772}
773
774bfa_status_t
775bfa_fcs_itnim_attr_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn,
776		       struct bfa_itnim_attr_s *attr)
777{
778	struct bfa_fcs_itnim_s *itnim = NULL;
779
780	itnim = bfa_fcs_itnim_lookup(port, rpwwn);
781
782	if (itnim == NULL)
783		return BFA_STATUS_NO_FCPIM_NEXUS;
784
785	attr->state	    = bfa_fcs_itnim_sm_to_state(itnim_sm_table, itnim->sm);
786	attr->retry	    = itnim->seq_rec;
787	attr->rec_support   = itnim->rec_support;
788	attr->conf_comp	    = itnim->conf_comp;
789	attr->task_retry_id = itnim->task_retry_id;
790	return BFA_STATUS_OK;
791}
792
793bfa_status_t
794bfa_fcs_itnim_stats_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn,
795			struct bfa_itnim_stats_s *stats)
796{
797	struct bfa_fcs_itnim_s *itnim = NULL;
798
799	WARN_ON(port == NULL);
800
801	itnim = bfa_fcs_itnim_lookup(port, rpwwn);
802
803	if (itnim == NULL)
804		return BFA_STATUS_NO_FCPIM_NEXUS;
805
806	memcpy(stats, &itnim->stats, sizeof(struct bfa_itnim_stats_s));
807
808	return BFA_STATUS_OK;
809}
810
811bfa_status_t
812bfa_fcs_itnim_stats_clear(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
813{
814	struct bfa_fcs_itnim_s *itnim = NULL;
815
816	WARN_ON(port == NULL);
817
818	itnim = bfa_fcs_itnim_lookup(port, rpwwn);
819
820	if (itnim == NULL)
821		return BFA_STATUS_NO_FCPIM_NEXUS;
822
823	memset(&itnim->stats, 0, sizeof(struct bfa_itnim_stats_s));
824	return BFA_STATUS_OK;
825}
826
827void
828bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim,
829			struct fchs_s *fchs, u16 len)
830{
831	struct fc_els_cmd_s *els_cmd;
832
833	bfa_trc(itnim->fcs, fchs->type);
834
835	if (fchs->type != FC_TYPE_ELS)
836		return;
837
838	els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
839
840	bfa_trc(itnim->fcs, els_cmd->els_code);
841
842	switch (els_cmd->els_code) {
843	case FC_ELS_PRLO:
844		bfa_fcs_rport_prlo(itnim->rport, fchs->ox_id);
845		break;
846
847	default:
848		WARN_ON(1);
849	}
850}
851