On Thursday, October 24, 2024 12:28 AM, Hannes Reinecke <hare@xxxxxxx> wrote: > > On 10/18/24 18:13, Karan Tilak Kumar wrote: > > Add support for target based solicited requests and responses. > > Add support for tport definitions and processing. > > Add support for restarting the IT nexus. > > > > Reported-by: kernel test robot <lkp@xxxxxxxxx> > > Closes: > > https://lore.kernel.org/oe-kbuild-all/202406120146.xchlZbqX-lkp@ > > intel.com/ > > > > Reviewed-by: Sesidhar Baddela <sebaddel@xxxxxxxxx> > > Co-developed-by: Gian Carlo Boffa <gcboffa@xxxxxxxxx> > > Signed-off-by: Gian Carlo Boffa <gcboffa@xxxxxxxxx> > > Co-developed-by: Arulprabhu Ponnusamy <arulponn@xxxxxxxxx> > > Signed-off-by: Arulprabhu Ponnusamy <arulponn@xxxxxxxxx> > > Co-developed-by: Arun Easi <aeasi@xxxxxxxxx> > > Signed-off-by: Arun Easi <aeasi@xxxxxxxxx> > > Co-developed-by: Karan Tilak Kumar <kartilak@xxxxxxxxx> > > Signed-off-by: Karan Tilak Kumar <kartilak@xxxxxxxxx> > > --- > > Changes between v4 and v5: > > Incorporate review comments from Martin: > > Call fdls_get_tgt_oxid_pool. > > Modify attribution appropriately. > > > > Changes between v2 and v3: > > Fix issue found by kernel test robot. > > Remove fnic_std_ba_acc definition to fix compilation > > warning. > > Incorporate review comments from Hannes: > > Replace redundant definitions with standard definitions. > > Replace static OXIDs with pool-based OXIDs for targets. > > > > Changes between v1 and v2: > > Incorporate review comments from Hannes: > > Use the correct kernel-doc format. > > Replace htonll() with get_unaligned_be64(). > > Replace fnic_del_fabric_timer_sync macro calls to function > > calls. > > Replace fnic_del_tport_timer_sync macro calls to function > > calls. > > Rename fc_abts_s to fc_tport_abts_s. > > Modify fc_tport_abts_s to be a global frame. > > Rename variable pfc_abts to tport_abts. > > Replace definitions with standard definitions from > > fc_els.h. > > Modify functions with returns in the middle to if else > > clauses. > > Replace simultaneous use of fc_tport_abts_s and tport_abts with > > just tport_abts. > > --- > > drivers/scsi/fnic/fdls_disc.c | 1569 +++++++++++++++++++++++++++++++-- > > drivers/scsi/fnic/fnic.h | 6 + > > drivers/scsi/fnic/fnic_fdls.h | 2 +- > > 3 files changed, 1502 insertions(+), 75 deletions(-) > > > > diff --git a/drivers/scsi/fnic/fdls_disc.c b/drivers/scsi/fnic/fdls_disc.c > > index 3a995b76a864..52459f6bb589 100644 > > --- a/drivers/scsi/fnic/fdls_disc.c > > +++ b/drivers/scsi/fnic/fdls_disc.c > > @@ -11,6 +11,10 @@ > > #include <scsi/fc/fc_fcp.h> > > #include <linux/utsname.h> > > > > +#define FC_FC4_TYPE_SCSI 0x08 > > + > > +static void fdls_send_rpn_id(struct fnic_iport_s *iport); > > + > > /* Frame initialization */ > > /* > > * Variables: > > @@ -66,6 +70,20 @@ struct fc_std_rpn_id fnic_std_rpn_id_req = { > > .ct_cmd = cpu_to_be16(FC_NS_RPN_ID)} > > }; > > > > +/* > > + * Variables: > > + * did, sid, oxid > > + */ > > +struct fc_std_els_prli fnic_std_prli_req = { > > + .fchdr = {.fh_r_ctl = FC_RCTL_ELS_REQ, .fh_type = FC_TYPE_ELS, > > + .fh_f_ctl = {FNIC_ELS_REQ_FCTL, 0, 0}, .fh_rx_id = 0xFFFF}, > > + .els_prli = {.prli_cmd = ELS_PRLI, > > + .prli_spp_len = 16, > > + .prli_len = cpu_to_be16(0x14)}, > > + .sp = {.spp_type = 0x08, .spp_flags = 0x0020, > > + .spp_params = cpu_to_be32(0xA2)} > > +}; > > + > > /* > > * Variables: > > * fh_s_id, port_id, port_name > > @@ -143,9 +161,19 @@ struct fc_frame_header fc_std_fabric_abts = { > > .fh_parm_offset = 0x00000000, /* bit:0 = 0 Abort a exchange */ > > }; > > > > +struct fc_frame_header fc_std_tport_abts = { > > + .fh_r_ctl = FC_RCTL_BA_ABTS, /* ABTS */ > > + .fh_cs_ctl = 0x00, .fh_type = FC_TYPE_BLS, > > + .fh_f_ctl = {FNIC_REQ_ABTS_FCTL, 0, 0}, .fh_seq_id = 0x00, > > + .fh_df_ctl = 0x00, .fh_seq_cnt = 0x0000, .fh_rx_id = 0xFFFF, > > + .fh_parm_offset = 0x00000000, /* bit:0 = 0 Abort a exchange */ > > +}; > > + > > #define RETRIES_EXHAUSTED(iport) \ > > (iport->fabric.retry_counter == FABRIC_LOGO_MAX_RETRY) > > > > +#define FNIC_TPORT_MAX_NEXUS_RESTART (8) > > + > > /* > > * For fabric requests and fdmi, once OXIDs are allocated from the pool > > * (and a range) they are encoded with expected rsp type as > > @@ -167,6 +195,14 @@ static void fdls_process_flogi_rsp(struct fnic_iport_s *iport, > > void *rx_frame); > > static void fnic_fdls_start_plogi(struct fnic_iport_s *iport); > > static void fnic_fdls_start_flogi(struct fnic_iport_s *iport); > > +static struct fnic_tport_s *fdls_create_tport(struct fnic_iport_s *iport, > > + uint32_t fcid, > > + uint64_t wwpn); > > +static void fdls_target_restart_nexus(struct fnic_tport_s *tport); > > +static void fdls_start_tport_timer(struct fnic_iport_s *iport, > > + struct fnic_tport_s *tport, int timeout); > > +static void fdls_tport_timer_callback(struct timer_list *t); > > + > > static void fdls_start_fabric_timer(struct fnic_iport_s *iport, > > int timeout); > > static void > > @@ -182,6 +218,8 @@ void fdls_init_oxid_pool(struct fnic_iport_s *iport) > > fdls_init_fabric_oxid_pool(&iport->fdmi_oxid_pool, > > FDLS_FDMI_OXID_POOL_BASE, > > FDLS_FDMI_OXID_POOL_SZ); > > + > > + fdls_init_tgt_oxid_pool(iport); > > } > > > > uint16_t fdls_alloc_oxid(struct fnic_iport_s *iport, > > @@ -313,6 +351,13 @@ static inline void fdls_schedule_fabric_oxid_free(struct fnic_iport_s > > iport->fabric_oxid_pool.active_oxid_fabric_req); > > } > > > > +static inline void fdls_schedule_tgt_oxid_free(struct fnic_iport_s *iport, > > + struct fnic_tgt_oxid_pool_s > > + *oxid_pool, uint16_t oxid) > > +{ > > + fdls_schedule_oxid_free(&oxid_pool->meta, oxid); > > +} > > + > > int fnic_fdls_expected_rsp(struct fnic_iport_s *iport, uint16_t oxid) > > { > > struct fnic *fnic = iport->fnic; > > @@ -340,6 +385,62 @@ static int fdls_is_oxid_in_fabric_range(uint16_t oxid) > > (oxid_unmasked <= FDLS_FABRIC_OXID_POOL_END)); > > } > > > > +void fdls_init_tgt_oxid_pool(struct fnic_iport_s *iport) > > +{ > > + memset(&iport->plogi_oxid_pool, 0, sizeof(iport->plogi_oxid_pool)); > > + iport->plogi_oxid_pool.meta.oxid_base = FDLS_PLOGI_OXID_BASE; > > + iport->plogi_oxid_pool.meta.sz = FDLS_TGT_OXID_BLOCK_SZ; > > + INIT_LIST_HEAD(&iport->plogi_oxid_pool.meta.reclaim_list); > > + > > + memset(&iport->prli_oxid_pool, 0, sizeof(iport->prli_oxid_pool)); > > + iport->prli_oxid_pool.meta.oxid_base = FDLS_PRLI_OXID_BASE; > > + iport->prli_oxid_pool.meta.sz = FDLS_TGT_OXID_BLOCK_SZ; > > + INIT_LIST_HEAD(&iport->prli_oxid_pool.meta.reclaim_list); > > + > > + memset(&iport->adisc_oxid_pool, 0, sizeof(iport->adisc_oxid_pool)); > > + iport->adisc_oxid_pool.meta.oxid_base = FDLS_ADISC_OXID_BASE; > > + iport->adisc_oxid_pool.meta.sz = FDLS_TGT_OXID_BLOCK_SZ; > > + INIT_LIST_HEAD(&iport->adisc_oxid_pool.meta.reclaim_list); > > +} > > + > > +inline uint16_t fdls_alloc_tgt_oxid(struct fnic_iport_s *iport, > > + struct fnic_tgt_oxid_pool_s *oxid_pool) > > +{ > > + uint16_t oxid; > > + > > + oxid = fdls_alloc_oxid(iport, &oxid_pool->meta, oxid_pool->bitmap); > > + return oxid; > > +} > > Do a 'return fdls_alloc_oxid()' and drop the intermediate variable. Thanks Hannes. Sure, I'll do this in the next version. > > + > > +inline void fdls_free_tgt_oxid(struct fnic_iport_s *iport, > > + struct fnic_tgt_oxid_pool_s *oxid_pool, > > + uint16_t oxid) > > +{ > > + fdls_free_oxid(iport, &oxid_pool->meta, oxid_pool->bitmap, oxid); > > +} > > + > > +static struct fnic_tgt_oxid_pool_s *fdls_get_tgt_oxid_pool(struct fnic_tport_s > > + *tport) > > +{ > > + struct fnic_iport_s *iport = (struct fnic_iport_s *)tport->iport; > > + struct fnic_tgt_oxid_pool_s *oxid_pool = NULL; > > + > > + switch (tport->state) { > > + case FDLS_TGT_STATE_PLOGI: > > + oxid_pool = &iport->plogi_oxid_pool; > > + break; > > + case FDLS_TGT_STATE_PRLI: > > + oxid_pool = &iport->prli_oxid_pool; > > + break; > > + case FDLS_TGT_STATE_ADISC: > > + oxid_pool = &iport->adisc_oxid_pool; > > + break; > > + default: > > + break; > > + } > > + return oxid_pool; > > +} > > + > > inline void fnic_del_fabric_timer_sync(struct fnic *fnic) > > { > > fnic->iport.fabric.del_timer_inprogress = 1; > > @@ -383,6 +484,56 @@ fdls_start_fabric_timer(struct fnic_iport_s *iport, int timeout) > > "fabric timer is %d ", timeout); > > } > > > > +static void > > +fdls_start_tport_timer(struct fnic_iport_s *iport, > > + struct fnic_tport_s *tport, int timeout) > > +{ > > + u64 fabric_tov; > > + struct fnic *fnic = iport->fnic; > > + > > + if (tport->timer_pending) { > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "tport fcid 0x%x: Canceling disc timer\n", > > + tport->fcid); > > + fnic_del_tport_timer_sync(fnic, tport); > > + tport->timer_pending = 0; > > + } > > + > > + if (!(tport->flags & FNIC_FDLS_TGT_ABORT_ISSUED)) > > + tport->retry_counter++; > > + > > + fabric_tov = jiffies + msecs_to_jiffies(timeout); > > + mod_timer(&tport->retry_timer, round_jiffies(fabric_tov)); > > + tport->timer_pending = 1; > > +} > > + > > +void > > +fdls_send_tport_abts(struct fnic_iport_s *iport, > > + struct fnic_tport_s *tport) > > +{ > > + uint8_t s_id[3]; > > + uint8_t d_id[3]; > > + struct fnic *fnic = iport->fnic; > > + struct fc_frame_header tport_abort = fc_std_tport_abts; > > + struct fc_frame_header *tport_abts = &tport_abort; > > + > > + hton24(s_id, iport->fcid); > > + hton24(d_id, tport->fcid); > > + FNIC_STD_SET_S_ID(tport_abts, s_id); > > + FNIC_STD_SET_D_ID(tport_abts, d_id); > > + tport->flags |= FNIC_FDLS_TGT_ABORT_ISSUED; > > + > > + tport_abts->fh_ox_id = tport->oxid_used; > > + > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "FDLS sending tport abts: tport->state: %d ", > > + tport->state); > > + > > + fnic_send_fcoe_frame(iport, tport_abts, sizeof(struct fc_frame_header)); > > + /* Even if fnic_send_fcoe_frame() fails we want to retry after timeout */ > > + fdls_start_tport_timer(iport, tport, 2 * iport->e_d_tov); > > +} > > + > > static void fdls_send_fabric_abts(struct fnic_iport_s *iport) > > { > > uint8_t fcid[3]; > > @@ -614,6 +765,176 @@ static void fdls_send_gpn_ft(struct fnic_iport_s *iport, int fdls_state) > > fdls_set_state((&iport->fabric), fdls_state); > > } > > > > +static void > > +fdls_send_tgt_adisc(struct fnic_iport_s *iport, struct fnic_tport_s *tport) > > +{ > > + struct fc_std_els_adisc adisc; > > + uint8_t s_id[3]; > > + uint8_t d_id[3]; > > + uint16_t oxid; > > + struct fnic *fnic = iport->fnic; > > + > > + memset(&adisc, 0, sizeof(struct fc_std_els_adisc)); > > + FNIC_STD_SET_R_CTL(&adisc.fchdr, 0x22); > > + FNIC_STD_SET_TYPE(&adisc.fchdr, 0x01); > > + FNIC_STD_SET_F_CTL(&adisc.fchdr, FNIC_ELS_REQ_FCTL << 16); > > + FNIC_STD_SET_RX_ID(&adisc.fchdr, cpu_to_be16(0xFFFF)); > > + > > + hton24(s_id, iport->fcid); > > + hton24(d_id, tport->fcid); > > + FNIC_STD_SET_S_ID(&adisc.fchdr, s_id); > > + FNIC_STD_SET_D_ID(&adisc.fchdr, d_id); > > + > > + oxid = htons(fdls_alloc_tgt_oxid(iport, &iport->adisc_oxid_pool)); > > + if (oxid == 0xFFFF) { > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "Failed to allocate OXID to send ADISC %p", iport); > > + return; > > + } > > + > > + tport->oxid_used = oxid; > > + tport->flags &= ~FNIC_FDLS_TGT_ABORT_ISSUED; > > + > > + FNIC_STD_SET_OX_ID((&adisc.fchdr), oxid); > > + FNIC_STD_SET_NPORT_NAME(&adisc.els.adisc_wwpn, > > + le64_to_cpu(iport->wwpn)); > > + FNIC_STD_SET_NODE_NAME(&adisc.els.adisc_wwnn, le64_to_cpu(iport->wwnn)); > > + > > + memcpy(adisc.els.adisc_port_id, s_id, 3); > That feels wrong. Isn't port_id a three-byte value in big endian? This is a byte-to-byte copy after hton24 converts the value to big endian. Please let us know your thoughts here. > > + adisc.els.adisc_cmd = ELS_ADISC; > > + > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "sending ADISC to tgt fcid: 0x%x", tport->fcid); > > + > > + > > + fnic_send_fcoe_frame(iport, &adisc, sizeof(struct fc_std_els_adisc)); > > + /* Even if fnic_send_fcoe_frame() fails we want to retry after timeout */ > > + fdls_start_tport_timer(iport, tport, 2 * iport->e_d_tov); > > +} > > + > > +bool fdls_delete_tport(struct fnic_iport_s *iport, struct fnic_tport_s *tport) > > +{ > > + struct fnic_tport_event_s *tport_del_evt; > > + struct fnic *fnic = iport->fnic; > > + > > + if ((tport->state == FDLS_TGT_STATE_OFFLINING) > > + || (tport->state == FDLS_TGT_STATE_OFFLINE)) { > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "tport fcid 0x%x: tport state is offlining/offline\n", > > + tport->fcid); > > + return false; > > + } > > + > > + fdls_set_tport_state(tport, FDLS_TGT_STATE_OFFLINING); > > + /* > > + * By setting this flag, the tport will not be seen in a look-up > > + * in an RSCN. Even if we move to multithreaded model, this tport > > + * will be destroyed and a new RSCN will have to create a new one > > + */ > > + tport->flags |= FNIC_FDLS_TPORT_TERMINATING; > > + > > + if (tport->timer_pending) { > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "tport fcid 0x%x: Canceling disc timer\n", > > + tport->fcid); > > + fnic_del_tport_timer_sync(fnic, tport); > > + tport->timer_pending = 0; > > + } > > + > > + if (IS_FNIC_FCP_INITIATOR(fnic)) { > > + spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); > > + fnic_rport_exch_reset(iport->fnic, tport->fcid); > > + spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags); > > + > > + if (tport->flags & FNIC_FDLS_SCSI_REGISTERED) { > > + tport_del_evt = > > + kzalloc(sizeof(struct fnic_tport_event_s), GFP_ATOMIC); > > + if (!tport_del_evt) { > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "Failed to allocate memory for tport fcid: 0x%0x\n", > > + tport->fcid); > > + return false; > > + } > > + tport_del_evt->event = TGT_EV_RPORT_DEL; > > + tport_del_evt->arg1 = (void *) tport; > > + list_add_tail(&tport_del_evt->links, &fnic->tport_event_list); > > + queue_work(fnic_event_queue, &fnic->tport_work); > > + } else { > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "tport 0x%x not reg with scsi_transport. Freeing locally", > > + tport->fcid); > > + list_del(&tport->links); > > + kfree(tport); > > + } > > + } > > + return true; > > +} > > + > > +static void > > +fdls_send_tgt_plogi(struct fnic_iport_s *iport, struct fnic_tport_s *tport) > > +{ > > + struct fc_std_flogi plogi; > > + uint8_t s_id[3]; > > + uint8_t d_id[3]; > > + uint16_t oxid; > > + struct fnic *fnic = iport->fnic; > > + uint32_t timeout; > > + > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "Send tgt PLOGI to fcid: 0x%x", tport->fcid); > > + > > + memcpy(&plogi, &fnic_std_plogi_req, sizeof(struct fc_std_flogi)); > > + > > + hton24(s_id, iport->fcid); > > + hton24(d_id, tport->fcid); > > + > > + FNIC_STD_SET_S_ID(&plogi.fchdr, s_id); > > + FNIC_STD_SET_D_ID(&plogi.fchdr, d_id); > > + FNIC_LOGI_SET_RDF_SIZE(&plogi.els, iport->max_payload_size); > > + > > + oxid = htons(fdls_alloc_tgt_oxid(iport, &iport->plogi_oxid_pool)); > > + if (oxid == 0xFFFF) { > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "0x%x: Failed to allocate oxid to send PLOGI to fcid: 0x%x", > > + iport->fcid, tport->fcid); > > + return; > > + } > > + > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "send tgt PLOGI: tgt fcid: 0x%x oxid: 0x%x", tport->fcid, > > + ntohs(oxid)); > > + tport->oxid_used = oxid; > > + tport->flags &= ~FNIC_FDLS_TGT_ABORT_ISSUED; > > + > > + FNIC_STD_SET_OX_ID((&plogi.fchdr), oxid); > > + FNIC_LOGI_SET_NPORT_NAME(&plogi.els, iport->wwpn); > > + FNIC_LOGI_SET_NODE_NAME(&plogi.els, iport->wwnn); > > + > > + timeout = max(2 * iport->e_d_tov, iport->plogi_timeout); > > + > > + > > + fnic_send_fcoe_frame(iport, &plogi, sizeof(struct fc_std_flogi)); > > + /* Even if fnic_send_fcoe_frame() fails we want to retry after timeout */ > > + fdls_start_tport_timer(iport, tport, timeout); > > +} > > + > > +static uint16_t > > +fnic_fc_plogi_rsp_rdf(struct fnic_iport_s *iport, > > + struct fc_std_flogi *plogi_rsp) > > +{ > > + uint16_t b2b_rdf_size = > > + be16_to_cpu(FNIC_LOGI_RDF_SIZE(&plogi_rsp->els)); > > + uint16_t spc3_rdf_size = > > + be16_to_cpu(plogi_rsp->els.fl_cssp[2].cp_rdfs) & FNIC_FC_C3_RDF; > > + struct fnic *fnic = iport->fnic; > > + > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "MFS: b2b_rdf_size: 0x%x spc3_rdf_size: 0x%x", > > + b2b_rdf_size, spc3_rdf_size); > > + > > + return MIN(b2b_rdf_size, spc3_rdf_size); > > +} > > + > > static void fdls_send_register_fc4_types(struct fnic_iport_s *iport) > > { > > struct fc_std_rft_id rft_id; > > @@ -690,6 +1011,48 @@ static void fdls_send_register_fc4_features(struct fnic_iport_s *iport) > > fdls_start_fabric_timer(iport, 2 * iport->e_d_tov); > > } > > > > +static void > > +fdls_send_tgt_prli(struct fnic_iport_s *iport, struct fnic_tport_s *tport) > > +{ > > + struct fc_std_els_prli prli; > > + uint8_t s_id[3]; > > + uint8_t d_id[3]; > > + uint16_t oxid; > > + struct fnic *fnic = iport->fnic; > > + uint32_t timeout; > > + > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "FDLS sending PRLI to tgt: 0x%x", tport->fcid); > > + > > + oxid = htons(fdls_alloc_tgt_oxid(iport, &iport->prli_oxid_pool)); > > + if (oxid == 0xFFFF) { > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "Failed to allocate OXID to send PRLI %p", iport); > > + return; > > + } > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "FDLS sending PRLI to tgt: 0x%x OXID: 0x%x", tport->fcid, > > + ntohs(oxid)); > > + > > + tport->oxid_used = oxid; > > + tport->flags &= ~FNIC_FDLS_TGT_ABORT_ISSUED; > > + memcpy(&prli, &fnic_std_prli_req, sizeof(struct fc_std_els_prli)); > Memcpy again. Thanks Hannes. Sure, I'll fix this in the next version. > > > + > > + hton24(s_id, iport->fcid); > > + hton24(d_id, tport->fcid); > > + > > + FNIC_STD_SET_S_ID((&prli.fchdr), s_id); > > + FNIC_STD_SET_D_ID((&prli.fchdr), d_id); > > + FNIC_STD_SET_OX_ID((&prli.fchdr), oxid); > > + > > + timeout = max(2 * iport->e_d_tov, iport->plogi_timeout); > > + > > + fdls_get_tgt_oxid_pool(tport); > > + fnic_send_fcoe_frame(iport, &prli, sizeof(struct fc_std_els_prli)); > > + /* Even if fnic_send_fcoe_frame() fails we want to retry after timeout */ > > + fdls_start_tport_timer(iport, tport, timeout); > > +} > > + > > /** > > * fdls_send_fabric_logo - Send flogo to the fcf > > * @iport: Handle to fnic iport > > @@ -742,6 +1105,212 @@ void fdls_send_fabric_logo(struct fnic_iport_s *iport) > > fnic_send_fcoe_frame(iport, &logo, sizeof(struct fc_std_logo)); > > } > > > > +/** > > + * fdls_tgt_logout - Send plogo to the remote port > > + * @iport: Handle to fnic iport > > + * @tport: Handle to remote port > > + * > > + * This function does not change or check the fabric/tport state. > > + * It the caller's responsibility to set the appropriate tport/fabric > > + * state when this is called. Normally that is fdls_tgt_state_plogo. > > + * This could be used to send plogo to nameserver process > > + * also not just target processes > > + */ > > +void fdls_tgt_logout(struct fnic_iport_s *iport, struct fnic_tport_s *tport) > > +{ > > + struct fc_std_logo logo; > > + uint8_t s_id[3]; > > + uint8_t d_id[3]; > > + struct fnic *fnic = iport->fnic; > > + uint16_t oxid; > > + > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "Sending logo to tport fcid: 0x%x", tport->fcid); > > + memcpy(&logo, &fnic_std_logo_req, sizeof(struct fc_std_logo)); > And here. Thanks Hannes. Sure, I'll fix this in the next version. > > + > > + hton24(s_id, iport->fcid); > > + hton24(d_id, tport->fcid); > > + > > + FNIC_STD_SET_S_ID((&logo.fchdr), s_id); > > + FNIC_STD_SET_D_ID((&logo.fchdr), d_id); > > + > > + oxid = htons(fdls_alloc_tgt_oxid(iport, &iport->plogi_oxid_pool)); > > + FNIC_STD_SET_OX_ID((&logo.fchdr), oxid); > > + > > + memcpy(&logo.els.fl_n_port_id, s_id, 3); > > + FNIC_STD_SET_NPORT_NAME(&logo.els.fl_n_port_wwn, > > + le64_to_cpu(iport->wwpn)); > > + > > + > > + fnic_send_fcoe_frame(iport, &logo, sizeof(struct fc_std_logo)); > > +} > > + > > + > > +struct fnic_tport_s *fnic_find_tport_by_fcid(struct fnic_iport_s *iport, > > + uint32_t fcid) > > +{ > > + struct fnic_tport_s *tport, *next; > > + > > + list_for_each_entry_safe(tport, next, &(iport->tport_list), links) { > > + if ((tport->fcid == fcid) > > + && !(tport->flags & FNIC_FDLS_TPORT_TERMINATING)) > > + return tport; > > Odd. Can you have two entries with the same fcid in the list? No, there cannot be two entries with the same fcid in the list. Please let us know your thoughts here. > > + } > > + return NULL; > > +} > > + > > + > > +struct fnic_tport_s *fnic_find_tport_by_wwpn(struct fnic_iport_s *iport, > > + uint64_t wwpn) > > +{ > > + struct fnic_tport_s *tport, *next; > > + > > + list_for_each_entry_safe(tport, next, &(iport->tport_list), links) { > > + if ((tport->wwpn == wwpn) > > + && !(tport->flags & FNIC_FDLS_TPORT_TERMINATING)) > > + return tport; > Same argument here. > I would have expected wwpns to be unique ... No, there cannot be two entries with the same wwpns in the list. Please let us know your thoughts here. > > + } > > + return NULL; > > +} Regards, Karan