aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Motin <mav@FreeBSD.org>2021-03-17 14:30:40 +0000
committerAlexander Motin <mav@FreeBSD.org>2021-03-24 01:26:00 +0000
commited407c92e43f88652365c84dc54098a7ed479471 (patch)
treec22a3590d3b6655b2cd119fb6f1f1c40d415a33c
parentc6aa83342e5deccc51f627fcb92ca083fe798a3b (diff)
downloadsrc-ed407c92e43f88652365c84dc54098a7ed479471.tar.gz
src-ed407c92e43f88652365c84dc54098a7ed479471.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.c24
1 files changed, 11 insertions, 13 deletions
diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c
index 351c6839a6f6..9f86e3a8c846 100644
--- a/sys/dev/nvme/nvme_ctrlr.c
+++ b/sys/dev/nvme/nvme_ctrlr.c
@@ -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)
@@ -1538,27 +1537,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);
}
}
@@ -1635,7 +1633,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);