pandora: defconfig: update
[pandora-kernel.git] / drivers / scsi / bfa / bfa_fcs.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  *  bfa_fcs.c BFA FCS main
20  */
21
22 #include "bfad_drv.h"
23 #include "bfad_im.h"
24 #include "bfa_fcs.h"
25 #include "bfa_fcbuild.h"
26
27 BFA_TRC_FILE(FCS, FCS);
28
29 /*
30  * FCS sub-modules
31  */
32 struct bfa_fcs_mod_s {
33         void            (*attach) (struct bfa_fcs_s *fcs);
34         void            (*modinit) (struct bfa_fcs_s *fcs);
35         void            (*modexit) (struct bfa_fcs_s *fcs);
36 };
37
38 #define BFA_FCS_MODULE(_mod) { _mod ## _modinit, _mod ## _modexit }
39
40 static struct bfa_fcs_mod_s fcs_modules[] = {
41         { bfa_fcs_port_attach, NULL, NULL },
42         { bfa_fcs_uf_attach, NULL, NULL },
43         { bfa_fcs_fabric_attach, bfa_fcs_fabric_modinit,
44           bfa_fcs_fabric_modexit },
45 };
46
47 /*
48  *  fcs_api BFA FCS API
49  */
50
51 static void
52 bfa_fcs_exit_comp(void *fcs_cbarg)
53 {
54         struct bfa_fcs_s      *fcs = fcs_cbarg;
55         struct bfad_s         *bfad = fcs->bfad;
56
57         complete(&bfad->comp);
58 }
59
60
61
62 /*
63  *  fcs_api BFA FCS API
64  */
65
66 /*
67  * fcs attach -- called once to initialize data structures at driver attach time
68  */
69 void
70 bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad,
71                bfa_boolean_t min_cfg)
72 {
73         int             i;
74         struct bfa_fcs_mod_s  *mod;
75
76         fcs->bfa = bfa;
77         fcs->bfad = bfad;
78         fcs->min_cfg = min_cfg;
79
80         bfa->fcs = BFA_TRUE;
81         fcbuild_init();
82
83         for (i = 0; i < sizeof(fcs_modules) / sizeof(fcs_modules[0]); i++) {
84                 mod = &fcs_modules[i];
85                 if (mod->attach)
86                         mod->attach(fcs);
87         }
88 }
89
90 /*
91  * fcs initialization, called once after bfa initialization is complete
92  */
93 void
94 bfa_fcs_init(struct bfa_fcs_s *fcs)
95 {
96         int     i;
97         struct bfa_fcs_mod_s  *mod;
98
99         for (i = 0; i < sizeof(fcs_modules) / sizeof(fcs_modules[0]); i++) {
100                 mod = &fcs_modules[i];
101                 if (mod->modinit)
102                         mod->modinit(fcs);
103         }
104 }
105
106 /*
107  * FCS update cfg - reset the pwwn/nwwn of fabric base logical port
108  * with values learned during bfa_init firmware GETATTR REQ.
109  */
110 void
111 bfa_fcs_update_cfg(struct bfa_fcs_s *fcs)
112 {
113         struct bfa_fcs_fabric_s *fabric = &fcs->fabric;
114         struct bfa_lport_cfg_s *port_cfg = &fabric->bport.port_cfg;
115         struct bfa_ioc_s *ioc = &fabric->fcs->bfa->ioc;
116
117         port_cfg->nwwn = ioc->attr->nwwn;
118         port_cfg->pwwn = ioc->attr->pwwn;
119 }
120
121 /*
122  * fcs pbc vport initialization
123  */
124 void
125 bfa_fcs_pbc_vport_init(struct bfa_fcs_s *fcs)
126 {
127         int i, npbc_vports;
128         struct bfi_pbc_vport_s pbc_vports[BFI_PBC_MAX_VPORTS];
129
130         /* Initialize pbc vports */
131         if (!fcs->min_cfg) {
132                 npbc_vports =
133                         bfa_iocfc_get_pbc_vports(fcs->bfa, pbc_vports);
134                 for (i = 0; i < npbc_vports; i++)
135                         bfa_fcb_pbc_vport_create(fcs->bfa->bfad, pbc_vports[i]);
136         }
137 }
138
139 /*
140  *      brief
141  *              FCS driver details initialization.
142  *
143  *      param[in]               fcs             FCS instance
144  *      param[in]               driver_info     Driver Details
145  *
146  *      return None
147  */
148 void
149 bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs,
150                         struct bfa_fcs_driver_info_s *driver_info)
151 {
152
153         fcs->driver_info = *driver_info;
154
155         bfa_fcs_fabric_psymb_init(&fcs->fabric);
156 }
157
158 /*
159  *      brief
160  *              FCS instance cleanup and exit.
161  *
162  *      param[in]               fcs                     FCS instance
163  *      return None
164  */
165 void
166 bfa_fcs_exit(struct bfa_fcs_s *fcs)
167 {
168         struct bfa_fcs_mod_s  *mod;
169         int             nmods, i;
170
171         bfa_wc_init(&fcs->wc, bfa_fcs_exit_comp, fcs);
172
173         nmods = sizeof(fcs_modules) / sizeof(fcs_modules[0]);
174
175         for (i = 0; i < nmods; i++) {
176
177                 mod = &fcs_modules[i];
178                 if (mod->modexit) {
179                         bfa_wc_up(&fcs->wc);
180                         mod->modexit(fcs);
181                 }
182         }
183
184         bfa_wc_wait(&fcs->wc);
185 }
186
187
188 /*
189  * Fabric module implementation.
190  */
191
192 #define BFA_FCS_FABRIC_RETRY_DELAY      (2000)  /* Milliseconds */
193 #define BFA_FCS_FABRIC_CLEANUP_DELAY    (10000) /* Milliseconds */
194
195 #define bfa_fcs_fabric_set_opertype(__fabric) do {                      \
196         if (bfa_fcport_get_topology((__fabric)->fcs->bfa)               \
197                                 == BFA_PORT_TOPOLOGY_P2P) {             \
198                 if (fabric->fab_type == BFA_FCS_FABRIC_SWITCHED)        \
199                         (__fabric)->oper_type = BFA_PORT_TYPE_NPORT;    \
200                 else                                                    \
201                         (__fabric)->oper_type = BFA_PORT_TYPE_P2P;      \
202         } else                                                          \
203                 (__fabric)->oper_type = BFA_PORT_TYPE_NLPORT;           \
204 } while (0)
205
206 /*
207  * forward declarations
208  */
209 static void bfa_fcs_fabric_init(struct bfa_fcs_fabric_s *fabric);
210 static void bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric);
211 static void bfa_fcs_fabric_notify_online(struct bfa_fcs_fabric_s *fabric);
212 static void bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric);
213 static void bfa_fcs_fabric_delay(void *cbarg);
214 static void bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric);
215 static void bfa_fcs_fabric_delete_comp(void *cbarg);
216 static void bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric,
217                                       struct fchs_s *fchs, u16 len);
218 static void bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric,
219                                          struct fchs_s *fchs, u16 len);
220 static void bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric);
221 static void bfa_fcs_fabric_flogiacc_comp(void *fcsarg,
222                                          struct bfa_fcxp_s *fcxp, void *cbarg,
223                                          bfa_status_t status,
224                                          u32 rsp_len,
225                                          u32 resid_len,
226                                          struct fchs_s *rspfchs);
227 static u8 bfa_fcs_fabric_oper_bbscn(struct bfa_fcs_fabric_s *fabric);
228 static bfa_boolean_t bfa_fcs_fabric_is_bbscn_enabled(
229                                 struct bfa_fcs_fabric_s *fabric);
230
231 static void     bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric,
232                                          enum bfa_fcs_fabric_event event);
233 static void     bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric,
234                                           enum bfa_fcs_fabric_event event);
235 static void     bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric,
236                                            enum bfa_fcs_fabric_event event);
237 static void     bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric,
238                                         enum bfa_fcs_fabric_event event);
239 static void     bfa_fcs_fabric_sm_flogi_retry(struct bfa_fcs_fabric_s *fabric,
240                                               enum bfa_fcs_fabric_event event);
241 static void     bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric,
242                                        enum bfa_fcs_fabric_event event);
243 static void     bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric,
244                                            enum bfa_fcs_fabric_event event);
245 static void     bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric,
246                                        enum bfa_fcs_fabric_event event);
247 static void     bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric,
248                                             enum bfa_fcs_fabric_event event);
249 static void     bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric,
250                                            enum bfa_fcs_fabric_event event);
251 static void     bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric,
252                                            enum bfa_fcs_fabric_event event);
253 /*
254  *   Beginning state before fabric creation.
255  */
256 static void
257 bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric,
258                          enum bfa_fcs_fabric_event event)
259 {
260         bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
261         bfa_trc(fabric->fcs, event);
262
263         switch (event) {
264         case BFA_FCS_FABRIC_SM_CREATE:
265                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_created);
266                 bfa_fcs_fabric_init(fabric);
267                 bfa_fcs_lport_init(&fabric->bport, &fabric->bport.port_cfg);
268                 break;
269
270         case BFA_FCS_FABRIC_SM_LINK_UP:
271         case BFA_FCS_FABRIC_SM_LINK_DOWN:
272                 break;
273
274         default:
275                 bfa_sm_fault(fabric->fcs, event);
276         }
277 }
278
279 /*
280  *   Beginning state before fabric creation.
281  */
282 static void
283 bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric,
284                           enum bfa_fcs_fabric_event event)
285 {
286         bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
287         bfa_trc(fabric->fcs, event);
288
289         switch (event) {
290         case BFA_FCS_FABRIC_SM_START:
291                 if (bfa_fcport_is_linkup(fabric->fcs->bfa)) {
292                         bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi);
293                         bfa_fcs_fabric_login(fabric);
294                 } else
295                         bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
296                 break;
297
298         case BFA_FCS_FABRIC_SM_LINK_UP:
299         case BFA_FCS_FABRIC_SM_LINK_DOWN:
300                 break;
301
302         case BFA_FCS_FABRIC_SM_DELETE:
303                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
304                 bfa_fcs_fabric_delete(fabric);
305                 break;
306
307         default:
308                 bfa_sm_fault(fabric->fcs, event);
309         }
310 }
311
312 /*
313  *   Link is down, awaiting LINK UP event from port. This is also the
314  *   first state at fabric creation.
315  */
316 static void
317 bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric,
318                            enum bfa_fcs_fabric_event event)
319 {
320         bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
321         bfa_trc(fabric->fcs, event);
322
323         switch (event) {
324         case BFA_FCS_FABRIC_SM_LINK_UP:
325                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi);
326                 bfa_fcs_fabric_login(fabric);
327                 break;
328
329         case BFA_FCS_FABRIC_SM_RETRY_OP:
330                 break;
331
332         case BFA_FCS_FABRIC_SM_DELETE:
333                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
334                 bfa_fcs_fabric_delete(fabric);
335                 break;
336
337         default:
338                 bfa_sm_fault(fabric->fcs, event);
339         }
340 }
341
342 /*
343  *   FLOGI is in progress, awaiting FLOGI reply.
344  */
345 static void
346 bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric,
347                         enum bfa_fcs_fabric_event event)
348 {
349         bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
350         bfa_trc(fabric->fcs, event);
351
352         switch (event) {
353         case BFA_FCS_FABRIC_SM_CONT_OP:
354
355                 bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa,
356                                            fabric->bb_credit,
357                                            bfa_fcs_fabric_oper_bbscn(fabric));
358                 fabric->fab_type = BFA_FCS_FABRIC_SWITCHED;
359
360                 if (fabric->auth_reqd && fabric->is_auth) {
361                         bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth);
362                         bfa_trc(fabric->fcs, event);
363                 } else {
364                         bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_online);
365                         bfa_fcs_fabric_notify_online(fabric);
366                 }
367                 break;
368
369         case BFA_FCS_FABRIC_SM_RETRY_OP:
370                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi_retry);
371                 bfa_timer_start(fabric->fcs->bfa, &fabric->delay_timer,
372                                 bfa_fcs_fabric_delay, fabric,
373                                 BFA_FCS_FABRIC_RETRY_DELAY);
374                 break;
375
376         case BFA_FCS_FABRIC_SM_LOOPBACK:
377                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_loopback);
378                 bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
379                 bfa_fcs_fabric_set_opertype(fabric);
380                 break;
381
382         case BFA_FCS_FABRIC_SM_NO_FABRIC:
383                 fabric->fab_type = BFA_FCS_FABRIC_N2N;
384                 bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa,
385                                            fabric->bb_credit,
386                                            bfa_fcs_fabric_oper_bbscn(fabric));
387                 bfa_fcs_fabric_notify_online(fabric);
388                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_nofabric);
389                 break;
390
391         case BFA_FCS_FABRIC_SM_LINK_DOWN:
392                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
393                 bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
394                 break;
395
396         case BFA_FCS_FABRIC_SM_DELETE:
397                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
398                 bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
399                 bfa_fcs_fabric_delete(fabric);
400                 break;
401
402         default:
403                 bfa_sm_fault(fabric->fcs, event);
404         }
405 }
406
407
408 static void
409 bfa_fcs_fabric_sm_flogi_retry(struct bfa_fcs_fabric_s *fabric,
410                               enum bfa_fcs_fabric_event event)
411 {
412         bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
413         bfa_trc(fabric->fcs, event);
414
415         switch (event) {
416         case BFA_FCS_FABRIC_SM_DELAYED:
417                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi);
418                 bfa_fcs_fabric_login(fabric);
419                 break;
420
421         case BFA_FCS_FABRIC_SM_LINK_DOWN:
422                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
423                 bfa_timer_stop(&fabric->delay_timer);
424                 break;
425
426         case BFA_FCS_FABRIC_SM_DELETE:
427                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
428                 bfa_timer_stop(&fabric->delay_timer);
429                 bfa_fcs_fabric_delete(fabric);
430                 break;
431
432         default:
433                 bfa_sm_fault(fabric->fcs, event);
434         }
435 }
436
437 /*
438  *   Authentication is in progress, awaiting authentication results.
439  */
440 static void
441 bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric,
442                        enum bfa_fcs_fabric_event event)
443 {
444         bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
445         bfa_trc(fabric->fcs, event);
446
447         switch (event) {
448         case BFA_FCS_FABRIC_SM_AUTH_FAILED:
449                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed);
450                 bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
451                 break;
452
453         case BFA_FCS_FABRIC_SM_AUTH_SUCCESS:
454                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_online);
455                 bfa_fcs_fabric_notify_online(fabric);
456                 break;
457
458         case BFA_FCS_FABRIC_SM_PERF_EVFP:
459                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_evfp);
460                 break;
461
462         case BFA_FCS_FABRIC_SM_LINK_DOWN:
463                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
464                 bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
465                 break;
466
467         case BFA_FCS_FABRIC_SM_DELETE:
468                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
469                 bfa_fcs_fabric_delete(fabric);
470                 break;
471
472         default:
473                 bfa_sm_fault(fabric->fcs, event);
474         }
475 }
476
477 /*
478  *   Authentication failed
479  */
480 void
481 bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric,
482                               enum bfa_fcs_fabric_event event)
483 {
484         bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
485         bfa_trc(fabric->fcs, event);
486
487         switch (event) {
488         case BFA_FCS_FABRIC_SM_LINK_DOWN:
489                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
490                 bfa_fcs_fabric_notify_offline(fabric);
491                 break;
492
493         case BFA_FCS_FABRIC_SM_DELETE:
494                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
495                 bfa_fcs_fabric_delete(fabric);
496                 break;
497
498         default:
499                 bfa_sm_fault(fabric->fcs, event);
500         }
501 }
502
503 /*
504  *   Port is in loopback mode.
505  */
506 void
507 bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric,
508                            enum bfa_fcs_fabric_event event)
509 {
510         bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
511         bfa_trc(fabric->fcs, event);
512
513         switch (event) {
514         case BFA_FCS_FABRIC_SM_LINK_DOWN:
515                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
516                 bfa_fcs_fabric_notify_offline(fabric);
517                 break;
518
519         case BFA_FCS_FABRIC_SM_DELETE:
520                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
521                 bfa_fcs_fabric_delete(fabric);
522                 break;
523
524         default:
525                 bfa_sm_fault(fabric->fcs, event);
526         }
527 }
528
529 /*
530  *   There is no attached fabric - private loop or NPort-to-NPort topology.
531  */
532 static void
533 bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric,
534                            enum bfa_fcs_fabric_event event)
535 {
536         bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
537         bfa_trc(fabric->fcs, event);
538
539         switch (event) {
540         case BFA_FCS_FABRIC_SM_LINK_DOWN:
541                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
542                 bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
543                 bfa_fcs_fabric_notify_offline(fabric);
544                 break;
545
546         case BFA_FCS_FABRIC_SM_DELETE:
547                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
548                 bfa_fcs_fabric_delete(fabric);
549                 break;
550
551         case BFA_FCS_FABRIC_SM_NO_FABRIC:
552                 bfa_trc(fabric->fcs, fabric->bb_credit);
553                 bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa,
554                                            fabric->bb_credit,
555                                            bfa_fcs_fabric_oper_bbscn(fabric));
556                 break;
557
558         case BFA_FCS_FABRIC_SM_RETRY_OP:
559                 break;
560
561         default:
562                 bfa_sm_fault(fabric->fcs, event);
563         }
564 }
565
566 /*
567  *   Fabric is online - normal operating state.
568  */
569 void
570 bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric,
571                          enum bfa_fcs_fabric_event event)
572 {
573         bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
574         bfa_trc(fabric->fcs, event);
575
576         switch (event) {
577         case BFA_FCS_FABRIC_SM_LINK_DOWN:
578                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
579                 bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
580                 bfa_fcs_fabric_notify_offline(fabric);
581                 break;
582
583         case BFA_FCS_FABRIC_SM_DELETE:
584                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
585                 bfa_fcs_fabric_delete(fabric);
586                 break;
587
588         case BFA_FCS_FABRIC_SM_AUTH_FAILED:
589                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed);
590                 bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
591                 break;
592
593         case BFA_FCS_FABRIC_SM_AUTH_SUCCESS:
594                 break;
595
596         default:
597                 bfa_sm_fault(fabric->fcs, event);
598         }
599 }
600
601 /*
602  *   Exchanging virtual fabric parameters.
603  */
604 static void
605 bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric,
606                        enum bfa_fcs_fabric_event event)
607 {
608         bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
609         bfa_trc(fabric->fcs, event);
610
611         switch (event) {
612         case BFA_FCS_FABRIC_SM_CONT_OP:
613                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_evfp_done);
614                 break;
615
616         case BFA_FCS_FABRIC_SM_ISOLATE:
617                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_isolated);
618                 break;
619
620         default:
621                 bfa_sm_fault(fabric->fcs, event);
622         }
623 }
624
625 /*
626  *   EVFP exchange complete and VFT tagging is enabled.
627  */
628 static void
629 bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric,
630                             enum bfa_fcs_fabric_event event)
631 {
632         bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
633         bfa_trc(fabric->fcs, event);
634 }
635
636 /*
637  *   Port is isolated after EVFP exchange due to VF_ID mismatch (N and F).
638  */
639 static void
640 bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric,
641                            enum bfa_fcs_fabric_event event)
642 {
643         struct bfad_s *bfad = (struct bfad_s *)fabric->fcs->bfad;
644         char    pwwn_ptr[BFA_STRING_32];
645
646         bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
647         bfa_trc(fabric->fcs, event);
648         wwn2str(pwwn_ptr, fabric->bport.port_cfg.pwwn);
649
650         BFA_LOG(KERN_INFO, bfad, bfa_log_level,
651                 "Port is isolated due to VF_ID mismatch. "
652                 "PWWN: %s Port VF_ID: %04x switch port VF_ID: %04x.",
653                 pwwn_ptr, fabric->fcs->port_vfid,
654                 fabric->event_arg.swp_vfid);
655 }
656
657 /*
658  *   Fabric is being deleted, awaiting vport delete completions.
659  */
660 static void
661 bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric,
662                            enum bfa_fcs_fabric_event event)
663 {
664         bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
665         bfa_trc(fabric->fcs, event);
666
667         switch (event) {
668         case BFA_FCS_FABRIC_SM_DELCOMP:
669                 bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit);
670                 bfa_wc_down(&fabric->fcs->wc);
671                 break;
672
673         case BFA_FCS_FABRIC_SM_LINK_UP:
674                 break;
675
676         case BFA_FCS_FABRIC_SM_LINK_DOWN:
677                 bfa_fcs_fabric_notify_offline(fabric);
678                 break;
679
680         default:
681                 bfa_sm_fault(fabric->fcs, event);
682         }
683 }
684
685
686
687 /*
688  *  fcs_fabric_private fabric private functions
689  */
690
691 static void
692 bfa_fcs_fabric_init(struct bfa_fcs_fabric_s *fabric)
693 {
694         struct bfa_lport_cfg_s *port_cfg = &fabric->bport.port_cfg;
695
696         port_cfg->roles = BFA_LPORT_ROLE_FCP_IM;
697         port_cfg->nwwn = fabric->fcs->bfa->ioc.attr->nwwn;
698         port_cfg->pwwn = fabric->fcs->bfa->ioc.attr->pwwn;
699 }
700
701 /*
702  * Port Symbolic Name Creation for base port.
703  */
704 void
705 bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric)
706 {
707         struct bfa_lport_cfg_s *port_cfg = &fabric->bport.port_cfg;
708         char model[BFA_ADAPTER_MODEL_NAME_LEN] = {0};
709         struct bfa_fcs_driver_info_s *driver_info = &fabric->fcs->driver_info;
710
711         bfa_ioc_get_adapter_model(&fabric->fcs->bfa->ioc, model);
712
713         /* Model name/number */
714         strncpy((char *)&port_cfg->sym_name, model,
715                 BFA_FCS_PORT_SYMBNAME_MODEL_SZ);
716         strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
717                 sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
718
719         /* Driver Version */
720         strncat((char *)&port_cfg->sym_name, (char *)driver_info->version,
721                 BFA_FCS_PORT_SYMBNAME_VERSION_SZ);
722         strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
723                 sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
724
725         /* Host machine name */
726         strncat((char *)&port_cfg->sym_name,
727                 (char *)driver_info->host_machine_name,
728                 BFA_FCS_PORT_SYMBNAME_MACHINENAME_SZ);
729         strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
730                 sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
731
732         /*
733          * Host OS Info :
734          * If OS Patch Info is not there, do not truncate any bytes from the
735          * OS name string and instead copy the entire OS info string (64 bytes).
736          */
737         if (driver_info->host_os_patch[0] == '\0') {
738                 strncat((char *)&port_cfg->sym_name,
739                         (char *)driver_info->host_os_name,
740                         BFA_FCS_OS_STR_LEN);
741                 strncat((char *)&port_cfg->sym_name,
742                         BFA_FCS_PORT_SYMBNAME_SEPARATOR,
743                         sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
744         } else {
745                 strncat((char *)&port_cfg->sym_name,
746                         (char *)driver_info->host_os_name,
747                         BFA_FCS_PORT_SYMBNAME_OSINFO_SZ);
748                 strncat((char *)&port_cfg->sym_name,
749                         BFA_FCS_PORT_SYMBNAME_SEPARATOR,
750                         sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
751
752                 /* Append host OS Patch Info */
753                 strncat((char *)&port_cfg->sym_name,
754                         (char *)driver_info->host_os_patch,
755                         BFA_FCS_PORT_SYMBNAME_OSPATCH_SZ);
756         }
757
758         /* null terminate */
759         port_cfg->sym_name.symname[BFA_SYMNAME_MAXLEN - 1] = 0;
760 }
761
762 /*
763  * bfa lps login completion callback
764  */
765 void
766 bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status)
767 {
768         struct bfa_fcs_fabric_s *fabric = uarg;
769
770         bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
771         bfa_trc(fabric->fcs, status);
772
773         switch (status) {
774         case BFA_STATUS_OK:
775                 fabric->stats.flogi_accepts++;
776                 break;
777
778         case BFA_STATUS_INVALID_MAC:
779                 /* Only for CNA */
780                 fabric->stats.flogi_acc_err++;
781                 bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP);
782
783                 return;
784
785         case BFA_STATUS_EPROTOCOL:
786                 switch (fabric->lps->ext_status) {
787                 case BFA_EPROTO_BAD_ACCEPT:
788                         fabric->stats.flogi_acc_err++;
789                         break;
790
791                 case BFA_EPROTO_UNKNOWN_RSP:
792                         fabric->stats.flogi_unknown_rsp++;
793                         break;
794
795                 default:
796                         break;
797                 }
798                 bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP);
799
800                 return;
801
802         case BFA_STATUS_FABRIC_RJT:
803                 fabric->stats.flogi_rejects++;
804                 if (fabric->lps->lsrjt_rsn == FC_LS_RJT_RSN_LOGICAL_ERROR &&
805                     fabric->lps->lsrjt_expl == FC_LS_RJT_EXP_NO_ADDL_INFO)
806                         fabric->fcs->bbscn_flogi_rjt = BFA_TRUE;
807
808                 bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP);
809                 return;
810
811         default:
812                 fabric->stats.flogi_rsp_err++;
813                 bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP);
814                 return;
815         }
816
817         fabric->bb_credit = fabric->lps->pr_bbcred;
818         bfa_trc(fabric->fcs, fabric->bb_credit);
819
820         if (!(fabric->lps->brcd_switch))
821                 fabric->fabric_name =  fabric->lps->pr_nwwn;
822
823         /*
824          * Check port type. It should be 1 = F-port.
825          */
826         if (fabric->lps->fport) {
827                 fabric->bport.pid = fabric->lps->lp_pid;
828                 fabric->is_npiv = fabric->lps->npiv_en;
829                 fabric->is_auth = fabric->lps->auth_req;
830                 bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_CONT_OP);
831         } else {
832                 /*
833                  * Nport-2-Nport direct attached
834                  */
835                 fabric->bport.port_topo.pn2n.rem_port_wwn =
836                         fabric->lps->pr_pwwn;
837                 fabric->fab_type = BFA_FCS_FABRIC_N2N;
838                 bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_NO_FABRIC);
839         }
840
841         bfa_trc(fabric->fcs, fabric->bport.pid);
842         bfa_trc(fabric->fcs, fabric->is_npiv);
843         bfa_trc(fabric->fcs, fabric->is_auth);
844 }
845 /*
846  *              Allocate and send FLOGI.
847  */
848 static void
849 bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric)
850 {
851         struct bfa_s            *bfa = fabric->fcs->bfa;
852         struct bfa_lport_cfg_s  *pcfg = &fabric->bport.port_cfg;
853         u8                      alpa = 0, bb_scn = 0;
854
855         if (bfa_fcport_get_topology(bfa) == BFA_PORT_TOPOLOGY_LOOP)
856                 alpa = bfa_fcport_get_myalpa(bfa);
857
858         if (bfa_fcs_fabric_is_bbscn_enabled(fabric) &&
859             (!fabric->fcs->bbscn_flogi_rjt))
860                 bb_scn = BFA_FCS_PORT_DEF_BB_SCN;
861
862         bfa_lps_flogi(fabric->lps, fabric, alpa, bfa_fcport_get_maxfrsize(bfa),
863                       pcfg->pwwn, pcfg->nwwn, fabric->auth_reqd, bb_scn);
864
865         fabric->stats.flogi_sent++;
866 }
867
868 static void
869 bfa_fcs_fabric_notify_online(struct bfa_fcs_fabric_s *fabric)
870 {
871         struct bfa_fcs_vport_s *vport;
872         struct list_head              *qe, *qen;
873
874         bfa_trc(fabric->fcs, fabric->fabric_name);
875
876         bfa_fcs_fabric_set_opertype(fabric);
877         fabric->stats.fabric_onlines++;
878
879         /*
880          * notify online event to base and then virtual ports
881          */
882         bfa_fcs_lport_online(&fabric->bport);
883
884         list_for_each_safe(qe, qen, &fabric->vport_q) {
885                 vport = (struct bfa_fcs_vport_s *) qe;
886                 bfa_fcs_vport_online(vport);
887         }
888 }
889
890 static void
891 bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric)
892 {
893         struct bfa_fcs_vport_s *vport;
894         struct list_head              *qe, *qen;
895
896         bfa_trc(fabric->fcs, fabric->fabric_name);
897         fabric->stats.fabric_offlines++;
898
899         /*
900          * notify offline event first to vports and then base port.
901          */
902         list_for_each_safe(qe, qen, &fabric->vport_q) {
903                 vport = (struct bfa_fcs_vport_s *) qe;
904                 bfa_fcs_vport_offline(vport);
905         }
906
907         bfa_fcs_lport_offline(&fabric->bport);
908
909         fabric->fabric_name = 0;
910         fabric->fabric_ip_addr[0] = 0;
911 }
912
913 static void
914 bfa_fcs_fabric_delay(void *cbarg)
915 {
916         struct bfa_fcs_fabric_s *fabric = cbarg;
917
918         bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELAYED);
919 }
920
921 /*
922  * Computes operating BB_SCN value
923  */
924 static u8
925 bfa_fcs_fabric_oper_bbscn(struct bfa_fcs_fabric_s *fabric)
926 {
927         u8      pr_bbscn = fabric->lps->pr_bbscn;
928         struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(fabric->fcs->bfa);
929
930         if (!(fcport->cfg.bb_scn_state && pr_bbscn))
931                 return 0;
932
933         /* return max of local/remote bb_scn values */
934         return ((pr_bbscn > BFA_FCS_PORT_DEF_BB_SCN) ?
935                 pr_bbscn : BFA_FCS_PORT_DEF_BB_SCN);
936 }
937
938 /*
939  * Check if BB_SCN can be enabled.
940  */
941 static bfa_boolean_t
942 bfa_fcs_fabric_is_bbscn_enabled(struct bfa_fcs_fabric_s *fabric)
943 {
944         struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(fabric->fcs->bfa);
945
946         if (bfa_ioc_get_fcmode(&fabric->fcs->bfa->ioc) &&
947                         fcport->cfg.bb_scn_state &&
948                         !bfa_fcport_is_qos_enabled(fabric->fcs->bfa) &&
949                         !bfa_fcport_is_trunk_enabled(fabric->fcs->bfa))
950                 return BFA_TRUE;
951         else
952                 return BFA_FALSE;
953 }
954
955 /*
956  * Delete all vports and wait for vport delete completions.
957  */
958 static void
959 bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric)
960 {
961         struct bfa_fcs_vport_s *vport;
962         struct list_head              *qe, *qen;
963
964         list_for_each_safe(qe, qen, &fabric->vport_q) {
965                 vport = (struct bfa_fcs_vport_s *) qe;
966                 bfa_fcs_vport_fcs_delete(vport);
967         }
968
969         bfa_fcs_lport_delete(&fabric->bport);
970         bfa_wc_wait(&fabric->wc);
971 }
972
973 static void
974 bfa_fcs_fabric_delete_comp(void *cbarg)
975 {
976         struct bfa_fcs_fabric_s *fabric = cbarg;
977
978         bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELCOMP);
979 }
980
981 /*
982  *  fcs_fabric_public fabric public functions
983  */
984
985 /*
986  * Attach time initialization.
987  */
988 void
989 bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs)
990 {
991         struct bfa_fcs_fabric_s *fabric;
992
993         fabric = &fcs->fabric;
994         memset(fabric, 0, sizeof(struct bfa_fcs_fabric_s));
995
996         /*
997          * Initialize base fabric.
998          */
999         fabric->fcs = fcs;
1000         INIT_LIST_HEAD(&fabric->vport_q);
1001         INIT_LIST_HEAD(&fabric->vf_q);
1002         fabric->lps = bfa_lps_alloc(fcs->bfa);
1003         WARN_ON(!fabric->lps);
1004
1005         /*
1006          * Initialize fabric delete completion handler. Fabric deletion is
1007          * complete when the last vport delete is complete.
1008          */
1009         bfa_wc_init(&fabric->wc, bfa_fcs_fabric_delete_comp, fabric);
1010         bfa_wc_up(&fabric->wc); /* For the base port */
1011
1012         bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit);
1013         bfa_fcs_lport_attach(&fabric->bport, fabric->fcs, FC_VF_ID_NULL, NULL);
1014 }
1015
1016 void
1017 bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs)
1018 {
1019         bfa_sm_send_event(&fcs->fabric, BFA_FCS_FABRIC_SM_CREATE);
1020         bfa_trc(fcs, 0);
1021 }
1022
1023 /*
1024  *   Module cleanup
1025  */
1026 void
1027 bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs)
1028 {
1029         struct bfa_fcs_fabric_s *fabric;
1030
1031         bfa_trc(fcs, 0);
1032
1033         /*
1034          * Cleanup base fabric.
1035          */
1036         fabric = &fcs->fabric;
1037         bfa_lps_delete(fabric->lps);
1038         bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELETE);
1039 }
1040
1041 /*
1042  * Fabric module start -- kick starts FCS actions
1043  */
1044 void
1045 bfa_fcs_fabric_modstart(struct bfa_fcs_s *fcs)
1046 {
1047         struct bfa_fcs_fabric_s *fabric;
1048
1049         bfa_trc(fcs, 0);
1050         fabric = &fcs->fabric;
1051         bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_START);
1052 }
1053
1054
1055 /*
1056  *   Link up notification from BFA physical port module.
1057  */
1058 void
1059 bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric)
1060 {
1061         bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
1062         bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_UP);
1063 }
1064
1065 /*
1066  *   Link down notification from BFA physical port module.
1067  */
1068 void
1069 bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric)
1070 {
1071         bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
1072         fabric->fcs->bbscn_flogi_rjt = BFA_FALSE;
1073         bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_DOWN);
1074 }
1075
1076 /*
1077  *   A child vport is being created in the fabric.
1078  *
1079  *   Call from vport module at vport creation. A list of base port and vports
1080  *   belonging to a fabric is maintained to propagate link events.
1081  *
1082  *   param[in] fabric - Fabric instance. This can be a base fabric or vf.
1083  *   param[in] vport  - Vport being created.
1084  *
1085  *   @return None (always succeeds)
1086  */
1087 void
1088 bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric,
1089                         struct bfa_fcs_vport_s *vport)
1090 {
1091         /*
1092          * - add vport to fabric's vport_q
1093          */
1094         bfa_trc(fabric->fcs, fabric->vf_id);
1095
1096         list_add_tail(&vport->qe, &fabric->vport_q);
1097         fabric->num_vports++;
1098         bfa_wc_up(&fabric->wc);
1099 }
1100
1101 /*
1102  *   A child vport is being deleted from fabric.
1103  *
1104  *   Vport is being deleted.
1105  */
1106 void
1107 bfa_fcs_fabric_delvport(struct bfa_fcs_fabric_s *fabric,
1108                         struct bfa_fcs_vport_s *vport)
1109 {
1110         list_del(&vport->qe);
1111         fabric->num_vports--;
1112         bfa_wc_down(&fabric->wc);
1113 }
1114
1115
1116 /*
1117  * Lookup for a vport within a fabric given its pwwn
1118  */
1119 struct bfa_fcs_vport_s *
1120 bfa_fcs_fabric_vport_lookup(struct bfa_fcs_fabric_s *fabric, wwn_t pwwn)
1121 {
1122         struct bfa_fcs_vport_s *vport;
1123         struct list_head              *qe;
1124
1125         list_for_each(qe, &fabric->vport_q) {
1126                 vport = (struct bfa_fcs_vport_s *) qe;
1127                 if (bfa_fcs_lport_get_pwwn(&vport->lport) == pwwn)
1128                         return vport;
1129         }
1130
1131         return NULL;
1132 }
1133
1134
1135 /*
1136  *  Get OUI of the attached switch.
1137  *
1138  *  Note : Use of this function should be avoided as much as possible.
1139  *         This function should be used only if there is any requirement
1140 *          to check for FOS version below 6.3.
1141  *         To check if the attached fabric is a brocade fabric, use
1142  *         bfa_lps_is_brcd_fabric() which works for FOS versions 6.3
1143  *         or above only.
1144  */
1145
1146 u16
1147 bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric)
1148 {
1149         wwn_t fab_nwwn;
1150         u8 *tmp;
1151         u16 oui;
1152
1153         fab_nwwn = fabric->lps->pr_nwwn;
1154
1155         tmp = (u8 *)&fab_nwwn;
1156         oui = (tmp[3] << 8) | tmp[4];
1157
1158         return oui;
1159 }
1160 /*
1161  *              Unsolicited frame receive handling.
1162  */
1163 void
1164 bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs,
1165                        u16 len)
1166 {
1167         u32     pid = fchs->d_id;
1168         struct bfa_fcs_vport_s *vport;
1169         struct list_head              *qe;
1170         struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
1171         struct fc_logi_s *flogi = (struct fc_logi_s *) els_cmd;
1172
1173         bfa_trc(fabric->fcs, len);
1174         bfa_trc(fabric->fcs, pid);
1175
1176         /*
1177          * Look for our own FLOGI frames being looped back. This means an
1178          * external loopback cable is in place. Our own FLOGI frames are
1179          * sometimes looped back when switch port gets temporarily bypassed.
1180          */
1181         if ((pid == bfa_ntoh3b(FC_FABRIC_PORT)) &&
1182             (els_cmd->els_code == FC_ELS_FLOGI) &&
1183             (flogi->port_name == bfa_fcs_lport_get_pwwn(&fabric->bport))) {
1184                 bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LOOPBACK);
1185                 return;
1186         }
1187
1188         /*
1189          * FLOGI/EVFP exchanges should be consumed by base fabric.
1190          */
1191         if (fchs->d_id == bfa_hton3b(FC_FABRIC_PORT)) {
1192                 bfa_trc(fabric->fcs, pid);
1193                 bfa_fcs_fabric_process_uf(fabric, fchs, len);
1194                 return;
1195         }
1196
1197         if (fabric->bport.pid == pid) {
1198                 /*
1199                  * All authentication frames should be routed to auth
1200                  */
1201                 bfa_trc(fabric->fcs, els_cmd->els_code);
1202                 if (els_cmd->els_code == FC_ELS_AUTH) {
1203                         bfa_trc(fabric->fcs, els_cmd->els_code);
1204                         return;
1205                 }
1206
1207                 bfa_trc(fabric->fcs, *(u8 *) ((u8 *) fchs));
1208                 bfa_fcs_lport_uf_recv(&fabric->bport, fchs, len);
1209                 return;
1210         }
1211
1212         /*
1213          * look for a matching local port ID
1214          */
1215         list_for_each(qe, &fabric->vport_q) {
1216                 vport = (struct bfa_fcs_vport_s *) qe;
1217                 if (vport->lport.pid == pid) {
1218                         bfa_fcs_lport_uf_recv(&vport->lport, fchs, len);
1219                         return;
1220                 }
1221         }
1222         bfa_trc(fabric->fcs, els_cmd->els_code);
1223         bfa_fcs_lport_uf_recv(&fabric->bport, fchs, len);
1224 }
1225
1226 /*
1227  *              Unsolicited frames to be processed by fabric.
1228  */
1229 static void
1230 bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs,
1231                           u16 len)
1232 {
1233         struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
1234
1235         bfa_trc(fabric->fcs, els_cmd->els_code);
1236
1237         switch (els_cmd->els_code) {
1238         case FC_ELS_FLOGI:
1239                 bfa_fcs_fabric_process_flogi(fabric, fchs, len);
1240                 break;
1241
1242         default:
1243                 /*
1244                  * need to generate a LS_RJT
1245                  */
1246                 break;
1247         }
1248 }
1249
1250 /*
1251  *      Process incoming FLOGI
1252  */
1253 static void
1254 bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric,
1255                         struct fchs_s *fchs, u16 len)
1256 {
1257         struct fc_logi_s *flogi = (struct fc_logi_s *) (fchs + 1);
1258         struct bfa_fcs_lport_s *bport = &fabric->bport;
1259
1260         bfa_trc(fabric->fcs, fchs->s_id);
1261
1262         fabric->stats.flogi_rcvd++;
1263         /*
1264          * Check port type. It should be 0 = n-port.
1265          */
1266         if (flogi->csp.port_type) {
1267                 /*
1268                  * @todo: may need to send a LS_RJT
1269                  */
1270                 bfa_trc(fabric->fcs, flogi->port_name);
1271                 fabric->stats.flogi_rejected++;
1272                 return;
1273         }
1274
1275         fabric->bb_credit = be16_to_cpu(flogi->csp.bbcred);
1276         fabric->lps->pr_bbscn = (be16_to_cpu(flogi->csp.rxsz) >> 12);
1277         bport->port_topo.pn2n.rem_port_wwn = flogi->port_name;
1278         bport->port_topo.pn2n.reply_oxid = fchs->ox_id;
1279
1280         /*
1281          * Send a Flogi Acc
1282          */
1283         bfa_fcs_fabric_send_flogi_acc(fabric);
1284         bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_NO_FABRIC);
1285 }
1286
1287 static void
1288 bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric)
1289 {
1290         struct bfa_lport_cfg_s *pcfg = &fabric->bport.port_cfg;
1291         struct bfa_fcs_lport_n2n_s *n2n_port = &fabric->bport.port_topo.pn2n;
1292         struct bfa_s      *bfa = fabric->fcs->bfa;
1293         struct bfa_fcxp_s *fcxp;
1294         u16     reqlen;
1295         struct fchs_s   fchs;
1296
1297         fcxp = bfa_fcs_fcxp_alloc(fabric->fcs);
1298         /*
1299          * Do not expect this failure -- expect remote node to retry
1300          */
1301         if (!fcxp)
1302                 return;
1303
1304         reqlen = fc_flogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
1305                                     bfa_hton3b(FC_FABRIC_PORT),
1306                                     n2n_port->reply_oxid, pcfg->pwwn,
1307                                     pcfg->nwwn,
1308                                     bfa_fcport_get_maxfrsize(bfa),
1309                                     bfa_fcport_get_rx_bbcredit(bfa),
1310                                     bfa_fcs_fabric_oper_bbscn(fabric));
1311
1312         bfa_fcxp_send(fcxp, NULL, fabric->vf_id, fabric->lps->bfa_tag,
1313                       BFA_FALSE, FC_CLASS_3,
1314                       reqlen, &fchs, bfa_fcs_fabric_flogiacc_comp, fabric,
1315                       FC_MAX_PDUSZ, 0);
1316 }
1317
1318 /*
1319  *   Flogi Acc completion callback.
1320  */
1321 static void
1322 bfa_fcs_fabric_flogiacc_comp(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
1323                              bfa_status_t status, u32 rsp_len,
1324                              u32 resid_len, struct fchs_s *rspfchs)
1325 {
1326         struct bfa_fcs_fabric_s *fabric = cbarg;
1327
1328         bfa_trc(fabric->fcs, status);
1329 }
1330
1331
1332 /*
1333  * Send AEN notification
1334  */
1335 static void
1336 bfa_fcs_fabric_aen_post(struct bfa_fcs_lport_s *port,
1337                         enum bfa_port_aen_event event)
1338 {
1339         struct bfad_s *bfad = (struct bfad_s *)port->fabric->fcs->bfad;
1340         struct bfa_aen_entry_s  *aen_entry;
1341
1342         bfad_get_aen_entry(bfad, aen_entry);
1343         if (!aen_entry)
1344                 return;
1345
1346         aen_entry->aen_data.port.pwwn = bfa_fcs_lport_get_pwwn(port);
1347         aen_entry->aen_data.port.fwwn = bfa_fcs_lport_get_fabric_name(port);
1348
1349         /* Send the AEN notification */
1350         bfad_im_post_vendor_event(aen_entry, bfad, ++port->fcs->fcs_aen_seq,
1351                                   BFA_AEN_CAT_PORT, event);
1352 }
1353
1354 /*
1355  *
1356  * @param[in] fabric - fabric
1357  * @param[in] wwn_t - new fabric name
1358  *
1359  * @return - none
1360  */
1361 void
1362 bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric,
1363                                wwn_t fabric_name)
1364 {
1365         struct bfad_s *bfad = (struct bfad_s *)fabric->fcs->bfad;
1366         char    pwwn_ptr[BFA_STRING_32];
1367         char    fwwn_ptr[BFA_STRING_32];
1368
1369         bfa_trc(fabric->fcs, fabric_name);
1370
1371         if (fabric->fabric_name == 0) {
1372                 /*
1373                  * With BRCD switches, we don't get Fabric Name in FLOGI.
1374                  * Don't generate a fabric name change event in this case.
1375                  */
1376                 fabric->fabric_name = fabric_name;
1377         } else {
1378                 fabric->fabric_name = fabric_name;
1379                 wwn2str(pwwn_ptr, bfa_fcs_lport_get_pwwn(&fabric->bport));
1380                 wwn2str(fwwn_ptr,
1381                         bfa_fcs_lport_get_fabric_name(&fabric->bport));
1382                 BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
1383                         "Base port WWN = %s Fabric WWN = %s\n",
1384                         pwwn_ptr, fwwn_ptr);
1385                 bfa_fcs_fabric_aen_post(&fabric->bport,
1386                                 BFA_PORT_AEN_FABRIC_NAME_CHANGE);
1387         }
1388 }
1389
1390 /*
1391  *      Returns FCS vf structure for a given vf_id.
1392  *
1393  *      param[in]       vf_id - VF_ID
1394  *
1395  *      return
1396  *      If lookup succeeds, retuns fcs vf object, otherwise returns NULL
1397  */
1398 bfa_fcs_vf_t   *
1399 bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id)
1400 {
1401         bfa_trc(fcs, vf_id);
1402         if (vf_id == FC_VF_ID_NULL)
1403                 return &fcs->fabric;
1404
1405         return NULL;
1406 }
1407
1408 /*
1409  *      Return the list of local logical ports present in the given VF.
1410  *
1411  *      @param[in]      vf      vf for which logical ports are returned
1412  *      @param[out]     lpwwn   returned logical port wwn list
1413  *      @param[in,out]  nlports in:size of lpwwn list;
1414  *                              out:total elements present,
1415  *                              actual elements returned is limited by the size
1416  */
1417 void
1418 bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t lpwwn[], int *nlports)
1419 {
1420         struct list_head *qe;
1421         struct bfa_fcs_vport_s *vport;
1422         int     i = 0;
1423         struct bfa_fcs_s        *fcs;
1424
1425         if (vf == NULL || lpwwn == NULL || *nlports == 0)
1426                 return;
1427
1428         fcs = vf->fcs;
1429
1430         bfa_trc(fcs, vf->vf_id);
1431         bfa_trc(fcs, (uint32_t) *nlports);
1432
1433         lpwwn[i++] = vf->bport.port_cfg.pwwn;
1434
1435         list_for_each(qe, &vf->vport_q) {
1436                 if (i >= *nlports)
1437                         break;
1438
1439                 vport = (struct bfa_fcs_vport_s *) qe;
1440                 lpwwn[i++] = vport->lport.port_cfg.pwwn;
1441         }
1442
1443         bfa_trc(fcs, i);
1444         *nlports = i;
1445 }
1446
1447 /*
1448  * BFA FCS PPORT ( physical port)
1449  */
1450 static void
1451 bfa_fcs_port_event_handler(void *cbarg, enum bfa_port_linkstate event)
1452 {
1453         struct bfa_fcs_s      *fcs = cbarg;
1454
1455         bfa_trc(fcs, event);
1456
1457         switch (event) {
1458         case BFA_PORT_LINKUP:
1459                 bfa_fcs_fabric_link_up(&fcs->fabric);
1460                 break;
1461
1462         case BFA_PORT_LINKDOWN:
1463                 bfa_fcs_fabric_link_down(&fcs->fabric);
1464                 break;
1465
1466         default:
1467                 WARN_ON(1);
1468         }
1469 }
1470
1471 void
1472 bfa_fcs_port_attach(struct bfa_fcs_s *fcs)
1473 {
1474         bfa_fcport_event_register(fcs->bfa, bfa_fcs_port_event_handler, fcs);
1475 }
1476
1477 /*
1478  * BFA FCS UF ( Unsolicited Frames)
1479  */
1480
1481 /*
1482  *              BFA callback for unsolicited frame receive handler.
1483  *
1484  * @param[in]           cbarg           callback arg for receive handler
1485  * @param[in]           uf              unsolicited frame descriptor
1486  *
1487  * @return None
1488  */
1489 static void
1490 bfa_fcs_uf_recv(void *cbarg, struct bfa_uf_s *uf)
1491 {
1492         struct bfa_fcs_s        *fcs = (struct bfa_fcs_s *) cbarg;
1493         struct fchs_s   *fchs = bfa_uf_get_frmbuf(uf);
1494         u16     len = bfa_uf_get_frmlen(uf);
1495         struct fc_vft_s *vft;
1496         struct bfa_fcs_fabric_s *fabric;
1497
1498         /*
1499          * check for VFT header
1500          */
1501         if (fchs->routing == FC_RTG_EXT_HDR &&
1502             fchs->cat_info == FC_CAT_VFT_HDR) {
1503                 bfa_stats(fcs, uf.tagged);
1504                 vft = bfa_uf_get_frmbuf(uf);
1505                 if (fcs->port_vfid == vft->vf_id)
1506                         fabric = &fcs->fabric;
1507                 else
1508                         fabric = bfa_fcs_vf_lookup(fcs, (u16) vft->vf_id);
1509
1510                 /*
1511                  * drop frame if vfid is unknown
1512                  */
1513                 if (!fabric) {
1514                         WARN_ON(1);
1515                         bfa_stats(fcs, uf.vfid_unknown);
1516                         bfa_uf_free(uf);
1517                         return;
1518                 }
1519
1520                 /*
1521                  * skip vft header
1522                  */
1523                 fchs = (struct fchs_s *) (vft + 1);
1524                 len -= sizeof(struct fc_vft_s);
1525
1526                 bfa_trc(fcs, vft->vf_id);
1527         } else {
1528                 bfa_stats(fcs, uf.untagged);
1529                 fabric = &fcs->fabric;
1530         }
1531
1532         bfa_trc(fcs, ((u32 *) fchs)[0]);
1533         bfa_trc(fcs, ((u32 *) fchs)[1]);
1534         bfa_trc(fcs, ((u32 *) fchs)[2]);
1535         bfa_trc(fcs, ((u32 *) fchs)[3]);
1536         bfa_trc(fcs, ((u32 *) fchs)[4]);
1537         bfa_trc(fcs, ((u32 *) fchs)[5]);
1538         bfa_trc(fcs, len);
1539
1540         bfa_fcs_fabric_uf_recv(fabric, fchs, len);
1541         bfa_uf_free(uf);
1542 }
1543
1544 void
1545 bfa_fcs_uf_attach(struct bfa_fcs_s *fcs)
1546 {
1547         bfa_uf_recv_register(fcs->bfa, bfa_fcs_uf_recv, fcs);
1548 }