Since f6afed726b00 the TX-hang escalation in iflib_timer() has
required a queue state other than IFLIB_QUEUE_IDLE, but nothing ever
sets IFLIB_QUEUE_WORKING, so IFLIB_QUEUE_HUNG has been unreachable
ever since: stalled TX queues are not detected, not reported, and not
reset - the TX watchdog of every iflib(4) driver has been dead code.
Mark a queue as working when the transmit path has handed new
descriptors to the hardware, and only from the idle state, so that
enqueueing more work never demotes a queue already marked hung; only
completion progress may do that. When escalating a stalled queue to
hung, check the link state explicitly instead of asserting it: the
timer deliberately runs unlocked and can race the link-down demotion,
and that benign race would trip the assertion on an INVARIANTS
kernel.
The demotions to idle (reclaim progress, link down, controller stop)
are unchanged and the drain path cannot hand out descriptors while
the link is down, so a link-down queue still cannot be marked hung -
preserving what f6afed726b00 fixed. With this change a stalled TX
queue is again marked hung within one timer period and reset by the
existing watchdog machinery one period later, restoring for all
iflib(4) drivers the behavior lost in 2020.
PR: 220997, 239240
Fixes: f6afed726b00 ("iflib: Prevent watchdog from resetting idle queues")
MFC after: 1 month
Assisted-by: Claude Code (Fable 5)