From e35816c1c9094804f5a4b5f7b34f920f78cff5bd Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Tue, 25 Jan 2022 16:23:03 -0700 Subject: [PATCH] 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);