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