Commit 3e49af93 authored by James Smart's avatar James Smart Committed by Martin K. Petersen
Browse files

scsi: lpfc: Add a option to enable interlocked ABTS before job completion

Default behavior for the driver, when aborting an I/O, is to terminate the
I/O with the adapter. The adapter will initiate an ABTS to terminate the
exchange on the link and mark the exchange is terminated so that no further
use of the sgl or any traffic for the exchange is worked on. Completion on
the Abort is then posted to the driver, which as the I/O is terminated can
complete the I/O to the OS. This completion may occur prior to the ABTS
handshake completing on the wire. The ABTS handshake can take a long time
to complete with timeouts and retries reaching 60+ seconds. Note: if
retries fail, LOGO occurs.

Some devices want to ensure that the ABTS handshake fully completes (this
device has fully ack'd it) before the I/O completion is posted back to the
OS, where a failed I/O may be retried via a different path.

To support this behavior, an option was added to the driver to change I/O
completion from the Abort cmd completion to the Exchange termination (aka
ABTS) completion.

Link: https://lore.kernel.org/r/20210514195559.119853-10-jsmart2021@gmail.com


Co-developed-by: default avatarJustin Tee <justin.tee@broadcom.com>
Signed-off-by: default avatarJustin Tee <justin.tee@broadcom.com>
Signed-off-by: default avatarJames Smart <jsmart2021@gmail.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 5aa615d1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -915,6 +915,7 @@ struct lpfc_hba {
	uint32_t cfg_request_firmware_upgrade;
	uint32_t cfg_suppress_link_up;
	uint32_t cfg_rrq_xri_bitmap_sz;
	u32      cfg_fcp_wait_abts_rsp;
	uint32_t cfg_delay_discovery;
	uint32_t cfg_sli_mode;
#define LPFC_INITIALIZE_LINK              0	/* do normal init_link mbox */
+11 −0
Original line number Diff line number Diff line
@@ -3448,6 +3448,15 @@ LPFC_ATTR_R(enable_npiv, 1, 0, 1,
LPFC_ATTR_R(fcf_failover_policy, 1, 1, 2,
	"FCF Fast failover=1 Priority failover=2");

/*
 * lpfc_fcp_wait_abts_rsp: Modifies criteria for reporting completion of
 * aborted IO.
 * The range is [0,1]. Default value is 0
 *      0, IO completes after ABTS issued (default).
 *      1, IO completes after receipt of ABTS response or timeout.
 */
LPFC_ATTR_R(fcp_wait_abts_rsp, 0, 0, 1, "Wait for FCP ABTS completion");

/*
# lpfc_enable_rrq: Track XRI/OXID reuse after IO failures
#	0x0 = disabled, XRI/OXID use not tracked.
@@ -6205,6 +6214,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
	&dev_attr_lpfc_enable_npiv,
	&dev_attr_lpfc_fcf_failover_policy,
	&dev_attr_lpfc_enable_rrq,
	&dev_attr_lpfc_fcp_wait_abts_rsp,
	&dev_attr_nport_evt_cnt,
	&dev_attr_board_mode,
	&dev_attr_max_vpi,
@@ -7332,6 +7342,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
	lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
	lpfc_fcf_failover_policy_init(phba, lpfc_fcf_failover_policy);
	lpfc_enable_rrq_init(phba, lpfc_enable_rrq);
	lpfc_fcp_wait_abts_rsp_init(phba, lpfc_fcp_wait_abts_rsp);
	lpfc_fdmi_on_init(phba, lpfc_fdmi_on);
	lpfc_enable_SmartSAN_init(phba, lpfc_enable_SmartSAN);
	lpfc_use_msi_init(phba, lpfc_use_msi);
+2 −1
Original line number Diff line number Diff line
@@ -522,6 +522,7 @@ lpfc_init_link(struct lpfc_hba * phba,
	}

	/* Enable asynchronous ABTS responses from firmware */
	if (phba->sli_rev == LPFC_SLI_REV3 && !phba->cfg_fcp_wait_abts_rsp)
		mb->un.varInitLnk.link_flags |= FLAGS_IMED_ABORT;

	/* NEW_FEATURE
+39 −6
Original line number Diff line number Diff line
@@ -518,6 +518,7 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba,
	struct lpfc_nodelist *ndlp;
	int rrq_empty = 0;
	struct lpfc_sli_ring *pring = phba->sli4_hba.els_wq->pring;
	struct scsi_cmnd *cmd;

	if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP))
		return;
@@ -553,6 +554,31 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba,
					psb->cur_iocbq.sli4_lxritag, rxid, 1);
				lpfc_sli4_abts_err_handler(phba, ndlp, axri);
			}

			if (phba->cfg_fcp_wait_abts_rsp) {
				spin_lock_irqsave(&psb->buf_lock, iflag);
				cmd = psb->pCmd;
				psb->pCmd = NULL;
				spin_unlock_irqrestore(&psb->buf_lock, iflag);

				/* The sdev is not guaranteed to be valid post
				 * scsi_done upcall.
				 */
				if (cmd)
					cmd->scsi_done(cmd);

				/*
				 * We expect there is an abort thread waiting
				 * for command completion wake up the thread.
				 */
				spin_lock_irqsave(&psb->buf_lock, iflag);
				psb->cur_iocbq.iocb_flag &=
					~LPFC_DRIVER_ABORTED;
				if (psb->waitq)
					wake_up(psb->waitq);
				spin_unlock_irqrestore(&psb->buf_lock, iflag);
			}

			lpfc_release_scsi_buf_s4(phba, psb);
			if (rrq_empty)
				lpfc_worker_wake_up(phba);
@@ -780,6 +806,7 @@ lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *psb)
	qp = psb->hdwq;
	if (psb->flags & LPFC_SBUF_XBUSY) {
		spin_lock_irqsave(&qp->abts_io_buf_list_lock, iflag);
		if (!phba->cfg_fcp_wait_abts_rsp)
			psb->pCmd = NULL;
		list_add_tail(&psb->list, &qp->lpfc_abts_io_buf_list);
		qp->abts_scsi_io_bufs++;
@@ -4045,6 +4072,7 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
	u32 logit = LOG_FCP;
	u32 status, idx;
	unsigned long iflags = 0;
	u8 wait_xb_clr = 0;

	/* Sanity check on return of outstanding command */
	if (!lpfc_cmd) {
@@ -4096,8 +4124,11 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
	lpfc_cmd->result = (wcqe->parameter & IOERR_PARAM_MASK);

	lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY;
	if (bf_get(lpfc_wcqe_c_xb, wcqe))
	if (bf_get(lpfc_wcqe_c_xb, wcqe)) {
		lpfc_cmd->flags |= LPFC_SBUF_XBUSY;
		if (phba->cfg_fcp_wait_abts_rsp)
			wait_xb_clr = 1;
	}

#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
	if (lpfc_cmd->prot_data_type) {
@@ -4329,6 +4360,8 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
		lpfc_io_ktime(phba, lpfc_cmd);
	}
#endif
	if (wait_xb_clr)
		goto out;
	lpfc_cmd->pCmd = NULL;
	spin_unlock(&lpfc_cmd->buf_lock);

@@ -4343,8 +4376,8 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
	lpfc_cmd->cur_iocbq.iocb_flag &= ~LPFC_DRIVER_ABORTED;
	if (lpfc_cmd->waitq)
		wake_up(lpfc_cmd->waitq);
out:
	spin_unlock(&lpfc_cmd->buf_lock);

	lpfc_release_scsi_buf(phba, lpfc_cmd);
}

@@ -4398,11 +4431,10 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,

	lpfc_cmd->result = (pIocbOut->iocb.un.ulpWord[4] & IOERR_PARAM_MASK);
	lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
	/* pick up SLI4 exhange busy status from HBA */
	/* pick up SLI4 exchange busy status from HBA */
	lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY;
	if (pIocbOut->iocb_flag & LPFC_EXCHANGE_BUSY)
		lpfc_cmd->flags |= LPFC_SBUF_XBUSY;
	else
		lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY;

#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
	if (lpfc_cmd->prot_data_type) {
@@ -4601,6 +4633,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
		lpfc_io_ktime(phba, lpfc_cmd);
	}
#endif

	/* The sdev is not guaranteed to be valid post scsi_done upcall. */
	cmd->scsi_done(cmd);