# DF-4214 — RAID reply handler deregistration is not refcounted: detaching one mpt(4) controller breaks the other's RAID completion path

- **File**: `sys/dev/disk/mpt/mpt_raid.c` (lifetime; interacts with `sys/dev/disk/mpt/mpt.c:402-478`)
- **Lines**: 135 (static id), 291–297 (attach register), 338–340 (detach deregister)
- **Class**: shared-resource lifetime bug (CWE-666/CWE-404) → request leak / unkillable hang on surviving controller
- **Preconditions**: ≥2 mpt(4) RAID controllers; one detached (hot-removal/kldunload path) while the other runs RAID activity

## Root cause

`mpt_reply_handlers[]` is a **global** table shared by all mpt controllers
(`mpt.c:119`). Registration is deliberately idempotent: a second controller
registering the same function gets the *same* slot back
(`mpt.c:417-426`: "If the same handler is registered multiple times, don't
error out"). Deregistration, however, is unconditional and un-refcounted
(`mpt.c:466-471`) — and `mpt_raid_detach()` calls it for the shared
`raid_handler_id` (`mpt_raid.c:338-340`, `raid_handler_id` is a file-static
at `mpt_raid.c:135`).

So: ctrl1 attach → slot X = mpt_raid_reply_handler; ctrl2 attach → reuses X
(no count); **ctrl1 detach → slot X cleared**; ctrl2 keeps issuing RAID
actions with `MsgContext = index | raid_handler_id` (`mpt_raid.c:616`).

## Consequence on the surviving controller

Late replies for ctrl2's RAID actions now dispatch to
`mpt_default_reply_handler` (`mpt.c:480-495`), which only prints and returns
— it never completes, dequeues, or frees the request. Every RAID action on
ctrl2 then:

- times out after the 2 s busy-poll (`mpt_wait_req`, sleep_ok=FALSE) and is
  either **leaked forever on `request_pending_list`** (mpt_verify_mwce /
  mpt_verify_resync_rate paths), or freed-while-pending (the DF-4211 bug),
- drains the 512-entry request pool until `mpt_get_request(sleep_ok=TRUE)`
  blocks forever in non-interruptible `mpt_sleep` — wedging the RAID thread
  and any thread touching the `vol_member_wce`/`vol_resync_rate` sysctls
  (unkillable local DoS from what should be a scoped device event).

## Verification status

**untested — hardware-gated** (needs two MPT Fusion HBAs; guest has none,
`env.txt`). Source-certain.

## Fix

`fix.diff`: reference-count the personality's registration
(`raid_handler_refs`) and only deregister when the last controller detaches.
