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