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