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
  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 */
  93void
  94bfa_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 */
 110void
 111bfa_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 */
 124void
 125bfa_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 */
 148void
 149bfa_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 */
 165void
 166bfa_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 */
 209static void bfa_fcs_fabric_init(struct bfa_fcs_fabric_s *fabric);
 210static void bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric);
 211static void bfa_fcs_fabric_notify_online(struct bfa_fcs_fabric_s *fabric);
 212static void bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric);
 213static void bfa_fcs_fabric_delay(void *cbarg);
 214static void bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric);
 215static void bfa_fcs_fabric_delete_comp(void *cbarg);
 216static void bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric,
 217                                      struct fchs_s *fchs, u16 len);
 218static void bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric,
 219                                         struct fchs_s *fchs, u16 len);
 220static void bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric);
 221static 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);
 227static u8 bfa_fcs_fabric_oper_bbscn(struct bfa_fcs_fabric_s *fabric);
 228static bfa_boolean_t bfa_fcs_fabric_is_bbscn_enabled(
 229                                struct bfa_fcs_fabric_s *fabric);
 230
 231static void     bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric,
 232                                         enum bfa_fcs_fabric_event event);
 233static void     bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric,
 234                                          enum bfa_fcs_fabric_event event);
 235static void     bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric,
 236                                           enum bfa_fcs_fabric_event event);
 237static void     bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric,
 238                                        enum bfa_fcs_fabric_event event);
 239static void     bfa_fcs_fabric_sm_flogi_retry(struct bfa_fcs_fabric_s *fabric,
 240                                              enum bfa_fcs_fabric_event event);
 241static void     bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric,
 242                                       enum bfa_fcs_fabric_event event);
 243static void     bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric,
 244                                           enum bfa_fcs_fabric_event event);
 245static void     bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric,
 246                                       enum bfa_fcs_fabric_event event);
 247static void     bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric,
 248                                            enum bfa_fcs_fabric_event event);
 249static void     bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric,
 250                                           enum bfa_fcs_fabric_event event);
 251static 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 */
 256static void
 257bfa_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 */
 282static void
 283bfa_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 */
 316static void
 317bfa_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 */
 345static void
 346bfa_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
 408static void
 409bfa_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 */
 440static void
 441bfa_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 */
 480void
 481bfa_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 */
 506void
 507bfa_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 */
 532static void
 533bfa_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 */
 569void
 570bfa_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 */
 604static void
 605bfa_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 */
 628static void
 629bfa_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 */
 639static void
 640bfa_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 */
 660static void
 661bfa_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
 691static void
 692bfa_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 */
 704void
 705bfa_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 */
 765void
 766bfa_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 */
 848static void
 849bfa_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
 868static void
 869bfa_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
 890static void
 891bfa_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
 913static void
 914bfa_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 */
 924static u8
 925bfa_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 */
 941static bfa_boolean_t
 942bfa_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 */
 958static void
 959bfa_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
 973static void
 974bfa_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 */
 988void
 989bfa_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
1016void
1017bfa_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 */
1026void
1027bfa_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 */
1044void
1045bfa_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 */
1058void
1059bfa_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 */
1068void
1069bfa_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 */
1087void
1088bfa_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 */
1106void
1107bfa_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 */
1119struct bfa_fcs_vport_s *
1120bfa_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
1146u16
1147bfa_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 */
1163void
1164bfa_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 */
1229static void
1230bfa_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 */
1253static void
1254bfa_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
1287static void
1288bfa_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 */
1321static void
1322bfa_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 */
1335static void
1336bfa_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 */
1361void
1362bfa_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 */
1398bfa_fcs_vf_t   *
1399bfa_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 */
1417void
1418bfa_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 */
1450static void
1451bfa_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
1471void
1472bfa_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 */
1489static void
1490bfa_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
1544void
1545bfa_fcs_uf_attach(struct bfa_fcs_s *fcs)
1546{
1547        bfa_uf_recv_register(fcs->bfa, bfa_fcs_uf_recv, fcs);
1548}
1549