git: e35816c1c909 - main - mpr/mps: Fix a race in diagnostic reset

From: Warner Losh <imp_at_FreeBSD.org>
Date: Wed, 26 Jan 2022 02:16:11 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=e35816c1c9094804f5a4b5f7b34f920f78cff5bd

commit e35816c1c9094804f5a4b5f7b34f920f78cff5bd
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2022-01-25 23:23:03 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2022-01-26 02:15:46 +0000

    mpr/mps: Fix a race in diagnostic reset
    
    There's a small race in freezing the simq when performing a diagnostic
    reset. During this time, a transaction can slip through and encounter
    the target id of 0. If we're still in diagnostic reset when we detect
    this, return a CAM_DEVICE_NOT_THERE status. Instead, freeze the queue
    and return a requeue status, similar to what we do when we're resetting
    a target and a transaction get here. The race is unavoidable due to
    separate locks for queue and SIM, but easy enough to detect and make
    harmless.
    
    Sponsored by:           Netflix
    Reviewed by:            scottl, mav
    Differential Revision:  https://reviews.freebsd.org/D34017
---
 sys/dev/mpr/mpr_sas.c | 9 +++++++++
 sys/dev/mps/mps_sas.c | 9 +++++++++
 2 files changed, 18 insertions(+)

diff --git a/sys/dev/mpr/mpr_sas.c b/sys/dev/mpr/mpr_sas.c
index 4a8dccb18538..d40900e03108 100644
--- a/sys/dev/mpr/mpr_sas.c
+++ b/sys/dev/mpr/mpr_sas.c
@@ -1864,6 +1864,15 @@ mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb)
 	targ = &sassc->targets[csio->ccb_h.target_id];
 	mpr_dprint(sc, MPR_TRACE, "ccb %p target flag %x\n", ccb, targ->flags);
 	if (targ->handle == 0x0) {
+		if (targ->flags & MPRSAS_TARGET_INDIAGRESET) {
+			mpr_dprint(sc, MPR_ERROR,
+			    "%s NULL handle for target %u in diag reset freezing queue\n",
+			    __func__, csio->ccb_h.target_id);
+			ccb->ccb_h.status = CAM_REQUEUE_REQ | CAM_DEV_QFRZN;
+			xpt_freeze_devq(ccb->ccb_h.path, 1);
+			xpt_done(ccb);
+			return;
+		}
 		mpr_dprint(sc, MPR_ERROR, "%s NULL handle for target %u\n", 
 		    __func__, csio->ccb_h.target_id);
 		mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
diff --git a/sys/dev/mps/mps_sas.c b/sys/dev/mps/mps_sas.c
index e55c4978208a..087988bedc6a 100644
--- a/sys/dev/mps/mps_sas.c
+++ b/sys/dev/mps/mps_sas.c
@@ -1637,6 +1637,15 @@ mpssas_action_scsiio(struct mpssas_softc *sassc, union ccb *ccb)
 	targ = &sassc->targets[csio->ccb_h.target_id];
 	mps_dprint(sc, MPS_TRACE, "ccb %p target flag %x\n", ccb, targ->flags);
 	if (targ->handle == 0x0) {
+		if (targ->flags & MPSSAS_TARGET_INDIAGRESET) {
+			mps_dprint(sc, MPS_ERROR,
+			    "%s NULL handle for target %u in diag reset freezing queue\n",
+			    __func__, csio->ccb_h.target_id);
+			ccb->ccb_h.status = CAM_REQUEUE_REQ | CAM_DEV_QFRZN;
+			xpt_freeze_devq(ccb->ccb_h.path, 1);
+			xpt_done(ccb);
+			return;
+		}
 		mps_dprint(sc, MPS_ERROR, "%s NULL handle for target %u\n", 
 		    __func__, csio->ccb_h.target_id);
 		mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);