Merge tag 'firewire-fixes-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / scsi / bfa / bfa_fcs_fcpim.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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 }