Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
0004  * Copyright (c) 2014- QLogic Corporation.
0005  * All rights reserved
0006  * www.qlogic.com
0007  *
0008  * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
0009  */
0010 
0011 /*
0012  *  fcpim.c - FCP initiator mode i-t nexus state machine
0013  */
0014 
0015 #include "bfad_drv.h"
0016 #include "bfa_fcs.h"
0017 #include "bfa_fcbuild.h"
0018 #include "bfad_im.h"
0019 
0020 BFA_TRC_FILE(FCS, FCPIM);
0021 
0022 /*
0023  * forward declarations
0024  */
0025 static void bfa_fcs_itnim_timeout(void *arg);
0026 static void bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim);
0027 static void bfa_fcs_itnim_send_prli(void *itnim_cbarg,
0028                     struct bfa_fcxp_s *fcxp_alloced);
0029 static void bfa_fcs_itnim_prli_response(void *fcsarg,
0030              struct bfa_fcxp_s *fcxp, void *cbarg,
0031                 bfa_status_t req_status, u32 rsp_len,
0032                 u32 resid_len, struct fchs_s *rsp_fchs);
0033 static void bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
0034             enum bfa_itnim_aen_event event);
0035 
0036 static void bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
0037                      enum bfa_fcs_itnim_event event);
0038 static void bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim,
0039                        enum bfa_fcs_itnim_event event);
0040 static void bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
0041                       enum bfa_fcs_itnim_event event);
0042 static void bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
0043                         enum bfa_fcs_itnim_event event);
0044 static void bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
0045                         enum bfa_fcs_itnim_event event);
0046 static void bfa_fcs_itnim_sm_hal_rport_online(struct bfa_fcs_itnim_s *itnim,
0047                     enum bfa_fcs_itnim_event event);
0048 static void bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
0049                     enum bfa_fcs_itnim_event event);
0050 static void bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim,
0051                          enum bfa_fcs_itnim_event event);
0052 static void bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
0053                        enum bfa_fcs_itnim_event event);
0054 
0055 static struct bfa_sm_table_s itnim_sm_table[] = {
0056     {BFA_SM(bfa_fcs_itnim_sm_offline), BFA_ITNIM_OFFLINE},
0057     {BFA_SM(bfa_fcs_itnim_sm_prli_send), BFA_ITNIM_PRLI_SEND},
0058     {BFA_SM(bfa_fcs_itnim_sm_prli), BFA_ITNIM_PRLI_SENT},
0059     {BFA_SM(bfa_fcs_itnim_sm_prli_retry), BFA_ITNIM_PRLI_RETRY},
0060     {BFA_SM(bfa_fcs_itnim_sm_hcb_online), BFA_ITNIM_HCB_ONLINE},
0061     {BFA_SM(bfa_fcs_itnim_sm_online), BFA_ITNIM_ONLINE},
0062     {BFA_SM(bfa_fcs_itnim_sm_hcb_offline), BFA_ITNIM_HCB_OFFLINE},
0063     {BFA_SM(bfa_fcs_itnim_sm_initiator), BFA_ITNIM_INITIATIOR},
0064 };
0065 
0066 /*
0067  *  fcs_itnim_sm FCS itnim state machine
0068  */
0069 
0070 static void
0071 bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
0072          enum bfa_fcs_itnim_event event)
0073 {
0074     bfa_trc(itnim->fcs, itnim->rport->pwwn);
0075     bfa_trc(itnim->fcs, event);
0076 
0077     switch (event) {
0078     case BFA_FCS_ITNIM_SM_FCS_ONLINE:
0079         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send);
0080         itnim->prli_retries = 0;
0081         bfa_fcs_itnim_send_prli(itnim, NULL);
0082         break;
0083 
0084     case BFA_FCS_ITNIM_SM_OFFLINE:
0085         bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
0086         break;
0087 
0088     case BFA_FCS_ITNIM_SM_INITIATOR:
0089         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
0090         break;
0091 
0092     case BFA_FCS_ITNIM_SM_DELETE:
0093         bfa_fcs_itnim_free(itnim);
0094         break;
0095 
0096     default:
0097         bfa_sm_fault(itnim->fcs, event);
0098     }
0099 
0100 }
0101 
0102 static void
0103 bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim,
0104          enum bfa_fcs_itnim_event event)
0105 {
0106     bfa_trc(itnim->fcs, itnim->rport->pwwn);
0107     bfa_trc(itnim->fcs, event);
0108 
0109     switch (event) {
0110     case BFA_FCS_ITNIM_SM_FRMSENT:
0111         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli);
0112         break;
0113 
0114     case BFA_FCS_ITNIM_SM_INITIATOR:
0115         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
0116         bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe);
0117         bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_FCS_ONLINE);
0118         break;
0119 
0120     case BFA_FCS_ITNIM_SM_OFFLINE:
0121         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
0122         bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe);
0123         bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
0124         break;
0125 
0126     case BFA_FCS_ITNIM_SM_DELETE:
0127         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
0128         bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe);
0129         bfa_fcs_itnim_free(itnim);
0130         break;
0131 
0132     default:
0133         bfa_sm_fault(itnim->fcs, event);
0134     }
0135 }
0136 
0137 static void
0138 bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
0139          enum bfa_fcs_itnim_event event)
0140 {
0141     bfa_trc(itnim->fcs, itnim->rport->pwwn);
0142     bfa_trc(itnim->fcs, event);
0143 
0144     switch (event) {
0145     case BFA_FCS_ITNIM_SM_RSP_OK:
0146         if (itnim->rport->scsi_function == BFA_RPORT_INITIATOR)
0147             bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
0148         else
0149             bfa_sm_set_state(itnim,
0150                 bfa_fcs_itnim_sm_hal_rport_online);
0151 
0152         bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_FCS_ONLINE);
0153         break;
0154 
0155     case BFA_FCS_ITNIM_SM_RSP_ERROR:
0156         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_retry);
0157         bfa_timer_start(itnim->fcs->bfa, &itnim->timer,
0158                 bfa_fcs_itnim_timeout, itnim,
0159                 BFA_FCS_RETRY_TIMEOUT);
0160         break;
0161 
0162     case BFA_FCS_ITNIM_SM_RSP_NOT_SUPP:
0163         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
0164         break;
0165 
0166     case BFA_FCS_ITNIM_SM_OFFLINE:
0167         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
0168         bfa_fcxp_discard(itnim->fcxp);
0169         bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
0170         break;
0171 
0172     case BFA_FCS_ITNIM_SM_INITIATOR:
0173         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
0174         bfa_fcxp_discard(itnim->fcxp);
0175         bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_FCS_ONLINE);
0176         break;
0177 
0178     case BFA_FCS_ITNIM_SM_DELETE:
0179         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
0180         bfa_fcxp_discard(itnim->fcxp);
0181         bfa_fcs_itnim_free(itnim);
0182         break;
0183 
0184     default:
0185         bfa_sm_fault(itnim->fcs, event);
0186     }
0187 }
0188 
0189 static void
0190 bfa_fcs_itnim_sm_hal_rport_online(struct bfa_fcs_itnim_s *itnim,
0191                 enum bfa_fcs_itnim_event event)
0192 {
0193     bfa_trc(itnim->fcs, itnim->rport->pwwn);
0194     bfa_trc(itnim->fcs, event);
0195 
0196     switch (event) {
0197     case BFA_FCS_ITNIM_SM_HAL_ONLINE:
0198         if (!itnim->bfa_itnim)
0199             itnim->bfa_itnim = bfa_itnim_create(itnim->fcs->bfa,
0200                     itnim->rport->bfa_rport, itnim);
0201 
0202         if (itnim->bfa_itnim) {
0203             bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_online);
0204             bfa_itnim_online(itnim->bfa_itnim, itnim->seq_rec);
0205         } else {
0206             bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
0207             bfa_sm_send_event(itnim->rport, RPSM_EVENT_DELETE);
0208         }
0209 
0210         break;
0211 
0212     case BFA_FCS_ITNIM_SM_OFFLINE:
0213         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
0214         bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
0215         break;
0216 
0217     case BFA_FCS_ITNIM_SM_DELETE:
0218         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
0219         bfa_fcs_itnim_free(itnim);
0220         break;
0221 
0222     default:
0223         bfa_sm_fault(itnim->fcs, event);
0224     }
0225 }
0226 
0227 static void
0228 bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
0229                 enum bfa_fcs_itnim_event event)
0230 {
0231     bfa_trc(itnim->fcs, itnim->rport->pwwn);
0232     bfa_trc(itnim->fcs, event);
0233 
0234     switch (event) {
0235     case BFA_FCS_ITNIM_SM_TIMEOUT:
0236         if (itnim->prli_retries < BFA_FCS_RPORT_MAX_RETRIES) {
0237             itnim->prli_retries++;
0238             bfa_trc(itnim->fcs, itnim->prli_retries);
0239             bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send);
0240             bfa_fcs_itnim_send_prli(itnim, NULL);
0241         } else {
0242             /* invoke target offline */
0243             bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
0244             bfa_sm_send_event(itnim->rport, RPSM_EVENT_LOGO_IMP);
0245         }
0246         break;
0247 
0248 
0249     case BFA_FCS_ITNIM_SM_OFFLINE:
0250         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
0251         bfa_timer_stop(&itnim->timer);
0252         bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
0253         break;
0254 
0255     case BFA_FCS_ITNIM_SM_INITIATOR:
0256         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
0257         bfa_timer_stop(&itnim->timer);
0258         bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_FCS_ONLINE);
0259         break;
0260 
0261     case BFA_FCS_ITNIM_SM_DELETE:
0262         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
0263         bfa_timer_stop(&itnim->timer);
0264         bfa_fcs_itnim_free(itnim);
0265         break;
0266 
0267     default:
0268         bfa_sm_fault(itnim->fcs, event);
0269     }
0270 }
0271 
0272 static void
0273 bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
0274                 enum bfa_fcs_itnim_event event)
0275 {
0276     struct bfad_s *bfad = (struct bfad_s *)itnim->fcs->bfad;
0277     char    lpwwn_buf[BFA_STRING_32];
0278     char    rpwwn_buf[BFA_STRING_32];
0279 
0280     bfa_trc(itnim->fcs, itnim->rport->pwwn);
0281     bfa_trc(itnim->fcs, event);
0282 
0283     switch (event) {
0284     case BFA_FCS_ITNIM_SM_HCB_ONLINE:
0285         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_online);
0286         bfa_fcb_itnim_online(itnim->itnim_drv);
0287         wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port));
0288         wwn2str(rpwwn_buf, itnim->rport->pwwn);
0289         BFA_LOG(KERN_INFO, bfad, bfa_log_level,
0290         "Target (WWN = %s) is online for initiator (WWN = %s)\n",
0291         rpwwn_buf, lpwwn_buf);
0292         bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_ONLINE);
0293         break;
0294 
0295     case BFA_FCS_ITNIM_SM_OFFLINE:
0296         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_offline);
0297         bfa_itnim_offline(itnim->bfa_itnim);
0298         break;
0299 
0300     case BFA_FCS_ITNIM_SM_DELETE:
0301         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
0302         bfa_fcs_itnim_free(itnim);
0303         break;
0304 
0305     default:
0306         bfa_sm_fault(itnim->fcs, event);
0307     }
0308 }
0309 
0310 static void
0311 bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
0312          enum bfa_fcs_itnim_event event)
0313 {
0314     struct bfad_s *bfad = (struct bfad_s *)itnim->fcs->bfad;
0315     char    lpwwn_buf[BFA_STRING_32];
0316     char    rpwwn_buf[BFA_STRING_32];
0317 
0318     bfa_trc(itnim->fcs, itnim->rport->pwwn);
0319     bfa_trc(itnim->fcs, event);
0320 
0321     switch (event) {
0322     case BFA_FCS_ITNIM_SM_OFFLINE:
0323         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_offline);
0324         bfa_fcb_itnim_offline(itnim->itnim_drv);
0325         bfa_itnim_offline(itnim->bfa_itnim);
0326         wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port));
0327         wwn2str(rpwwn_buf, itnim->rport->pwwn);
0328         if (bfa_fcs_lport_is_online(itnim->rport->port) == BFA_TRUE) {
0329             BFA_LOG(KERN_ERR, bfad, bfa_log_level,
0330             "Target (WWN = %s) connectivity lost for "
0331             "initiator (WWN = %s)\n", rpwwn_buf, lpwwn_buf);
0332             bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_DISCONNECT);
0333         } else {
0334             BFA_LOG(KERN_INFO, bfad, bfa_log_level,
0335             "Target (WWN = %s) offlined by initiator (WWN = %s)\n",
0336             rpwwn_buf, lpwwn_buf);
0337             bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_OFFLINE);
0338         }
0339         break;
0340 
0341     case BFA_FCS_ITNIM_SM_DELETE:
0342         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
0343         bfa_fcs_itnim_free(itnim);
0344         break;
0345 
0346     default:
0347         bfa_sm_fault(itnim->fcs, event);
0348     }
0349 }
0350 
0351 static void
0352 bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim,
0353                  enum bfa_fcs_itnim_event event)
0354 {
0355     bfa_trc(itnim->fcs, itnim->rport->pwwn);
0356     bfa_trc(itnim->fcs, event);
0357 
0358     switch (event) {
0359     case BFA_FCS_ITNIM_SM_HCB_OFFLINE:
0360         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
0361         bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
0362         break;
0363 
0364     case BFA_FCS_ITNIM_SM_DELETE:
0365         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
0366         bfa_fcs_itnim_free(itnim);
0367         break;
0368 
0369     default:
0370         bfa_sm_fault(itnim->fcs, event);
0371     }
0372 }
0373 
0374 /*
0375  * This state is set when a discovered rport is also in intiator mode.
0376  * This ITN is marked as no_op and is not active and will not be truned into
0377  * online state.
0378  */
0379 static void
0380 bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
0381          enum bfa_fcs_itnim_event event)
0382 {
0383     bfa_trc(itnim->fcs, itnim->rport->pwwn);
0384     bfa_trc(itnim->fcs, event);
0385 
0386     switch (event) {
0387     case BFA_FCS_ITNIM_SM_OFFLINE:
0388         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
0389         bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
0390         break;
0391 
0392     /*
0393      * fcs_online is expected here for well known initiator ports
0394      */
0395     case BFA_FCS_ITNIM_SM_FCS_ONLINE:
0396         bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_FCS_ONLINE);
0397         break;
0398 
0399     case BFA_FCS_ITNIM_SM_RSP_ERROR:
0400     case BFA_FCS_ITNIM_SM_INITIATOR:
0401         break;
0402 
0403     case BFA_FCS_ITNIM_SM_DELETE:
0404         bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
0405         bfa_fcs_itnim_free(itnim);
0406         break;
0407 
0408     default:
0409         bfa_sm_fault(itnim->fcs, event);
0410     }
0411 }
0412 
0413 static void
0414 bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
0415             enum bfa_itnim_aen_event event)
0416 {
0417     struct bfa_fcs_rport_s *rport = itnim->rport;
0418     struct bfad_s *bfad = (struct bfad_s *)itnim->fcs->bfad;
0419     struct bfa_aen_entry_s  *aen_entry;
0420 
0421     /* Don't post events for well known addresses */
0422     if (BFA_FCS_PID_IS_WKA(rport->pid))
0423         return;
0424 
0425     bfad_get_aen_entry(bfad, aen_entry);
0426     if (!aen_entry)
0427         return;
0428 
0429     aen_entry->aen_data.itnim.vf_id = rport->port->fabric->vf_id;
0430     aen_entry->aen_data.itnim.ppwwn = bfa_fcs_lport_get_pwwn(
0431                     bfa_fcs_get_base_port(itnim->fcs));
0432     aen_entry->aen_data.itnim.lpwwn = bfa_fcs_lport_get_pwwn(rport->port);
0433     aen_entry->aen_data.itnim.rpwwn = rport->pwwn;
0434 
0435     /* Send the AEN notification */
0436     bfad_im_post_vendor_event(aen_entry, bfad, ++rport->fcs->fcs_aen_seq,
0437                   BFA_AEN_CAT_ITNIM, event);
0438 }
0439 
0440 static void
0441 bfa_fcs_itnim_send_prli(void *itnim_cbarg, struct bfa_fcxp_s *fcxp_alloced)
0442 {
0443     struct bfa_fcs_itnim_s *itnim = itnim_cbarg;
0444     struct bfa_fcs_rport_s *rport = itnim->rport;
0445     struct bfa_fcs_lport_s *port = rport->port;
0446     struct fchs_s   fchs;
0447     struct bfa_fcxp_s *fcxp;
0448     int     len;
0449 
0450     bfa_trc(itnim->fcs, itnim->rport->pwwn);
0451 
0452     fcxp = fcxp_alloced ? fcxp_alloced :
0453            bfa_fcs_fcxp_alloc(port->fcs, BFA_TRUE);
0454     if (!fcxp) {
0455         itnim->stats.fcxp_alloc_wait++;
0456         bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &itnim->fcxp_wqe,
0457                 bfa_fcs_itnim_send_prli, itnim, BFA_TRUE);
0458         return;
0459     }
0460     itnim->fcxp = fcxp;
0461 
0462     len = fc_prli_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
0463                 itnim->rport->pid, bfa_fcs_lport_get_fcid(port), 0);
0464 
0465     bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id, port->lp_tag,
0466               BFA_FALSE, FC_CLASS_3, len, &fchs,
0467               bfa_fcs_itnim_prli_response, (void *)itnim,
0468               FC_MAX_PDUSZ, FC_ELS_TOV);
0469 
0470     itnim->stats.prli_sent++;
0471     bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_FRMSENT);
0472 }
0473 
0474 static void
0475 bfa_fcs_itnim_prli_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
0476                 bfa_status_t req_status, u32 rsp_len,
0477                 u32 resid_len, struct fchs_s *rsp_fchs)
0478 {
0479     struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cbarg;
0480     struct fc_els_cmd_s *els_cmd;
0481     struct fc_prli_s *prli_resp;
0482     struct fc_ls_rjt_s *ls_rjt;
0483     struct fc_prli_params_s *sparams;
0484 
0485     bfa_trc(itnim->fcs, req_status);
0486 
0487     /*
0488      * Sanity Checks
0489      */
0490     if (req_status != BFA_STATUS_OK) {
0491         itnim->stats.prli_rsp_err++;
0492         bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR);
0493         return;
0494     }
0495 
0496     els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);
0497 
0498     if (els_cmd->els_code == FC_ELS_ACC) {
0499         prli_resp = (struct fc_prli_s *) els_cmd;
0500 
0501         if (fc_prli_rsp_parse(prli_resp, rsp_len) != FC_PARSE_OK) {
0502             bfa_trc(itnim->fcs, rsp_len);
0503             /*
0504              * Check if this  r-port is also in Initiator mode.
0505              * If so, we need to set this ITN as a no-op.
0506              */
0507             if (prli_resp->parampage.servparams.initiator) {
0508                 bfa_trc(itnim->fcs, prli_resp->parampage.type);
0509                 itnim->rport->scsi_function =
0510                         BFA_RPORT_INITIATOR;
0511                 itnim->stats.prli_rsp_acc++;
0512                 itnim->stats.initiator++;
0513                 bfa_sm_send_event(itnim,
0514                           BFA_FCS_ITNIM_SM_RSP_OK);
0515                 return;
0516             }
0517 
0518             itnim->stats.prli_rsp_parse_err++;
0519             return;
0520         }
0521         itnim->rport->scsi_function = BFA_RPORT_TARGET;
0522 
0523         sparams = &prli_resp->parampage.servparams;
0524         itnim->seq_rec       = sparams->retry;
0525         itnim->rec_support   = sparams->rec_support;
0526         itnim->task_retry_id = sparams->task_retry_id;
0527         itnim->conf_comp     = sparams->confirm;
0528 
0529         itnim->stats.prli_rsp_acc++;
0530         bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_OK);
0531     } else {
0532         ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);
0533 
0534         bfa_trc(itnim->fcs, ls_rjt->reason_code);
0535         bfa_trc(itnim->fcs, ls_rjt->reason_code_expl);
0536 
0537         itnim->stats.prli_rsp_rjt++;
0538         if (ls_rjt->reason_code == FC_LS_RJT_RSN_CMD_NOT_SUPP) {
0539             bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_NOT_SUPP);
0540             return;
0541         }
0542         bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR);
0543     }
0544 }
0545 
0546 static void
0547 bfa_fcs_itnim_timeout(void *arg)
0548 {
0549     struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) arg;
0550 
0551     itnim->stats.timeout++;
0552     bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_TIMEOUT);
0553 }
0554 
0555 static void
0556 bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim)
0557 {
0558     if (itnim->bfa_itnim) {
0559         bfa_itnim_delete(itnim->bfa_itnim);
0560         itnim->bfa_itnim = NULL;
0561     }
0562 
0563     bfa_fcb_itnim_free(itnim->fcs->bfad, itnim->itnim_drv);
0564 }
0565 
0566 
0567 
0568 /*
0569  *  itnim_public FCS ITNIM public interfaces
0570  */
0571 
0572 /*
0573  *  Called by rport when a new rport is created.
0574  *
0575  * @param[in] rport -  remote port.
0576  */
0577 struct bfa_fcs_itnim_s *
0578 bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport)
0579 {
0580     struct bfa_fcs_lport_s *port = rport->port;
0581     struct bfa_fcs_itnim_s *itnim;
0582     struct bfad_itnim_s   *itnim_drv;
0583     int ret;
0584 
0585     /*
0586      * call bfad to allocate the itnim
0587      */
0588     ret = bfa_fcb_itnim_alloc(port->fcs->bfad, &itnim, &itnim_drv);
0589     if (ret) {
0590         bfa_trc(port->fcs, rport->pwwn);
0591         return NULL;
0592     }
0593 
0594     /*
0595      * Initialize itnim
0596      */
0597     itnim->rport = rport;
0598     itnim->fcs = rport->fcs;
0599     itnim->itnim_drv = itnim_drv;
0600 
0601     itnim->bfa_itnim     = NULL;
0602     itnim->seq_rec       = BFA_FALSE;
0603     itnim->rec_support   = BFA_FALSE;
0604     itnim->conf_comp     = BFA_FALSE;
0605     itnim->task_retry_id = BFA_FALSE;
0606 
0607     /*
0608      * Set State machine
0609      */
0610     bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
0611 
0612     return itnim;
0613 }
0614 
0615 /*
0616  *  Called by rport to delete  the instance of FCPIM.
0617  *
0618  * @param[in] rport -  remote port.
0619  */
0620 void
0621 bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim)
0622 {
0623     bfa_trc(itnim->fcs, itnim->rport->pid);
0624     bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_DELETE);
0625 }
0626 
0627 /*
0628  * Notification from rport that PLOGI is complete to initiate FC-4 session.
0629  */
0630 void
0631 bfa_fcs_itnim_brp_online(struct bfa_fcs_itnim_s *itnim)
0632 {
0633     itnim->stats.onlines++;
0634 
0635     if (!BFA_FCS_PID_IS_WKA(itnim->rport->pid))
0636         bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HAL_ONLINE);
0637 }
0638 
0639 /*
0640  * Called by rport to handle a remote device offline.
0641  */
0642 void
0643 bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim)
0644 {
0645     itnim->stats.offlines++;
0646     bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_OFFLINE);
0647 }
0648 
0649 /*
0650  * Called by rport when remote port is known to be an initiator from
0651  * PRLI received.
0652  */
0653 void
0654 bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim)
0655 {
0656     bfa_trc(itnim->fcs, itnim->rport->pid);
0657     itnim->stats.initiator++;
0658     bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR);
0659 }
0660 
0661 /*
0662  * Called by rport to check if the itnim is online.
0663  */
0664 bfa_status_t
0665 bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim)
0666 {
0667     bfa_trc(itnim->fcs, itnim->rport->pid);
0668     switch (bfa_sm_to_state(itnim_sm_table, itnim->sm)) {
0669     case BFA_ITNIM_ONLINE:
0670     case BFA_ITNIM_INITIATIOR:
0671         return BFA_STATUS_OK;
0672 
0673     default:
0674         return BFA_STATUS_NO_FCPIM_NEXUS;
0675     }
0676 }
0677 
0678 /*
0679  * BFA completion callback for bfa_itnim_online().
0680  */
0681 void
0682 bfa_cb_itnim_online(void *cbarg)
0683 {
0684     struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cbarg;
0685 
0686     bfa_trc(itnim->fcs, itnim->rport->pwwn);
0687     bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_ONLINE);
0688 }
0689 
0690 /*
0691  * BFA completion callback for bfa_itnim_offline().
0692  */
0693 void
0694 bfa_cb_itnim_offline(void *cb_arg)
0695 {
0696     struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
0697 
0698     bfa_trc(itnim->fcs, itnim->rport->pwwn);
0699     bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_OFFLINE);
0700 }
0701 
0702 /*
0703  * Mark the beginning of PATH TOV handling. IO completion callbacks
0704  * are still pending.
0705  */
0706 void
0707 bfa_cb_itnim_tov_begin(void *cb_arg)
0708 {
0709     struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
0710 
0711     bfa_trc(itnim->fcs, itnim->rport->pwwn);
0712 }
0713 
0714 /*
0715  * Mark the end of PATH TOV handling. All pending IOs are already cleaned up.
0716  */
0717 void
0718 bfa_cb_itnim_tov(void *cb_arg)
0719 {
0720     struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
0721     struct bfad_itnim_s *itnim_drv = itnim->itnim_drv;
0722 
0723     bfa_trc(itnim->fcs, itnim->rport->pwwn);
0724     itnim_drv->state = ITNIM_STATE_TIMEOUT;
0725 }
0726 
0727 /*
0728  *      BFA notification to FCS/driver for second level error recovery.
0729  *
0730  * Atleast one I/O request has timedout and target is unresponsive to
0731  * repeated abort requests. Second level error recovery should be initiated
0732  * by starting implicit logout and recovery procedures.
0733  */
0734 void
0735 bfa_cb_itnim_sler(void *cb_arg)
0736 {
0737     struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
0738 
0739     itnim->stats.sler++;
0740     bfa_trc(itnim->fcs, itnim->rport->pwwn);
0741     bfa_sm_send_event(itnim->rport, RPSM_EVENT_LOGO_IMP);
0742 }
0743 
0744 struct bfa_fcs_itnim_s *
0745 bfa_fcs_itnim_lookup(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
0746 {
0747     struct bfa_fcs_rport_s *rport;
0748     rport = bfa_fcs_rport_lookup(port, rpwwn);
0749 
0750     if (!rport)
0751         return NULL;
0752 
0753     WARN_ON(rport->itnim == NULL);
0754     return rport->itnim;
0755 }
0756 
0757 bfa_status_t
0758 bfa_fcs_itnim_attr_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn,
0759                struct bfa_itnim_attr_s *attr)
0760 {
0761     struct bfa_fcs_itnim_s *itnim = NULL;
0762 
0763     itnim = bfa_fcs_itnim_lookup(port, rpwwn);
0764 
0765     if (itnim == NULL)
0766         return BFA_STATUS_NO_FCPIM_NEXUS;
0767 
0768     attr->state     = bfa_sm_to_state(itnim_sm_table, itnim->sm);
0769     attr->retry     = itnim->seq_rec;
0770     attr->rec_support   = itnim->rec_support;
0771     attr->conf_comp     = itnim->conf_comp;
0772     attr->task_retry_id = itnim->task_retry_id;
0773     return BFA_STATUS_OK;
0774 }
0775 
0776 bfa_status_t
0777 bfa_fcs_itnim_stats_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn,
0778             struct bfa_itnim_stats_s *stats)
0779 {
0780     struct bfa_fcs_itnim_s *itnim = NULL;
0781 
0782     WARN_ON(port == NULL);
0783 
0784     itnim = bfa_fcs_itnim_lookup(port, rpwwn);
0785 
0786     if (itnim == NULL)
0787         return BFA_STATUS_NO_FCPIM_NEXUS;
0788 
0789     memcpy(stats, &itnim->stats, sizeof(struct bfa_itnim_stats_s));
0790 
0791     return BFA_STATUS_OK;
0792 }
0793 
0794 bfa_status_t
0795 bfa_fcs_itnim_stats_clear(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
0796 {
0797     struct bfa_fcs_itnim_s *itnim = NULL;
0798 
0799     WARN_ON(port == NULL);
0800 
0801     itnim = bfa_fcs_itnim_lookup(port, rpwwn);
0802 
0803     if (itnim == NULL)
0804         return BFA_STATUS_NO_FCPIM_NEXUS;
0805 
0806     memset(&itnim->stats, 0, sizeof(struct bfa_itnim_stats_s));
0807     return BFA_STATUS_OK;
0808 }
0809 
0810 void
0811 bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim,
0812             struct fchs_s *fchs, u16 len)
0813 {
0814     struct fc_els_cmd_s *els_cmd;
0815 
0816     bfa_trc(itnim->fcs, fchs->type);
0817 
0818     if (fchs->type != FC_TYPE_ELS)
0819         return;
0820 
0821     els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
0822 
0823     bfa_trc(itnim->fcs, els_cmd->els_code);
0824 
0825     switch (els_cmd->els_code) {
0826     case FC_ELS_PRLO:
0827         bfa_fcs_rport_prlo(itnim->rport, fchs->ox_id);
0828         break;
0829 
0830     default:
0831         WARN_ON(1);
0832     }
0833 }