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