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