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