]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/scsi/bfa/fcpim.c
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[mv-sheeva.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_assert(0);
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_assert(0);
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_assert(0);
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_assert(0);
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_assert(0);
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                 }
294                 break;
295
296         case BFA_FCS_ITNIM_SM_DELETE:
297                 bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
298                 bfa_fcs_itnim_free(itnim);
299                 break;
300
301         default:
302                 bfa_assert(0);
303         }
304 }
305
306 static void
307 bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim,
308                              enum bfa_fcs_itnim_event event)
309 {
310         bfa_trc(itnim->fcs, itnim->rport->pwwn);
311         bfa_trc(itnim->fcs, event);
312
313         switch (event) {
314         case BFA_FCS_ITNIM_SM_HCB_OFFLINE:
315                 bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
316                 bfa_fcs_rport_itnim_ack(itnim->rport);
317                 break;
318
319         case BFA_FCS_ITNIM_SM_DELETE:
320                 bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
321                 bfa_fcs_itnim_free(itnim);
322                 break;
323
324         default:
325                 bfa_assert(0);
326         }
327 }
328
329 /*
330  * This state is set when a discovered rport is also in intiator mode.
331  * This ITN is marked as no_op and is not active and will not be truned into
332  * online state.
333  */
334 static void
335 bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
336                            enum bfa_fcs_itnim_event event)
337 {
338         bfa_trc(itnim->fcs, itnim->rport->pwwn);
339         bfa_trc(itnim->fcs, event);
340
341         switch (event) {
342         case BFA_FCS_ITNIM_SM_OFFLINE:
343                 bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
344                 bfa_fcs_rport_itnim_ack(itnim->rport);
345                 break;
346
347         case BFA_FCS_ITNIM_SM_RSP_ERROR:
348         case BFA_FCS_ITNIM_SM_ONLINE:
349         case BFA_FCS_ITNIM_SM_INITIATOR:
350                 break;
351
352         case BFA_FCS_ITNIM_SM_DELETE:
353                 bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
354                 bfa_fcs_itnim_free(itnim);
355                 break;
356
357         default:
358                 bfa_assert(0);
359         }
360 }
361
362
363
364 /**
365  *  itnim_private FCS ITNIM private interfaces
366  */
367
368 static void
369 bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
370                        enum bfa_itnim_aen_event event)
371 {
372         struct bfa_fcs_rport_s *rport = itnim->rport;
373         union bfa_aen_data_u aen_data;
374         struct bfa_log_mod_s *logmod = rport->fcs->logm;
375         wwn_t           lpwwn = bfa_fcs_port_get_pwwn(rport->port);
376         wwn_t           rpwwn = rport->pwwn;
377         char            lpwwn_ptr[BFA_STRING_32];
378         char            rpwwn_ptr[BFA_STRING_32];
379
380         /*
381          * Don't post events for well known addresses
382          */
383         if (BFA_FCS_PID_IS_WKA(rport->pid))
384                 return;
385
386         wwn2str(lpwwn_ptr, lpwwn);
387         wwn2str(rpwwn_ptr, rpwwn);
388
389         switch (event) {
390         case BFA_ITNIM_AEN_ONLINE:
391                 bfa_log(logmod, BFA_AEN_ITNIM_ONLINE, rpwwn_ptr, lpwwn_ptr);
392                 break;
393         case BFA_ITNIM_AEN_OFFLINE:
394                 bfa_log(logmod, BFA_AEN_ITNIM_OFFLINE, rpwwn_ptr, lpwwn_ptr);
395                 break;
396         case BFA_ITNIM_AEN_DISCONNECT:
397                 bfa_log(logmod, BFA_AEN_ITNIM_DISCONNECT, rpwwn_ptr, lpwwn_ptr);
398                 break;
399         default:
400                 break;
401         }
402
403         aen_data.itnim.vf_id = rport->port->fabric->vf_id;
404         aen_data.itnim.ppwwn =
405                 bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(itnim->fcs));
406         aen_data.itnim.lpwwn = lpwwn;
407         aen_data.itnim.rpwwn = rpwwn;
408 }
409
410 static void
411 bfa_fcs_itnim_send_prli(void *itnim_cbarg, struct bfa_fcxp_s *fcxp_alloced)
412 {
413         struct bfa_fcs_itnim_s *itnim = itnim_cbarg;
414         struct bfa_fcs_rport_s *rport = itnim->rport;
415         struct bfa_fcs_port_s *port = rport->port;
416         struct fchs_s          fchs;
417         struct bfa_fcxp_s *fcxp;
418         int             len;
419
420         bfa_trc(itnim->fcs, itnim->rport->pwwn);
421
422         fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
423         if (!fcxp) {
424                 itnim->stats.fcxp_alloc_wait++;
425                 bfa_fcxp_alloc_wait(port->fcs->bfa, &itnim->fcxp_wqe,
426                                     bfa_fcs_itnim_send_prli, itnim);
427                 return;
428         }
429         itnim->fcxp = fcxp;
430
431         len = fc_prli_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), itnim->rport->pid,
432                             bfa_fcs_port_get_fcid(port), 0);
433
434         bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id, port->lp_tag,
435                       BFA_FALSE, FC_CLASS_3, len, &fchs,
436                       bfa_fcs_itnim_prli_response, (void *)itnim, FC_MAX_PDUSZ,
437                       FC_RA_TOV);
438
439         itnim->stats.prli_sent++;
440         bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_FRMSENT);
441 }
442
443 static void
444 bfa_fcs_itnim_prli_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
445                             bfa_status_t req_status, u32 rsp_len,
446                             u32 resid_len, struct fchs_s *rsp_fchs)
447 {
448         struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cbarg;
449         struct fc_els_cmd_s   *els_cmd;
450         struct fc_prli_s      *prli_resp;
451         struct fc_ls_rjt_s    *ls_rjt;
452         struct fc_prli_params_s *sparams;
453
454         bfa_trc(itnim->fcs, req_status);
455
456         /*
457          * Sanity Checks
458          */
459         if (req_status != BFA_STATUS_OK) {
460                 itnim->stats.prli_rsp_err++;
461                 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR);
462                 return;
463         }
464
465         els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);
466
467         if (els_cmd->els_code == FC_ELS_ACC) {
468                 prli_resp = (struct fc_prli_s *) els_cmd;
469
470                 if (fc_prli_rsp_parse(prli_resp, rsp_len) != FC_PARSE_OK) {
471                         bfa_trc(itnim->fcs, rsp_len);
472                         /*
473                          * Check if this  r-port is also in Initiator mode.
474                          * If so, we need to set this ITN as a no-op.
475                          */
476                         if (prli_resp->parampage.servparams.initiator) {
477                                 bfa_trc(itnim->fcs, prli_resp->parampage.type);
478                                 itnim->rport->scsi_function =
479                                         BFA_RPORT_INITIATOR;
480                                 itnim->stats.prli_rsp_acc++;
481                                 bfa_sm_send_event(itnim,
482                                                   BFA_FCS_ITNIM_SM_INITIATOR);
483                                 return;
484                         }
485
486                         itnim->stats.prli_rsp_parse_err++;
487                         return;
488                 }
489                 itnim->rport->scsi_function = BFA_RPORT_TARGET;
490
491                 sparams = &prli_resp->parampage.servparams;
492                 itnim->seq_rec = sparams->retry;
493                 itnim->rec_support = sparams->rec_support;
494                 itnim->task_retry_id = sparams->task_retry_id;
495                 itnim->conf_comp = sparams->confirm;
496
497                 itnim->stats.prli_rsp_acc++;
498                 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_OK);
499         } else {
500                 ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);
501
502                 bfa_trc(itnim->fcs, ls_rjt->reason_code);
503                 bfa_trc(itnim->fcs, ls_rjt->reason_code_expl);
504
505                 itnim->stats.prli_rsp_rjt++;
506                 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR);
507         }
508 }
509
510 static void
511 bfa_fcs_itnim_timeout(void *arg)
512 {
513         struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)arg;
514
515         itnim->stats.timeout++;
516         bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_TIMEOUT);
517 }
518
519 static void
520 bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim)
521 {
522         bfa_itnim_delete(itnim->bfa_itnim);
523         bfa_fcb_itnim_free(itnim->fcs->bfad, itnim->itnim_drv);
524 }
525
526
527
528 /**
529  *  itnim_public FCS ITNIM public interfaces
530  */
531
532 /**
533  *      Called by rport when a new rport is created.
534  *
535  * @param[in] rport     -  remote port.
536  */
537 struct bfa_fcs_itnim_s *
538 bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport)
539 {
540         struct bfa_fcs_port_s *port = rport->port;
541         struct bfa_fcs_itnim_s *itnim;
542         struct bfad_itnim_s *itnim_drv;
543         struct bfa_itnim_s *bfa_itnim;
544
545         /*
546          * call bfad to allocate the itnim
547          */
548         bfa_fcb_itnim_alloc(port->fcs->bfad, &itnim, &itnim_drv);
549         if (itnim == NULL) {
550                 bfa_trc(port->fcs, rport->pwwn);
551                 return NULL;
552         }
553
554         /*
555          * Initialize itnim
556          */
557         itnim->rport = rport;
558         itnim->fcs = rport->fcs;
559         itnim->itnim_drv = itnim_drv;
560
561         /*
562          * call BFA to create the itnim
563          */
564         bfa_itnim = bfa_itnim_create(port->fcs->bfa, rport->bfa_rport, itnim);
565
566         if (bfa_itnim == NULL) {
567                 bfa_trc(port->fcs, rport->pwwn);
568                 bfa_fcb_itnim_free(port->fcs->bfad, itnim_drv);
569                 bfa_assert(0);
570                 return NULL;
571         }
572
573         itnim->bfa_itnim = bfa_itnim;
574         itnim->seq_rec = BFA_FALSE;
575         itnim->rec_support = BFA_FALSE;
576         itnim->conf_comp = BFA_FALSE;
577         itnim->task_retry_id = BFA_FALSE;
578
579         /*
580          * Set State machine
581          */
582         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
583
584         return itnim;
585 }
586
587 /**
588  *      Called by rport to delete  the instance of FCPIM.
589  *
590  * @param[in] rport     -  remote port.
591  */
592 void
593 bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim)
594 {
595         bfa_trc(itnim->fcs, itnim->rport->pid);
596         bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_DELETE);
597 }
598
599 /**
600  * Notification from rport that PLOGI is complete to initiate FC-4 session.
601  */
602 void
603 bfa_fcs_itnim_rport_online(struct bfa_fcs_itnim_s *itnim)
604 {
605         itnim->stats.onlines++;
606
607         if (!BFA_FCS_PID_IS_WKA(itnim->rport->pid)) {
608                 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_ONLINE);
609         } else {
610                 /*
611                  * For well known addresses, we set the itnim to initiator
612                  * state
613                  */
614                 itnim->stats.initiator++;
615                 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR);
616         }
617 }
618
619 /**
620  * Called by rport to handle a remote device offline.
621  */
622 void
623 bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim)
624 {
625         itnim->stats.offlines++;
626         bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_OFFLINE);
627 }
628
629 /**
630  * Called by rport when remote port is known to be an initiator from
631  * PRLI received.
632  */
633 void
634 bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim)
635 {
636         bfa_trc(itnim->fcs, itnim->rport->pid);
637         itnim->stats.initiator++;
638         bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR);
639 }
640
641 /**
642  * Called by rport to check if the itnim is online.
643  */
644 bfa_status_t
645 bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim)
646 {
647         bfa_trc(itnim->fcs, itnim->rport->pid);
648         switch (bfa_sm_to_state(itnim_sm_table, itnim->sm)) {
649         case BFA_ITNIM_ONLINE:
650         case BFA_ITNIM_INITIATIOR:
651                 return BFA_STATUS_OK;
652
653         default:
654                 return BFA_STATUS_NO_FCPIM_NEXUS;
655
656         }
657 }
658
659 /**
660  * BFA completion callback for bfa_itnim_online().
661  */
662 void
663 bfa_cb_itnim_online(void *cbarg)
664 {
665         struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cbarg;
666
667         bfa_trc(itnim->fcs, itnim->rport->pwwn);
668         bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_ONLINE);
669 }
670
671 /**
672  * BFA completion callback for bfa_itnim_offline().
673  */
674 void
675 bfa_cb_itnim_offline(void *cb_arg)
676 {
677         struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg;
678
679         bfa_trc(itnim->fcs, itnim->rport->pwwn);
680         bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_OFFLINE);
681 }
682
683 /**
684  * Mark the beginning of PATH TOV handling. IO completion callbacks
685  * are still pending.
686  */
687 void
688 bfa_cb_itnim_tov_begin(void *cb_arg)
689 {
690         struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg;
691
692         bfa_trc(itnim->fcs, itnim->rport->pwwn);
693         bfa_fcb_itnim_tov_begin(itnim->itnim_drv);
694 }
695
696 /**
697  * Mark the end of PATH TOV handling. All pending IOs are already cleaned up.
698  */
699 void
700 bfa_cb_itnim_tov(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_fcb_itnim_tov(itnim->itnim_drv);
706 }
707
708 /**
709  *              BFA notification to FCS/driver for second level error recovery.
710  *
711  * Atleast one I/O request has timedout and target is unresponsive to
712  * repeated abort requests. Second level error recovery should be initiated
713  * by starting implicit logout and recovery procedures.
714  */
715 void
716 bfa_cb_itnim_sler(void *cb_arg)
717 {
718         struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg;
719
720         itnim->stats.sler++;
721         bfa_trc(itnim->fcs, itnim->rport->pwwn);
722         bfa_fcs_rport_logo_imp(itnim->rport);
723 }
724
725 struct bfa_fcs_itnim_s *
726 bfa_fcs_itnim_lookup(struct bfa_fcs_port_s *port, wwn_t rpwwn)
727 {
728         struct bfa_fcs_rport_s *rport;
729         rport = bfa_fcs_rport_lookup(port, rpwwn);
730
731         if (!rport)
732                 return NULL;
733
734         bfa_assert(rport->itnim != NULL);
735         return (rport->itnim);
736 }
737
738 bfa_status_t
739 bfa_fcs_itnim_attr_get(struct bfa_fcs_port_s *port, wwn_t rpwwn,
740                        struct bfa_itnim_attr_s *attr)
741 {
742         struct bfa_fcs_itnim_s *itnim = NULL;
743
744         itnim = bfa_fcs_itnim_lookup(port, rpwwn);
745
746         if (itnim == NULL)
747                 return BFA_STATUS_NO_FCPIM_NEXUS;
748
749         attr->state = bfa_sm_to_state(itnim_sm_table, itnim->sm);
750         attr->retry = itnim->seq_rec;
751         attr->rec_support = itnim->rec_support;
752         attr->conf_comp = itnim->conf_comp;
753         attr->task_retry_id = itnim->task_retry_id;
754
755         return BFA_STATUS_OK;
756 }
757
758 bfa_status_t
759 bfa_fcs_itnim_stats_get(struct bfa_fcs_port_s *port, wwn_t rpwwn,
760                         struct bfa_itnim_stats_s *stats)
761 {
762         struct bfa_fcs_itnim_s *itnim = NULL;
763
764         bfa_assert(port != NULL);
765
766         itnim = bfa_fcs_itnim_lookup(port, rpwwn);
767
768         if (itnim == NULL)
769                 return BFA_STATUS_NO_FCPIM_NEXUS;
770
771         bfa_os_memcpy(stats, &itnim->stats, sizeof(struct bfa_itnim_stats_s));
772
773         return BFA_STATUS_OK;
774 }
775
776 bfa_status_t
777 bfa_fcs_itnim_stats_clear(struct bfa_fcs_port_s *port, wwn_t rpwwn)
778 {
779         struct bfa_fcs_itnim_s *itnim = NULL;
780
781         bfa_assert(port != NULL);
782
783         itnim = bfa_fcs_itnim_lookup(port, rpwwn);
784
785         if (itnim == NULL)
786                 return BFA_STATUS_NO_FCPIM_NEXUS;
787
788         bfa_os_memset(&itnim->stats, 0, sizeof(struct bfa_itnim_stats_s));
789         return BFA_STATUS_OK;
790 }
791
792 void
793 bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, struct fchs_s *fchs,
794                       u16 len)
795 {
796         struct fc_els_cmd_s   *els_cmd;
797
798         bfa_trc(itnim->fcs, fchs->type);
799
800         if (fchs->type != FC_TYPE_ELS)
801                 return;
802
803         els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
804
805         bfa_trc(itnim->fcs, els_cmd->els_code);
806
807         switch (els_cmd->els_code) {
808         case FC_ELS_PRLO:
809                 /* bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_PRLO); */
810                 break;
811
812         default:
813                 bfa_assert(0);
814         }
815 }
816
817 void
818 bfa_fcs_itnim_pause(struct bfa_fcs_itnim_s *itnim)
819 {
820 }
821
822 void
823 bfa_fcs_itnim_resume(struct bfa_fcs_itnim_s *itnim)
824 {
825 }
826
827 /**
828  *   Module initialization
829  */
830 void
831 bfa_fcs_fcpim_modinit(struct bfa_fcs_s *fcs)
832 {
833 }
834
835 /**
836  *   Module cleanup
837  */
838 void
839 bfa_fcs_fcpim_modexit(struct bfa_fcs_s *fcs)
840 {
841         bfa_fcs_modexit_comp(fcs);
842 }
843
844