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