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
 592        /*
 593         * call bfad to allocate the itnim
 594         */
 595        bfa_fcb_itnim_alloc(port->fcs->bfad, &itnim, &itnim_drv);
 596        if (itnim == NULL) {
 597                bfa_trc(port->fcs, rport->pwwn);
 598                return NULL;
 599        }
 600
 601        /*
 602         * Initialize itnim
 603         */
 604        itnim->rport = rport;
 605        itnim->fcs = rport->fcs;
 606        itnim->itnim_drv = itnim_drv;
 607
 608        itnim->bfa_itnim     = NULL;
 609        itnim->seq_rec       = BFA_FALSE;
 610        itnim->rec_support   = BFA_FALSE;
 611        itnim->conf_comp     = BFA_FALSE;
 612        itnim->task_retry_id = BFA_FALSE;
 613
 614        /*
 615         * Set State machine
 616         */
 617        bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
 618
 619        return itnim;
 620}
 621
 622/*
 623 *      Called by rport to delete  the instance of FCPIM.
 624 *
 625 * @param[in] rport     -  remote port.
 626 */
 627void
 628bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim)
 629{
 630        bfa_trc(itnim->fcs, itnim->rport->pid);
 631        bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_DELETE);
 632}
 633
 634/*
 635 * Notification from rport that PLOGI is complete to initiate FC-4 session.
 636 */
 637void
 638bfa_fcs_itnim_brp_online(struct bfa_fcs_itnim_s *itnim)
 639{
 640        itnim->stats.onlines++;
 641
 642        if (!BFA_FCS_PID_IS_WKA(itnim->rport->pid))
 643                bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HAL_ONLINE);
 644}
 645
 646/*
 647 * Called by rport to handle a remote device offline.
 648 */
 649void
 650bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim)
 651{
 652        itnim->stats.offlines++;
 653        bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_OFFLINE);
 654}
 655
 656/*
 657 * Called by rport when remote port is known to be an initiator from
 658 * PRLI received.
 659 */
 660void
 661bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim)
 662{
 663        bfa_trc(itnim->fcs, itnim->rport->pid);
 664        itnim->stats.initiator++;
 665        bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR);
 666}
 667
 668/*
 669 * Called by rport to check if the itnim is online.
 670 */
 671bfa_status_t
 672bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim)
 673{
 674        bfa_trc(itnim->fcs, itnim->rport->pid);
 675        switch (bfa_sm_to_state(itnim_sm_table, itnim->sm)) {
 676        case BFA_ITNIM_ONLINE:
 677        case BFA_ITNIM_INITIATIOR:
 678                return BFA_STATUS_OK;
 679
 680        default:
 681                return BFA_STATUS_NO_FCPIM_NEXUS;
 682        }
 683}
 684
 685/*
 686 * BFA completion callback for bfa_itnim_online().
 687 */
 688void
 689bfa_cb_itnim_online(void *cbarg)
 690{
 691        struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cbarg;
 692
 693        bfa_trc(itnim->fcs, itnim->rport->pwwn);
 694        bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_ONLINE);
 695}
 696
 697/*
 698 * BFA completion callback for bfa_itnim_offline().
 699 */
 700void
 701bfa_cb_itnim_offline(void *cb_arg)
 702{
 703        struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
 704
 705        bfa_trc(itnim->fcs, itnim->rport->pwwn);
 706        bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_OFFLINE);
 707}
 708
 709/*
 710 * Mark the beginning of PATH TOV handling. IO completion callbacks
 711 * are still pending.
 712 */
 713void
 714bfa_cb_itnim_tov_begin(void *cb_arg)
 715{
 716        struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
 717
 718        bfa_trc(itnim->fcs, itnim->rport->pwwn);
 719}
 720
 721/*
 722 * Mark the end of PATH TOV handling. All pending IOs are already cleaned up.
 723 */
 724void
 725bfa_cb_itnim_tov(void *cb_arg)
 726{
 727        struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
 728        struct bfad_itnim_s *itnim_drv = itnim->itnim_drv;
 729
 730        bfa_trc(itnim->fcs, itnim->rport->pwwn);
 731        itnim_drv->state = ITNIM_STATE_TIMEOUT;
 732}
 733
 734/*
 735 *              BFA notification to FCS/driver for second level error recovery.
 736 *
 737 * Atleast one I/O request has timedout and target is unresponsive to
 738 * repeated abort requests. Second level error recovery should be initiated
 739 * by starting implicit logout and recovery procedures.
 740 */
 741void
 742bfa_cb_itnim_sler(void *cb_arg)
 743{
 744        struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
 745
 746        itnim->stats.sler++;
 747        bfa_trc(itnim->fcs, itnim->rport->pwwn);
 748        bfa_sm_send_event(itnim->rport, RPSM_EVENT_LOGO_IMP);
 749}
 750
 751struct bfa_fcs_itnim_s *
 752bfa_fcs_itnim_lookup(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
 753{
 754        struct bfa_fcs_rport_s *rport;
 755        rport = bfa_fcs_rport_lookup(port, rpwwn);
 756
 757        if (!rport)
 758                return NULL;
 759
 760        WARN_ON(rport->itnim == NULL);
 761        return rport->itnim;
 762}
 763
 764bfa_status_t
 765bfa_fcs_itnim_attr_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn,
 766                       struct bfa_itnim_attr_s *attr)
 767{
 768        struct bfa_fcs_itnim_s *itnim = NULL;
 769
 770        itnim = bfa_fcs_itnim_lookup(port, rpwwn);
 771
 772        if (itnim == NULL)
 773                return BFA_STATUS_NO_FCPIM_NEXUS;
 774
 775        attr->state         = bfa_sm_to_state(itnim_sm_table, itnim->sm);
 776        attr->retry         = itnim->seq_rec;
 777        attr->rec_support   = itnim->rec_support;
 778        attr->conf_comp     = itnim->conf_comp;
 779        attr->task_retry_id = itnim->task_retry_id;
 780        return BFA_STATUS_OK;
 781}
 782
 783bfa_status_t
 784bfa_fcs_itnim_stats_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn,
 785                        struct bfa_itnim_stats_s *stats)
 786{
 787        struct bfa_fcs_itnim_s *itnim = NULL;
 788
 789        WARN_ON(port == NULL);
 790
 791        itnim = bfa_fcs_itnim_lookup(port, rpwwn);
 792
 793        if (itnim == NULL)
 794                return BFA_STATUS_NO_FCPIM_NEXUS;
 795
 796        memcpy(stats, &itnim->stats, sizeof(struct bfa_itnim_stats_s));
 797
 798        return BFA_STATUS_OK;
 799}
 800
 801bfa_status_t
 802bfa_fcs_itnim_stats_clear(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
 803{
 804        struct bfa_fcs_itnim_s *itnim = NULL;
 805
 806        WARN_ON(port == NULL);
 807
 808        itnim = bfa_fcs_itnim_lookup(port, rpwwn);
 809
 810        if (itnim == NULL)
 811                return BFA_STATUS_NO_FCPIM_NEXUS;
 812
 813        memset(&itnim->stats, 0, sizeof(struct bfa_itnim_stats_s));
 814        return BFA_STATUS_OK;
 815}
 816
 817void
 818bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim,
 819                        struct fchs_s *fchs, u16 len)
 820{
 821        struct fc_els_cmd_s *els_cmd;
 822
 823        bfa_trc(itnim->fcs, fchs->type);
 824
 825        if (fchs->type != FC_TYPE_ELS)
 826                return;
 827
 828        els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
 829
 830        bfa_trc(itnim->fcs, els_cmd->els_code);
 831
 832        switch (els_cmd->els_code) {
 833        case FC_ELS_PRLO:
 834                bfa_fcs_rport_prlo(itnim->rport, fchs->ox_id);
 835                break;
 836
 837        default:
 838                WARN_ON(1);
 839        }
 840}
 841