⬢ DragonFlyBSD Kernel Audit
DF-3802 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/raid/mpr/mpr_sas.c b/sys/dev/raid/mpr/mpr_sas.c
index 1111111..2222222 100644
--- a/sys/dev/raid/mpr/mpr_sas.c
+++ b/sys/dev/raid/mpr/mpr_sas.c
@@ -1601,10 +1601,22 @@ mprsas_send_abort(struct mpr_softc *sc, struct mpr_command *tm,
 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
 	struct mprsas_target *targ;
 	int err;
 
 	targ = cm->cm_targ;
 	if (targ->handle == 0) {
 		mpr_dprint(sc, MPR_ERROR|MPR_RECOVERY,
 		   "%s null devhandle for target_id %d\n",
 		    __func__, cm->cm_ccb->ccb_h.target_id);
+		/*
+		 * DF-3802: returning without unwinding wedges the target
+		 * forever (targ->tm stays set, the timedout command is
+		 * never completed) and leaks the TM.
+		 */
+		targ->tm = NULL;
+		mprsas_free_tm(sc, tm);
+		while ((cm = TAILQ_FIRST(&targ->timedout_commands)) != NULL) {
+			union ccb *ccb = cm->cm_complete_data;
+			TAILQ_REMOVE(&targ->timedout_commands, cm, cm_recovery);
+			cm->cm_state = MPR_CM_STATE_BUSY;
+			mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
+			mprsas_scsiio_complete(sc, cm);
+		}
 		return -1;
 	}
diff --git a/sys/dev/raid/mpr/mpr_sas.c b/sys/dev/raid/mpr/mpr_sas.c
index 1111111..3333333 100644
--- a/sys/dev/raid/mpr/mpr_sas.c
+++ b/sys/dev/raid/mpr/mpr_sas.c
@@ -405,6 +405,20 @@ mprsas_remove_volume(struct mpr_softc *sc, struct mpr_command *tm)
 		targ->flags = 0x0;
 		targ->scsi_req_desc_type = 0;
+
+		/*
+		 * DF-3802: drain outstanding commands like
+		 * mprsas_remove_device does; otherwise a later timeout on a
+		 * command for this dead volume wedges error recovery
+		 * (send_abort -1 with handle == 0).
+		 */
+		TAILQ_FOREACH_MUTABLE(cm, &targ->commands, cm_link, next_cm) {
+			union ccb *ccb;
+
+			ccb = cm->cm_complete_data;
+			mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
+			mprsas_scsiio_complete(sc, cm);
+		}
 	}
*** NOTE: the second hunk requires promoting `next_cm` in
*** mprsas_remove_volume's declarations (struct mpr_command *next_cm, *cm).