nvme: Replace potentially long DELAY() with pause().

In some cases like broken hardware nvme(4) may wait minutes for
controller response before timeout.  Doing so in a tight spin loop
made whole system unresponsive.

Reviewed by:	imp
MFC after:	1 week
Differential Revision:	https://reviews.freebsd.org/D29309
Sponsored by:	iXsystems, Inc.
This commit is contained in:
Alexander Motin 2021-03-17 10:30:40 -04:00
parent f187d6dfbf
commit 4fbbe52365

View file

@ -255,10 +255,9 @@ nvme_ctrlr_fail_req_task(void *arg, int pending)
static int
nvme_ctrlr_wait_for_ready(struct nvme_controller *ctrlr, int desired_val)
{
int ms_waited;
int timeout = ticks + (uint64_t)ctrlr->ready_timeout_in_ms * hz / 1000;
uint32_t csts;
ms_waited = 0;
while (1) {
csts = nvme_mmio_read_4(ctrlr, csts);
if (csts == NVME_GONE) /* Hot unplug. */
@ -266,12 +265,12 @@ nvme_ctrlr_wait_for_ready(struct nvme_controller *ctrlr, int desired_val)
if (((csts >> NVME_CSTS_REG_RDY_SHIFT) & NVME_CSTS_REG_RDY_MASK)
== desired_val)
break;
if (ms_waited++ > ctrlr->ready_timeout_in_ms) {
if (timeout - ticks < 0) {
nvme_printf(ctrlr, "controller ready did not become %d "
"within %d ms\n", desired_val, ctrlr->ready_timeout_in_ms);
return (ENXIO);
}
DELAY(1000);
pause("nvmerdy", 1);
}
return (0);
@ -410,7 +409,7 @@ nvme_ctrlr_hw_reset(struct nvme_controller *ctrlr)
nvme_ctrlr_disable_qpairs(ctrlr);
DELAY(100*1000);
pause("nvmehwreset", hz / 10);
err = nvme_ctrlr_disable(ctrlr);
if (err != 0)
@ -1536,27 +1535,26 @@ nvme_ctrlr_shutdown(struct nvme_controller *ctrlr)
{
uint32_t cc;
uint32_t csts;
int ticks = 0, timeout;
int timeout;
cc = nvme_mmio_read_4(ctrlr, cc);
cc &= ~(NVME_CC_REG_SHN_MASK << NVME_CC_REG_SHN_SHIFT);
cc |= NVME_SHN_NORMAL << NVME_CC_REG_SHN_SHIFT;
nvme_mmio_write_4(ctrlr, cc, cc);
timeout = ctrlr->cdata.rtd3e == 0 ? 5 * hz :
((uint64_t)ctrlr->cdata.rtd3e * hz + 999999) / 1000000;
timeout = ticks + (ctrlr->cdata.rtd3e == 0 ? 5 * hz :
((uint64_t)ctrlr->cdata.rtd3e * hz + 999999) / 1000000);
while (1) {
csts = nvme_mmio_read_4(ctrlr, csts);
if (csts == NVME_GONE) /* Hot unplug. */
break;
if (NVME_CSTS_GET_SHST(csts) == NVME_SHST_COMPLETE)
break;
if (ticks++ > timeout) {
nvme_printf(ctrlr, "did not complete shutdown within"
" %d ticks of notification\n", timeout);
if (timeout - ticks < 0) {
nvme_printf(ctrlr, "shutdown timeout\n");
break;
}
pause("nvme shn", 1);
pause("nvmeshut", 1);
}
}
@ -1633,7 +1631,7 @@ nvme_ctrlr_suspend(struct nvme_controller *ctrlr)
*/
nvme_ctrlr_delete_qpairs(ctrlr);
nvme_ctrlr_disable_qpairs(ctrlr);
DELAY(100*1000);
pause("nvmesusp", hz / 10);
nvme_ctrlr_shutdown(ctrlr);
return (0);