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