# DF-3951 — mlx_start() wedge path leaks mlx_busycmds (slot-count never decremented) and leaves the DMA map loaded

**Severity:** Low · **CWE-772 / resource-accounting** · hardware-gated
(controller must stop accepting mailbox writes)

## Bug

When the controller refuses every mailbox write (the 100000-iteration spin
at mlx.c:2089-2097 fails), `mlx_start()` revokes the slot on the error path:

```c
    sc->mlx_busycmd[mc->mc_slot] = NULL;          /* mlx.c:2107 */
    device_printf(sc->mlx_dev, "controller wedged (not taking commands)\n");
    mc->mc_status = MLX_STATUS_WEDGED;
```

but **forgets `sc->mlx_busycmds--`**. The only decrement in the driver is in
`mlx_done()` (mlx.c:2146), which only runs for commands the controller
completed. Each wedged submission therefore permanently inflates
`mlx_busycmds`:

- `mlx_getslot()` (mlx.c:1966) refuses new commands once
  `mlx_busycmds >= limit - 4` (normal) / `>= limit` (priority) — after a
  handful of wedge events **all future I/O returns EBUSY forever**:
  `mlx_startio()` breaks out (mlx.c:1739-1742), every read/write to the
  mlx drives fails, and even MLX_COMMAND management ioctls are locked out.
  No recovery path exists short of a reboot.

Additionally, on the `mlx_startio()` wedge path the command's DMA map is
never unloaded: `mlx_unmapcmd()` is only called from `mlx_complete()`
(mlx.c:2194) for commands that reached the work queue; the WEDGED command
never did, and `mlx_completeio()` (mlx.c:1796-1800 → 1839) releases the
command with `mc->mc_data` still mapped. The recycled command's map is then
re-loaded by a later `mlx_mapcmd()` without an intervening unload.

## Build / Run / Expected

```sh
cc -O2 -Wall -o mlx_ioctl_trigger mlx_ioctl_trigger.c
./mlx_ioctl_trigger wedge /dev/mlx0   # against a controller that stopped taking commands
dd if=/dev/mlxd0 of=/dev/null bs=64k count=1   # -> EBUSY permanently
```
Expected on hardware: after N wedge events, `dd` fails and all mlx I/O
returns EBUSY until reboot. On this guest: ENOENT (no HBA) — hardware-gated.

## Fix

Decrement `mlx_busycmds` alongside the slot clear (fix.diff).
