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).