71d23d19bc9d62975aeed68b0013c481a68fcfd4
[safe/jmp/linux-2.6] / 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         switch (event) {
389         case BFA_ITNIM_AEN_ONLINE:
390                 bfa_log(logmod, BFA_AEN_ITNIM_ONLINE, rpwwn_ptr, lpwwn_ptr);
391                 break;
392         case BFA_ITNIM_AEN_OFFLINE:
393                 bfa_log(logmod, BFA_AEN_ITNIM_OFFLINE, rpwwn_ptr, lpwwn_ptr);
394                 break;
395         case BFA_ITNIM_AEN_DISCONNECT:
396                 bfa_log(logmod, BFA_AEN_ITNIM_DISCONNECT, rpwwn_ptr, lpwwn_ptr);
397                 break;
398         default:
399                 break;
400         }
401
402         aen_data.itnim.vf_id = rport->port->fabric->vf_id;
403         aen_data.itnim.ppwwn =
404                 bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(itnim->fcs));
405         aen_data.itnim.lpwwn = lpwwn;
406         aen_data.itnim.rpwwn = rpwwn;
407 }
408
409 static void
410 bfa_fcs_itnim_send_prli(void *itnim_cbarg, struct bfa_fcxp_s *fcxp_alloced)
411 {
412         struct bfa_fcs_itnim_s *itnim = itnim_cbarg;
413         struct bfa_fcs_rport_s *rport = itnim->rport;
414         struct bfa_fcs_port_s *port = rport->port;
415         struct fchs_s          fchs;
416         struct bfa_fcxp_s *fcxp;
417         int             len;
418
419         bfa_trc(itnim->fcs, itnim->rport->pwwn);
420
421         fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
422         if (!fcxp) {
423                 itnim->stats.fcxp_alloc_wait++;
424                 bfa_fcxp_alloc_wait(port->fcs->bfa, &itnim->fcxp_wqe,
425                                     bfa_fcs_itnim_send_prli, itnim);
426                 return;
427         }
428         itnim->fcxp = fcxp;
429
430         len = fc_prli_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), itnim->rport->pid,
431                             bfa_fcs_port_get_fcid(port), 0);
432
433         bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id, port->lp_tag,
434                       BFA_FALSE, FC_CLASS_3, len, &fchs,
435                       bfa_fcs_itnim_prli_response, (void *)itnim, FC_MAX_PDUSZ,
436                       FC_RA_TOV);
437
438         itnim->stats.prli_sent++;
439         bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_FRMSENT);
440 }
441
442 static void
443 bfa_fcs_itnim_prli_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
444                             bfa_status_t req_status, u32 rsp_len,
445                             u32 resid_len, struct fchs_s *rsp_fchs)
446 {
447         struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cbarg;
448         struct fc_els_cmd_s   *els_cmd;
449         struct fc_prli_s      *prli_resp;
450         struct fc_ls_rjt_s    *ls_rjt;
451         struct fc_prli_params_s *sparams;
452
453         bfa_trc(itnim->fcs, req_status);
454
455         /*
456          * Sanity Checks
457          */
458         if (req_status != BFA_STATUS_OK) {
459                 itnim->stats.prli_rsp_err++;
460                 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR);
461                 return;
462         }
463
464         els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);
465
466         if (els_cmd->els_code == FC_ELS_ACC) {
467                 prli_resp = (struct fc_prli_s *) els_cmd;
468
469                 if (fc_prli_rsp_parse(prli_resp, rsp_len) != FC_PARSE_OK) {
470                         bfa_trc(itnim->fcs, rsp_len);
471                         /*
472                          * Check if this  r-port is also in Initiator mode.
473                          * If so, we need to set this ITN as a no-op.
474                          */
475                         if (prli_resp->parampage.servparams.initiator) {
476                                 bfa_trc(itnim->fcs, prli_resp->parampage.type);
477                                 itnim->rport->scsi_function =
478                                         BFA_RPORT_INITIATOR;
479                                 itnim->stats.prli_rsp_acc++;
480                                 bfa_sm_send_event(itnim,
481                                                   BFA_FCS_ITNIM_SM_INITIATOR);
482                                 return;
483                         }
484
485                         itnim->stats.prli_rsp_parse_err++;
486                         return;
487                 }
488                 itnim->rport->scsi_function = BFA_RPORT_TARGET;
489
490                 sparams = &prli_resp->parampage.servparams;
491                 itnim->seq_rec = sparams->retry;
492                 itnim->rec_support = sparams->rec_support;
493                 itnim->task_retry_id = sparams->task_retry_id;
494                 itnim->conf_comp = sparams->confirm;
495
496                 itnim->stats.prli_rsp_acc++;
497                 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_OK);
498         } else {
499                 ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);
500
501                 bfa_trc(itnim->fcs, ls_rjt->reason_code);
502                 bfa_trc(itnim->fcs, ls_rjt->reason_code_expl);
503
504                 itnim->stats.prli_rsp_rjt++;
505                 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR);
506         }
507 }
508
509 static void
510 bfa_fcs_itnim_timeout(void *arg)
511 {
512         struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)arg;
513
514         itnim->stats.timeout++;
515         bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_TIMEOUT);
516 }
517
518 static void
519 bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim)
520 {
521         bfa_itnim_delete(itnim->bfa_itnim);
522         bfa_fcb_itnim_free(itnim->fcs->bfad, itnim->itnim_drv);
523 }
524
525
526
527 /**
528  *  itnim_public FCS ITNIM public interfaces
529  */
530
531 /**
532  *      Called by rport when a new rport is created.
533  *
534  * @param[in] rport     -  remote port.
535  */
536 struct bfa_fcs_itnim_s *
537 bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport)
538 {
539         struct bfa_fcs_port_s *port = rport->port;
540         struct bfa_fcs_itnim_s *itnim;
541         struct bfad_itnim_s *itnim_drv;
542         struct bfa_itnim_s *bfa_itnim;
543
544         /*
545          * call bfad to allocate the itnim
546          */
547         bfa_fcb_itnim_alloc(port->fcs->bfad, &itnim, &itnim_drv);
548         if (itnim == NULL) {
549                 bfa_trc(port->fcs, rport->pwwn);
550                 return NULL;
551         }
552
553         /*
554          * Initialize itnim
555          */
556         itnim->rport = rport;
557         itnim->fcs = rport->fcs;
558         itnim->itnim_drv = itnim_drv;
559
560         /*
561          * call BFA to create the itnim
562          */
563         bfa_itnim = bfa_itnim_create(port->fcs->bfa, rport->bfa_rport, itnim);
564
565         if (bfa_itnim == NULL) {
566                 bfa_trc(port->fcs, rport->pwwn);
567                 bfa_fcb_itnim_free(port->fcs->bfad, itnim_drv);
568                 bfa_assert(0);
569                 return NULL;
570         }
571
572         itnim->bfa_itnim = bfa_itnim;
573         itnim->seq_rec = BFA_FALSE;
574         itnim->rec_support = BFA_FALSE;
575         itnim->conf_comp = BFA_FALSE;
576         itnim->task_retry_id = BFA_FALSE;
577
578         /*
579          * Set State machine
580          */
581         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
582
583         return itnim;
584 }
585
586 /**
587  *      Called by rport to delete  the instance of FCPIM.
588  *
589  * @param[in] rport     -  remote port.
590  */
591 void
592 bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim)
593 {
594         bfa_trc(itnim->fcs, itnim->rport->pid);
595         bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_DELETE);
596 }
597
598 /**
599  * Notification from rport that PLOGI is complete to initiate FC-4 session.
600  */
601 void
602 bfa_fcs_itnim_rport_online(struct bfa_fcs_itnim_s *itnim)
603 {
604         itnim->stats.onlines++;
605
606         if (!BFA_FCS_PID_IS_WKA(itnim->rport->pid)) {
607                 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_ONLINE);
608         } else {
609                 /*
610                  * For well known addresses, we set the itnim to initiator
611                  * state
612                  */
613                 itnim->stats.initiator++;
614                 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR);
615         }
616 }
617
618 /**
619  * Called by rport to handle a remote device offline.
620  */
621 void
622 bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim)
623 {
624         itnim->stats.offlines++;
625         bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_OFFLINE);
626 }
627
628 /**
629  * Called by rport when remote port is known to be an initiator from
630  * PRLI received.
631  */
632 void
633 bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim)
634 {
635         bfa_trc(itnim->fcs, itnim->rport->pid);
636         itnim->stats.initiator++;
637         bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR);
638 }
639
640 /**
641  * Called by rport to check if the itnim is online.
642  */
643 bfa_status_t
644 bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim)
645 {
646         bfa_trc(itnim->fcs, itnim->rport->pid);
647         switch (bfa_sm_to_state(itnim_sm_table, itnim->sm)) {
648         case BFA_ITNIM_ONLINE:
649         case BFA_ITNIM_INITIATIOR:
650                 return BFA_STATUS_OK;
651
652         default:
653                 return BFA_STATUS_NO_FCPIM_NEXUS;
654
655         }
656 }
657
658 /**
659  * BFA completion callback for bfa_itnim_online().
660  */
661 void
662 bfa_cb_itnim_online(void *cbarg)
663 {
664         struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cbarg;
665
666         bfa_trc(itnim->fcs, itnim->rport->pwwn);
667         bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_ONLINE);
668 }
669
670 /**
671  * BFA completion callback for bfa_itnim_offline().
672  */
673 void
674 bfa_cb_itnim_offline(void *cb_arg)
675 {
676         struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg;
677
678         bfa_trc(itnim->fcs, itnim->rport->pwwn);
679         bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_OFFLINE);
680 }
681
682 /**
683  * Mark the beginning of PATH TOV handling. IO completion callbacks
684  * are still pending.
685  */
686 void
687 bfa_cb_itnim_tov_begin(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_begin(itnim->itnim_drv);
693 }
694
695 /**
696  * Mark the end of PATH TOV handling. All pending IOs are already cleaned up.
697  */
698 void
699 bfa_cb_itnim_tov(void *cb_arg)
700 {
701         struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg;
702
703         bfa_trc(itnim->fcs, itnim->rport->pwwn);
704         bfa_fcb_itnim_tov(itnim->itnim_drv);
705 }
706
707 /**
708  *              BFA notification to FCS/driver for second level error recovery.
709  *
710  * Atleast one I/O request has timedout and target is unresponsive to
711  * repeated abort requests. Second level error recovery should be initiated
712  * by starting implicit logout and recovery procedures.
713  */
714 void
715 bfa_cb_itnim_sler(void *cb_arg)
716 {
717         struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg;
718
719         itnim->stats.sler++;
720         bfa_trc(itnim->fcs, itnim->rport->pwwn);
721         bfa_fcs_rport_logo_imp(itnim->rport);
722 }
723
724 struct bfa_fcs_itnim_s *
725 bfa_fcs_itnim_lookup(struct bfa_fcs_port_s *port, wwn_t rpwwn)
726 {
727         struct bfa_fcs_rport_s *rport;
728         rport = bfa_fcs_rport_lookup(port, rpwwn);
729
730         if (!rport)
731                 return NULL;
732
733         bfa_assert(rport->itnim != NULL);
734         return rport->itnim;
735 }
736
737 bfa_status_t
738 bfa_fcs_itnim_attr_get(struct bfa_fcs_port_s *port, wwn_t rpwwn,
739                        struct bfa_itnim_attr_s *attr)
740 {
741         struct bfa_fcs_itnim_s *itnim = NULL;
742
743         itnim = bfa_fcs_itnim_lookup(port, rpwwn);
744
745         if (itnim == NULL)
746                 return BFA_STATUS_NO_FCPIM_NEXUS;
747
748         attr->state = bfa_sm_to_state(itnim_sm_table, itnim->sm);
749         attr->retry = itnim->seq_rec;
750         attr->rec_support = itnim->rec_support;
751         attr->conf_comp = itnim->conf_comp;
752         attr->task_retry_id = itnim->task_retry_id;
753
754         return BFA_STATUS_OK;
755 }
756
757 bfa_status_t
758 bfa_fcs_itnim_stats_get(struct bfa_fcs_port_s *port, wwn_t rpwwn,
759                         struct bfa_itnim_stats_s *stats)
760 {
761         struct bfa_fcs_itnim_s *itnim = NULL;
762
763         bfa_assert(port != NULL);
764
765         itnim = bfa_fcs_itnim_lookup(port, rpwwn);
766
767         if (itnim == NULL)
768                 return BFA_STATUS_NO_FCPIM_NEXUS;
769
770         bfa_os_memcpy(stats, &itnim->stats, sizeof(struct bfa_itnim_stats_s));
771
772         return BFA_STATUS_OK;
773 }
774
775 bfa_status_t
776 bfa_fcs_itnim_stats_clear(struct bfa_fcs_port_s *port, wwn_t rpwwn)
777 {
778         struct bfa_fcs_itnim_s *itnim = NULL;
779
780         bfa_assert(port != NULL);
781
782         itnim = bfa_fcs_itnim_lookup(port, rpwwn);
783
784         if (itnim == NULL)
785                 return BFA_STATUS_NO_FCPIM_NEXUS;
786
787         bfa_os_memset(&itnim->stats, 0, sizeof(struct bfa_itnim_stats_s));
788         return BFA_STATUS_OK;
789 }
790
791 void
792 bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, struct fchs_s *fchs,
793                       u16 len)
794 {
795         struct fc_els_cmd_s   *els_cmd;
796
797         bfa_trc(itnim->fcs, fchs->type);
798
799         if (fchs->type != FC_TYPE_ELS)
800                 return;
801
802         els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
803
804         bfa_trc(itnim->fcs, els_cmd->els_code);
805
806         switch (els_cmd->els_code) {
807         case FC_ELS_PRLO:
808                 /* bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_PRLO); */
809                 break;
810
811         default:
812                 bfa_assert(0);
813         }
814 }
815
816 void
817 bfa_fcs_itnim_pause(struct bfa_fcs_itnim_s *itnim)
818 {
819 }
820
821 void
822 bfa_fcs_itnim_resume(struct bfa_fcs_itnim_s *itnim)
823 {
824 }