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