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