# DF-3802 — TM error-path early returns wedge the target forever and leak the TM

- File: `sys/dev/raid/mpr/mpr_sas.c`
- Class: unkillable I/O hang (ccb never completed) + high-priority command leak
- Severity: Medium / Confidence: likely
- Status on guest: not_reproduced — no SAS3 HBA (see `env.txt`)

## Defect

`mprsas_send_abort` and `mprsas_send_reset` have early `-1` return paths that
neither free the task-management command nor clear `targ->tm`:

- `mpr_sas.c:1609-1615` — `send_abort`: `targ = cm->cm_targ; if (targ->handle == 0) return -1;`
- `mpr_sas.c:1456-1461` — `send_reset`: `if (target->handle == 0) ... return -1;`
- `mpr_sas.c:1489-1492` — `send_reset`: unknown type → `return -1`

Every caller ignores the return value:

- `mpr_sas.c:1731` (`mprsas_scsiio_timeout`: `targ->tm = mprsas_alloc_tm(sc); ... mprsas_send_abort(sc, targ->tm, cm);`)
- `mpr_sas.c:1351`, `mpr_sas.c:1584` (`mprsas_send_abort` re-arm from
  `logical_unit_reset_complete` / `abort_complete`)
- `mpr_sas.c:1365`, `mpr_sas.c:1594` (`mprsas_send_reset` escalation)

After the early return:

1. `targ->tm` remains set forever (only the TM *completion* handlers clear it —
   `mpr_sas.c:1307/1353/1403/1431/1553/1578` — and the TM was never sent, so it
   never completes; `mprsas_free_tm` is never called).
2. The timed-out command stays on `targ->timedout_commands` in state
   `MPR_CM_STATE_TIMEDOUT` with its ccb **never completed** — once a ccb is in
   the SIM, CAM has no further timeout for it; the issuing thread hangs forever.
3. Every subsequent timeout on the target takes the `targ->tm != NULL` path
   (`mpr_sas.c:1716-1722`) and piles more never-aborted commands.
4. The allocated high-priority command leaks (pool shrink under repetition).

## Reachable trigger (provable sequence)

Outstanding I/O to a **RAID volume** that is deleted:

- `mprsas_prepare_volume_remove` sends the reset TM (`mpr_sas.c:439-490`), but
  `mprsas_remove_volume` clears `targ->handle = 0` on success
  (`mpr_sas.c:411-429`) **without draining `targ->commands`** — unlike
  `mprsas_remove_device`, which completes them (`mpr_sas.c:621-628`).
- Any command still on `targ->commands` that times out afterwards runs
  `mprsas_scsiio_timeout` → allocates `targ->tm` → `mprsas_send_abort` sees
  `targ->handle == 0` → returns `-1` → wedge + leak, per above.

The same wedge occurs mid-error-recovery when the handle is cleared while a
recovery TM exists (abort escalation at `mpr_sas.c:1584/1594`).

## Fix

Handle the `-1` returns: free the TM, clear `targ->tm`, and complete the
timed-out ccbs with `CAM_DEV_NOT_THERE`; also drain `targ->commands` in
`mprsas_remove_volume` like `mprsas_remove_device` does. See `fix.diff`.

## Guest verification

No SAS3 controller in the guest; no mpr SIM registered → the sequence cannot
run. Static proof stands. See `env.txt`.

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
