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