diff options
author | Alexander Motin <mav@FreeBSD.org> | 2021-03-17 14:30:40 +0000 |
---|---|---|
committer | Alexander Motin <mav@FreeBSD.org> | 2021-03-24 01:26:34 +0000 |
commit | d00a723a2a5c1cd686fdab4b6d9c5084705d7182 (patch) | |
tree | 1aa6e80e55423816d1efcbec33880cb17bfce66c | |
parent | 610706f5e71a2805688cb3c13e8605675b58802c (diff) | |
download | src-d00a723a2a5c1cd686fdab4b6d9c5084705d7182.tar.gz src-d00a723a2a5c1cd686fdab4b6d9c5084705d7182.zip |
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.
(cherry picked from commit 4fbbe523653b6d2a0186aca38224efcab941deaa)
-rw-r--r-- | sys/dev/nvme/nvme_ctrlr.c | 24 |
1 files changed, 11 insertions, 13 deletions
diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c index 9e4268d9f4b5..d011eec99722 100644 --- a/sys/dev/nvme/nvme_ctrlr.c +++ b/sys/dev/nvme/nvme_ctrlr.c @@ -224,10 +224,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 == 0xffffffff) /* Hot unplug. */ @@ -235,12 +234,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); @@ -379,7 +378,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) @@ -1514,27 +1513,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 == 0xffffffff) /* 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); } } @@ -1611,7 +1609,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); |