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