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