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