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