mirror of
https://github.com/torvalds/linux.git
synced 2024-12-18 09:02:17 +00:00
scsi: lpfc: Fix target reset failing
Target reset is failed by the target as an invalid command. The Target Reset TMF has been obsoleted in T10 for a while, but continues to be used. On (newer) devices, the TMF is rejected causing the reset handler to escalate to adapter resets. Fix by having Target Reset TMF rejections be translated into a LOGO and re-PLOGI with the target device. This provides the same semantic action (although, if the device also supports nvme traffic, it will terminate nvme traffic as well - but it's still recoverable). Link: https://lore.kernel.org/r/20210104180240.46824-10-jsmart2021@gmail.com Co-developed-by: Dick Kennedy <dick.kennedy@broadcom.com> Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com> Signed-off-by: James Smart <jsmart2021@gmail.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
da09ae4864
commit
31051249f1
@ -135,14 +135,17 @@ struct lpfc_nodelist {
|
|||||||
struct lpfc_scsicmd_bkt *lat_data; /* Latency data */
|
struct lpfc_scsicmd_bkt *lat_data; /* Latency data */
|
||||||
uint32_t fc4_prli_sent;
|
uint32_t fc4_prli_sent;
|
||||||
uint32_t fc4_xpt_flags;
|
uint32_t fc4_xpt_flags;
|
||||||
|
uint32_t upcall_flags;
|
||||||
#define NLP_WAIT_FOR_UNREG 0x1
|
#define NLP_WAIT_FOR_UNREG 0x1
|
||||||
#define SCSI_XPT_REGD 0x2
|
#define SCSI_XPT_REGD 0x2
|
||||||
#define NVME_XPT_REGD 0x4
|
#define NVME_XPT_REGD 0x4
|
||||||
|
#define NLP_WAIT_FOR_LOGO 0x2
|
||||||
|
|
||||||
|
|
||||||
uint32_t nvme_fb_size; /* NVME target's supported byte cnt */
|
uint32_t nvme_fb_size; /* NVME target's supported byte cnt */
|
||||||
#define NVME_FB_BIT_SHIFT 9 /* PRLI Rsp first burst in 512B units. */
|
#define NVME_FB_BIT_SHIFT 9 /* PRLI Rsp first burst in 512B units. */
|
||||||
uint32_t nlp_defer_did;
|
uint32_t nlp_defer_did;
|
||||||
|
wait_queue_head_t *logo_waitq;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lpfc_node_rrq {
|
struct lpfc_node_rrq {
|
||||||
|
@ -2817,6 +2817,7 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
IOCB_t *irsp;
|
IOCB_t *irsp;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
uint32_t skip_recovery = 0;
|
uint32_t skip_recovery = 0;
|
||||||
|
int wake_up_waiter = 0;
|
||||||
|
|
||||||
/* we pass cmdiocb to state machine which needs rspiocb as well */
|
/* we pass cmdiocb to state machine which needs rspiocb as well */
|
||||||
cmdiocb->context_un.rsp_iocb = rspiocb;
|
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);
|
irsp = &(rspiocb->iocb);
|
||||||
spin_lock_irq(&ndlp->lock);
|
spin_lock_irq(&ndlp->lock);
|
||||||
ndlp->nlp_flag &= ~NLP_LOGO_SND;
|
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);
|
spin_unlock_irq(&ndlp->lock);
|
||||||
|
|
||||||
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
|
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
|
||||||
@ -2889,6 +2894,8 @@ out:
|
|||||||
* Initiator, we are assuming the NPortID is not going to change.
|
* 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.
|
* 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
|
* For any other port type, the rpi is unregistered as an implicit
|
||||||
|
@ -5924,6 +5924,8 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd)
|
|||||||
struct lpfc_scsi_event_header scsi_event;
|
struct lpfc_scsi_event_header scsi_event;
|
||||||
int status;
|
int status;
|
||||||
u32 logit = LOG_FCP;
|
u32 logit = LOG_FCP;
|
||||||
|
unsigned long flags;
|
||||||
|
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
|
||||||
|
|
||||||
rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
|
rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
|
||||||
if (!rdata || !rdata->pnode) {
|
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,
|
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
|
||||||
"0722 Target Reset rport failure: rdata x%px\n", rdata);
|
"0722 Target Reset rport failure: rdata x%px\n", rdata);
|
||||||
if (pnode) {
|
if (pnode) {
|
||||||
spin_lock_irq(&pnode->lock);
|
spin_lock_irqsave(&pnode->lock, flags);
|
||||||
pnode->nlp_flag &= ~NLP_NPR_ADISC;
|
pnode->nlp_flag &= ~NLP_NPR_ADISC;
|
||||||
pnode->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
|
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_reset_flush_io_context(vport, tgt_id, lun_id,
|
||||||
LPFC_CTX_TGT);
|
LPFC_CTX_TGT);
|
||||||
@ -5965,6 +5967,38 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd)
|
|||||||
FCP_TARGET_RESET);
|
FCP_TARGET_RESET);
|
||||||
if (status != SUCCESS)
|
if (status != SUCCESS)
|
||||||
logit = LOG_TRACE_EVENT;
|
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,
|
lpfc_printf_vlog(vport, KERN_ERR, logit,
|
||||||
"0723 SCSI layer issued Target Reset (%d, %llu) "
|
"0723 SCSI layer issued Target Reset (%d, %llu) "
|
||||||
|
Loading…
Reference in New Issue
Block a user