diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index ea07afcb750a..4cea61b63fdf 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -135,14 +135,17 @@ struct lpfc_nodelist { struct lpfc_scsicmd_bkt *lat_data; /* Latency data */ uint32_t fc4_prli_sent; uint32_t fc4_xpt_flags; + uint32_t upcall_flags; #define NLP_WAIT_FOR_UNREG 0x1 #define SCSI_XPT_REGD 0x2 #define NVME_XPT_REGD 0x4 +#define NLP_WAIT_FOR_LOGO 0x2 uint32_t nvme_fb_size; /* NVME target's supported byte cnt */ #define NVME_FB_BIT_SHIFT 9 /* PRLI Rsp first burst in 512B units. */ uint32_t nlp_defer_did; + wait_queue_head_t *logo_waitq; }; struct lpfc_node_rrq { diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index e099caa04535..c944f220406e 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -2817,6 +2817,7 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, IOCB_t *irsp; unsigned long flags; uint32_t skip_recovery = 0; + int wake_up_waiter = 0; /* we pass cmdiocb to state machine which needs rspiocb as well */ cmdiocb->context_un.rsp_iocb = rspiocb; @@ -2824,6 +2825,10 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp = &(rspiocb->iocb); spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_LOGO_SND; + if (ndlp->upcall_flags & NLP_WAIT_FOR_LOGO) { + wake_up_waiter = 1; + ndlp->upcall_flags &= ~NLP_WAIT_FOR_LOGO; + } spin_unlock_irq(&ndlp->lock); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, @@ -2889,6 +2894,8 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * Initiator, we are assuming the NPortID is not going to change. */ + if (wake_up_waiter && ndlp->logo_waitq) + wake_up(ndlp->logo_waitq); /* * If the node is a target, the handling attempts to recover the port. * For any other port type, the rpi is unregistered as an implicit diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 78f34b1af980..4ee890de556b 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -5924,6 +5924,8 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) struct lpfc_scsi_event_header scsi_event; int status; u32 logit = LOG_FCP; + unsigned long flags; + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); rdata = lpfc_rport_data_from_scsi_device(cmnd->device); if (!rdata || !rdata->pnode) { @@ -5942,10 +5944,10 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0722 Target Reset rport failure: rdata x%px\n", rdata); if (pnode) { - spin_lock_irq(&pnode->lock); + spin_lock_irqsave(&pnode->lock, flags); pnode->nlp_flag &= ~NLP_NPR_ADISC; pnode->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; - spin_unlock_irq(&pnode->lock); + spin_unlock_irqrestore(&pnode->lock, flags); } lpfc_reset_flush_io_context(vport, tgt_id, lun_id, LPFC_CTX_TGT); @@ -5965,6 +5967,38 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) FCP_TARGET_RESET); if (status != SUCCESS) logit = LOG_TRACE_EVENT; + spin_lock_irqsave(&pnode->lock, flags); + if (status != SUCCESS && + (!(pnode->upcall_flags & NLP_WAIT_FOR_LOGO)) && + !pnode->logo_waitq) { + pnode->logo_waitq = &waitq; + pnode->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; + pnode->nlp_flag |= NLP_ISSUE_LOGO; + pnode->upcall_flags |= NLP_WAIT_FOR_LOGO; + spin_unlock_irqrestore(&pnode->lock, flags); + lpfc_unreg_rpi(vport, pnode); + wait_event_timeout(waitq, + (!(pnode->upcall_flags & NLP_WAIT_FOR_LOGO)), + msecs_to_jiffies(vport->cfg_devloss_tmo * + 1000)); + + if (pnode->upcall_flags & NLP_WAIT_FOR_LOGO) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "0725 SCSI layer TGTRST failed & LOGO TMO " + " (%d, %llu) return x%x\n", tgt_id, + lun_id, status); + spin_lock_irqsave(&pnode->lock, flags); + pnode->upcall_flags &= ~NLP_WAIT_FOR_LOGO; + } else { + spin_lock_irqsave(&pnode->lock, flags); + } + pnode->logo_waitq = NULL; + spin_unlock_irqrestore(&pnode->lock, flags); + status = SUCCESS; + } else { + status = FAILED; + spin_unlock_irqrestore(&pnode->lock, flags); + } lpfc_printf_vlog(vport, KERN_ERR, logit, "0723 SCSI layer issued Target Reset (%d, %llu) "