mpr_wait_db_ack() and mps_wait_db_ack() poll the doorbell and, when they
may sleep, sleep "1 ms" between polls as hz/1000 ticks. With hz < 1000
that is 0: msleep() with timo 0 sleeps without a timeout, nothing ever
wakes msleep_fake_chan, and the thread stays in "mprdba"/"mpsdba" for
ever with the softc mutex held. The pause() branch does not hang
(pause_sbt() turns 0 into one tick) but sleeps a whole tick per poll, so
its timeout is ten times longer than intended at hz=100.
Three things have to come together for the hang, which is why it is
rarely seen:
- hz below 1000: a host with kern.hz set low, or any virtual machine, where hz defaults to 100 (HZ_VM);
- the sleeping branch with the softc mutex held, i.e. CAN_SLEEP after attach: attach itself uses NO_SLEEP ("If we are in attach call, do not sleep"), and the attach-time doorbell messages run without the mutex and so take the pause() branch. After attach the callers are the driver detach (mpr_free -> mpr_transition_ready), the reinit after a firmware fault (mpr_reinit -> mpr_diag_reset(CAN_SLEEP)) and synchronous commands;
- a doorbell write the IOC has not acknowledged by the first poll, which a message unit reset or diag reset is (ordinary I/O never touches the doorbell).
Seen on a host running with kern.hz=100 when "devctl detach mpr0" was
run to pass an SAS3008 through to a guest: the thread hung in
mpr_free -> mpr_transition_ready -> mpr_wait_db_ack, state D,
unkillable, and only a reboot ended it. A FreeBSD guest with one of
these HBAs passed through is in the same position whenever its driver
detaches or recovers from a firmware fault.
Use msleep_sbt()/pause_sbt() with SBT_1MS: the wait is 1 ms at any hz
and the timeout means what it says.
Signed-off-by: Wanpeng Qian <wanpengqian@gmail.com>
Sponsored by: keelos.dev