# DF-5423 — root-hub `usbconfig reset` never returns: unkillable D4 process + permanent USB-subsystem wedge (u4b core, reproduced through the uftdi rig)

## What (human-readable)

`usbconfig -d ugen0.1 reset` (reset of a **root hub**) with any device
attached to that root hub:

* the `usbconfig` process enters state **D4, wchan `USBSLP`** and never
  returns — **`kill -9` cannot remove it**;
* subsequent USB operations wedge too (`usbconfig list` hangs — the bus
  explore path is dead);
* the guest otherwise stays alive; only a **reboot** clears it.

Reproduced 3× (twice with an open/writing uftdi port, once with the port
closed and the device merely attached — the open tty is *not* required).
This matches the D4 hang the umodem.c pass-2 observed while probing this
family; it is a u4b-**core** defect (usb_dev.c + usb_hub.c), with uftdi as
the attached passenger device.

## Root cause (path:line)

* The userland reset lands in the generic-usb ioctl path whose tail is
  sys/bus/u4b/usb_dev.c:1137-1149:

  ```c
  /* Wait for re-enumeration, if any */
  while (f->udev->re_enumerate_wait != USB_RE_ENUM_DONE) {
          usb_unref_device(cpd, &refs);
          usb_pause_mtx(NULL, hz / 128);          /* "USBSLP", uninterruptible */
          if (usb_ref_device(cpd, &refs, 1)) { err = ENXIO; goto done; }
  }
  ```

  — an **unbounded, uninterruptible** spin-wait.

* For the *root hub* the flag is set by the reset ioctl
  (usb_generic.c:1801-1802, `re_enumerate_wait = USB_RE_ENUM_START`), but
  `uhub_explore_handle_re_enumerate()` — the only code that clears it
  (usb_hub.c:474,498,511,515) — is invoked **only for hub children**
  (usb_hub.c:550, inside `uhub_explore`'s per-port loop). The root hub has
  `parent_hub == NULL`; **nothing ever services its re_enumerate_wait**, so
  the wait loop spins forever, one `USBSLP` sleep at a time.
  (usb_hub.c:461-467 already special-cases "the root HUB cannot be
  re-enumerated" — but that code is unreachable for the root hub itself.)

* The observed child detach/re-attach (dmesg: `ugen0.2 (disconnected)` →
  `device still open, forcing close` → `detached` → re-attach) comes from
  the root-hub power-mode change that the same ioctl triggers — cosmetic
  w.r.t. the hang.

## Who can trigger

Root only (`usbconfig reset` needs the 0600 root ugen node). The wedge is
system-wide and permanent though: one command kills the whole USB bus
(hotplug, enumeration, new opens of usbconfig) until reboot, and leaves an
unkillable D4 process.

## Reproduce

```
usbconfig -d ugen0.1 reset        # any device attached to the root hub
ps -ax -o pid,stat,wchan,command | grep usbconfig
#   -> D4  USBSLP  usbconfig -d ugen0.1 reset
kill -9 <pid>                     # survives
usbconfig list                    # hangs
```

`run.log` is the clean 3rd reproduction (device attached, port NOT open):
D4/USBSLP, `kill -9` "Killed" yet the process still present, and
`usbconfig list` hanging (the ssh session had to be cut by the operator).

## Fix

`fix.diff` (usb_dev.c): bound the re-enumerate wait (~2 s of hz/128 sleeps
→ `ETIMEDOUT`), with a comment pointing at the unserviced root-hub flag.
`git apply --check` passes against `sys/`. (A fuller fix would service the
root hub's own `re_enumerate_wait` from the bus explore thread; the bound
removes the unkillable-wedge failure mode either way.)
