# DF-5367 — ufoma uninterruptible mode-switch ACK waits stall the USB hub event thread at detach (up to ~16-18 s)

## What (finding in one line)

`ufoma_cfg_open()` / `ufoma_cfg_close()` block in `cv_timedwait(&sc->sc_cv,
&sc->sc_lock, …)` for up to **1 s** (`ufoma_cfg_link_state`, sys/bus/u4b/serial/ufoma.c:527)
plus **15 s** (`ufoma_cfg_activate_state`, ufoma.c:549-550 — `UFOMA_MAX_TIMEOUT`),
with **no abort when the device is removed or the ucom process is draining**.
The only wakeup source is the ACK notification handled in
`ufoma_intr_callback()` (ufoma.c:689-697); on unplug the interrupt xfer is
merely *cancelled* (ufoma.c:601,647,759) and nobody signals `sc_cv`.
When unplug races an in-flight open/close cfg task, `ufoma_detach()`
(ufoma.c:476) → `ucom_detach()` → `usb_proc_drain()` (usb_serial.c:394)
blocks the **USB hub event thread** for the remainder of the wait —
measured **13.005 s** for an unplug 2 s into the 15 s wait — delaying all
USB event processing system-wide, repeatable per insertion cycle.

## Why this guest can't run the full path (evidence class)

`ufoma` probes on USB interface class `UICLASS_CDC` (0x02) / subclass
`UISUBCLASS_MCPC` (0x88) (ufoma.c:114,314-317). The audit QEMU guest's
usb-serial attaches but binds `uftdi` (proven in DF-5359) — no MCPC device
can enumerate. Per the sanctioned evidence classes, verification is a
**KLD harness compiled from production code**: it drives the *same*
in-kernel `usb_process` machinery (`usb_proc_create` / `usb_proc_msignal`
/ `usb_proc_drain`) that `ufoma_detach()`'s `ucom_detach()` goes through,
with a cfg task performing exactly ufoma.c:549's `cv_timedwait(15*hz)`.

## Build

    # on the guest (DragonFly 6.5-DEVELOPMENT, /usr/src present):
    mkdir -p /usr/src/sys/bus/u4b/serial/hx5367
    cp ufoma_drain_harness.c Makefile /usr/src/sys/bus/u4b/serial/hx5367/
    sh build.sh          # in-tree kmod build, -Werror clean

## Run

    sh run.sh            # kldload ./ufoharness.ko; kldunload; dmesg

## Expected output (decisive lines)

    HX: DF-5367 ufoma detach-stall harness, hz=100
    HX[A] cfg-task: enter t=1791032834, cv_timedwait(15*hz), no abort on gone
    HX[A] unplug done, usb_proc_drain() begin t=1791032836
    HX[A] cfg-task: leave t=1791032849
    HX[A] usb_proc_drain() done t=1791032849  ELAPSED=13000 ms ...
    HX[B] cfg-task(fixed): enter t=1791032849, 1s slices + dying
    HX[B] unplug done, usb_proc_drain() begin t=1791032851
    HX[B] usb_proc_drain() done t=1791032851  ELAPSED=0 ms ...

Phase A (baseline) MUST show `ELAPSED` ≈ (15 − lead-in) seconds.
Phase B (fix mechanism from `fix.diff`) MUST show `ELAPSED` ≈ 0 ms.
Run 2 confirmed stability: `ELAPSED=13005 ms` / `0 ms`.

## Artifacts

* `ufoma_drain_harness.c` — the KLD harness (annotated with the ufoma.c lines it mirrors)
* `Makefile`, `build.sh`, `run.sh`
* `build.log`, `run.log`, `run.1.log`, `run.2.log`, `env.txt`
* `fix.diff` — git-apply-able against `sys/` (verified: `git apply --check` passes;
  the patched driver also compiles `-Werror`-clean as a kmod on the guest)
* `VERDICT.md`, `manifest.json`, `verdict.json`
