# DF-3894 — XPT_RESET_DEV allocates a regular-pool command but frees it via the high-priority list, and underflows tm_count: both command pools corrupted, TM simq-freeze discipline permanently disabled

File: `sys/dev/raid/mps/mps_sas.c` (pass 2). Twin of DF-1223 (filed against
mpr_sas.c; the mpt-era original of the same pattern).

## What

`mpssas_action_resetdev` allocates its task-management command from the
**normal** pool:

```c
        tm = mps_alloc_command(sc);            /* mps_sas.c:2765 — pops sc->req_list */
```

but the completion handler frees it through the TM helper, which pushes onto
the **high-priority** pool and decrements the TM refcount that this command
never incremented:

```c
 bailout:
        mpssas_free_tm(sc, tm);                /* mps_sas.c:2832 */
```
```c
 mpssas_free_tm(...):
        if (--sc->sassc->tm_count == 0) {      /* mps_sas.c:262 — 0 -> UINT_MAX */
                xpt_release_simq(...);
        }
        mps_free_high_priority_command(sc, tm);/* mps_sas.c:269 — pushes high_priority_req_list */
```

Pools (`sys/dev/raid/mps/mpsvar.h`):
- `mps_alloc_command` pops `sc->req_list` (mpsvar.h:543-555)
- `mps_free_high_priority_command` inserts into
  `sc->high_priority_req_list` (mpsvar.h:558-577)
- At init, SMIDs `<= facts->HighPriorityCredit` are seeded onto the hp list
  and the rest onto the normal list (mps.c:864-867).

`tm_count` is `u_int` (`sys/dev/raid/mps/mps_sas.h:100`); XPT_RESET_DEV never
calls `mpssas_alloc_tm` (which is what increments it, mps_sas.c:242), so the
decrement in `mpssas_free_tm` underflows 0 → 0xFFFFFFFF.

## Impact (three coupled effects, all persistent)

1. **Pool accounting corruption**: the normal `req_list` permanently loses
   one command per XPT_RESET_DEV (SMID leak), and `high_priority_req_list`
   gains an SMID above the firmware's HighPriorityCredit budget. Repeated
   device resets (normal CAM error recovery on a flaky disk) drain the
   normal pool until `mps_alloc_command` returns NULL → all I/O on the
   adapter fails (CAM_RESRC_UNAVAIL storm). A later `mpssas_alloc_tm` can
   hand out the mis-pooled SMID, sending a high-priority request whose SMID
   is outside the high-priority credit range — undefined firmware behavior.
2. **tm_count poisoned forever**: after the underflow, `tm_count` wraps
   through UINT_MAX; subsequent `mpssas_alloc_tm` no longer sees the
   0→1 transition (`if (sc->sassc->tm_count++ == 0)`, mps_sas.c:242), so
   **the simq is never frozen while task management is in flight** —
   violating the exact invariant the refcount exists for ("LSI's firmware
   requires us to stop sending commands when we're doing task management",
   mps_sas.c:231-234) — and `mpssas_free_tm` never releases it either
   (balance is preserved only by both sides being broken).
3. The underflowed refcount also breaks any future legitimate freeze
   accounting after a diag reset cleanup walks the tm list.

Trigger: XPT_RESET_DEV reaching the SIM — issued by CAM periph error
recovery (da(4) escalating timeouts) or `camcontrol reset <dev>` (root).
No special race required; every single occurrence corrupts the pools.

## Build/run

`run.sh` records the hardware gate. Source-level certainty: total.

## Fix

Allocate the TM with `mpssas_alloc_tm()` (balanced against
`mpssas_free_tm`, freezes the simq per the driver's own TM discipline), and
zero the reused request frame while at it (mpssas_action_resetdev is the
only TM sender that does not `memset` its req — mps_sas.c:512-513,
579 contrast). See fix.diff.
