# DF-2163: tsleep while holding queue_lock deadlocks IPS interrupt handler

## Verdict: NOT REPRODUCED (HW-gated) — source-confirmed real bug

## Reachability
**NOT reachable on this QEMU guest.** `ips_ioctl_cmd()` is in `sys/dev/raid/ips/ips_ioctl.c`,
part of the `ips(4)` IBM ServeRAID driver. `device ips` is in GENERIC but requires IBM
ServeRAID PCI hardware. PCI survey: no ServeRAID controller. `ls /dev/ips*` → not present.
The ioctl path (`IPS_USER_CMD`) is only reachable via an attached ips device node.

## Mechanism (source-confirmed)
`ips_ioctl_cmd()` at `ips_ioctl.c:125-139`:
1. Line 125: `lockmgr(&sc->queue_lock, LK_EXCLUSIVE|LK_RETRY)` — acquires exclusive lock
2. Line 132: `ips_ioctl_start(command)` — submits hardware command
3. Lines 133-134: `while (ioctl_cmd->status.value == 0xffffffff) tsleep(ioctl_cmd, 0, "ips", hz/10)`
   — **sleeps while holding `queue_lock`**
4. Line 139: `lockmgr(&sc->queue_lock, LK_RELEASE)` — releases lock after command completes

**The bug:** DragonFlyBSD's `tsleep()` does NOT release `lockmgr` locks — only `lksleep()`
does (see `kern_synch.c:831-843`). The IPS interrupt handler (`ips_intr`) needs
`queue_lock` to signal command completion (set `ioctl_cmd->status.value`), but it can't
acquire the lock because `ips_ioctl_cmd()` holds it while sleeping.

Result: **permanent deadlock**. The ioctl never returns, the controller is hung, and any
further IPS I/O is blocked. This is a local DoS (requires `ips` device access, typically
root or operator group).

## Primitive
- Class: deadlock / permanent DoS
- Impact: hangs the IPS controller indefinitely
- Requires access to the ips device (typically root-only)

## Fix
`fix.diff`: Replace `tsleep()` with `lksleep()` at line 134:
```c
lksleep(ioctl_cmd, &sc->queue_lock, 0, "ips", hz / 10);
```
`lksleep()` releases `queue_lock` during sleep and re-acquires it on wakeup, allowing the
interrupt handler to complete the command.
