⬢ DragonFlyBSD Kernel Audit
DF-3895 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/raid/mps/mps_sas.c b/sys/dev/raid/mps/mps_sas.c
index 1111111..2222222 100644
--- a/sys/dev/raid/mps/mps_sas.c
+++ b/sys/dev/raid/mps/mps_sas.c
@@ -1300,10 +1300,24 @@ mpssas_send_reset(struct mps_softc *sc, struct mps_command *tm, uint8_t type)
 	int err;
 
 	target = tm->cm_targ;
 	if (target->handle == 0) {
 		mps_printf(sc, "%s null devhandle for target_id %d\n",
 		    __func__, target->tid);
+		/* DF-3895: unwinding is mandatory — returning without it
+		 * wedges the target forever (targ->tm stays set, timedout
+		 * commands are never completed) and leaks the TM. */
+		target->tm = NULL;
+		mpssas_free_tm(sc, tm);
+		{
+			struct mps_command *tcm, *tnext;
+			TAILQ_FOREACH_MUTABLE(tcm, &target->timedout_commands,
+			    cm_recovery, tnext) {
+				union ccb *tccb = tcm->cm_complete_data;
+				TAILQ_REMOVE(&target->timedout_commands, tcm,
+				    cm_recovery);
+				tcm->cm_state = MPS_CM_STATE_BUSY;
+				tccb->ccb_h.status = CAM_DEV_NOT_THERE;
+				mpssas_scsiio_complete(sc, tcm);
+			}
+		}
 		return -1;
 	}
 
 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
diff --git a/sys/dev/raid/mps/mps_sas.c b/sys/dev/raid/mps/mps_sas.c
index 1111111..3333333 100644
--- a/sys/dev/raid/mps/mps_sas.c
+++ b/sys/dev/raid/mps/mps_sas.c
@@ -1440,10 +1440,25 @@ mpssas_send_abort(struct mps_softc *sc, struct mps_command *tm, struct mps_command *cm)
 	int err;
 
 	targ = cm->cm_targ;
 	if (targ->handle == 0) {
 		mps_printf(sc, "%s null devhandle for target_id %d\n",
 		    __func__, cm->cm_ccb->ccb_h.target_id);
+		/* DF-3895: same unwind as mpssas_send_reset. */
+		targ->tm = NULL;
+		mpssas_free_tm(sc, tm);
+		{
+			struct mps_command *tcm, *tnext;
+			TAILQ_FOREACH_MUTABLE(tcm, &targ->timedout_commands,
+			    cm_recovery, tnext) {
+				union ccb *tccb = tcm->cm_complete_data;
+				TAILQ_REMOVE(&targ->timedout_commands, tcm,
+				    cm_recovery);
+				tcm->cm_state = MPS_CM_STATE_BUSY;
+				tccb->ccb_h.status = CAM_DEV_NOT_THERE;
+				mpssas_scsiio_complete(sc, tcm);
+			}
+		}
 		return -1;
 	}
 
 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
diff --git a/sys/dev/raid/mps/mps_sas.c b/sys/dev/raid/mps/mps_sas.c
index 1111111..4444444 100644
--- a/sys/dev/raid/mps/mps_sas.c
+++ b/sys/dev/raid/mps/mps_sas.c
@@ -384,6 +384,19 @@ mpssas_remove_volume(struct mps_softc *sc, struct mps_command *tm)
 		targ->linkrate = 0x0;
 		targ->devinfo = 0x0;
 		targ->flags = 0x0;
+
+		/* DF-3895: drain outstanding commands exactly like
+		 * mpssas_remove_device does; otherwise later timeouts on
+		 * this dead volume wedge error recovery in
+		 * mpssas_send_abort's handle==0 path. */
+		TAILQ_FOREACH_MUTABLE(cm, &targ->commands, cm_link, next_cm) {
+			union ccb *ccb;
+
+			ccb = cm->cm_complete_data;
+			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
+			mpssas_scsiio_complete(sc, cm);
+		}
 	}
 
 	mpssas_free_tm(sc, tm);
*** NOTE: the third hunk requires promoting `next_cm` in
*** mpssas_remove_volume's declarations
*** (struct mps_command *next_cm, *cm;) — mps_sas.c:350-352 currently
*** declares only `reply`/`targ`/`handle`; the function-local shadow of the
*** remove_device pattern (cf. mps_sas.c:592-599) is intended.