xref: /linux/drivers/scsi/bfa/bfa_fcs_fcpim.c (revision 1f20a5769446a1acae67ac9e63d07a594829a789)
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 
21 BFA_TRC_FILE(FCS, FCPIM);
22 
23 /*
24  * forward declarations
25  */
26 static void	bfa_fcs_itnim_timeout(void *arg);
27 static void	bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim);
28 static void	bfa_fcs_itnim_send_prli(void *itnim_cbarg,
29 					struct bfa_fcxp_s *fcxp_alloced);
30 static 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);
34 static void	bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
35 			enum bfa_itnim_aen_event event);
36 
37 static void	bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
38 					 enum bfa_fcs_itnim_event event);
39 static void	bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim,
40 					   enum bfa_fcs_itnim_event event);
41 static void	bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
42 				      enum bfa_fcs_itnim_event event);
43 static void	bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
44 					    enum bfa_fcs_itnim_event event);
45 static void	bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
46 					    enum bfa_fcs_itnim_event event);
47 static void	bfa_fcs_itnim_sm_hal_rport_online(struct bfa_fcs_itnim_s *itnim,
48 					enum bfa_fcs_itnim_event event);
49 static void	bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
50 					enum bfa_fcs_itnim_event event);
51 static void	bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim,
52 					     enum bfa_fcs_itnim_event event);
53 static void	bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
54 					   enum bfa_fcs_itnim_event event);
55 
56 struct 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 
62 static inline enum bfa_itnim_state
63 bfa_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 
72 static 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 
87 static void
88 bfa_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 
119 static void
120 bfa_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 
154 static void
155 bfa_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 
206 static void
207 bfa_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 
244 static void
245 bfa_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 
289 static void
290 bfa_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 
327 static void
328 bfa_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 
368 static void
369 bfa_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  */
396 static void
397 bfa_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 
430 static void
431 bfa_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 
457 static void
458 bfa_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 
491 static void
492 bfa_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 
563 static void
564 bfa_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 
572 static void
573 bfa_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  */
594 struct bfa_fcs_itnim_s *
595 bfa_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  */
637 void
638 bfa_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  */
647 void
648 bfa_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  */
659 void
660 bfa_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  */
670 void
671 bfa_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  */
681 bfa_status_t
682 bfa_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  */
698 void
699 bfa_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  */
710 void
711 bfa_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  */
723 void
724 bfa_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  */
734 void
735 bfa_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  */
751 void
752 bfa_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 
761 struct bfa_fcs_itnim_s *
762 bfa_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 
774 bfa_status_t
775 bfa_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 
793 bfa_status_t
794 bfa_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 
811 bfa_status_t
812 bfa_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 
827 void
828 bfa_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