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