Author: jimharris Date: Tue Mar 26 20:56:58 2013 New Revision: 248755 URL: http://svnweb.freebsd.org/changeset/base/248755
Log: Make nvme_ctrlr_reset a nop if a reset is already in progress. This protects against cases where a controller crashes with multiple I/O outstanding, each timing out and requesting controller resets simultaneously. While here, remove a debugging printf from a previous commit, and add more logging around I/O that need to be resubmitted after a controller reset. Sponsored by: Intel Reviewed by: carl Modified: head/sys/dev/nvme/nvme_ctrlr.c head/sys/dev/nvme/nvme_private.h head/sys/dev/nvme/nvme_qpair.c Modified: head/sys/dev/nvme/nvme_ctrlr.c ============================================================================== --- head/sys/dev/nvme/nvme_ctrlr.c Tue Mar 26 20:32:57 2013 (r248754) +++ head/sys/dev/nvme/nvme_ctrlr.c Tue Mar 26 20:56:58 2013 (r248755) @@ -422,6 +422,13 @@ nvme_ctrlr_hw_reset(struct nvme_controll void nvme_ctrlr_reset(struct nvme_controller *ctrlr) { + int cmpset; + + cmpset = atomic_cmpset_32(&ctrlr->is_resetting, 0, 1); + + if (cmpset == 0) + /* Controller is already resetting. */ + return; taskqueue_enqueue(ctrlr->taskqueue, &ctrlr->reset_task); } @@ -700,6 +707,8 @@ nvme_ctrlr_reset_task(void *arg, int pen pause("nvmereset", hz / 10); if (status == 0) nvme_ctrlr_start(ctrlr); + + atomic_cmpset_32(&ctrlr->is_resetting, 1, 0); } static void @@ -896,6 +905,8 @@ intx: taskqueue_thread_enqueue, &ctrlr->taskqueue); taskqueue_start_threads(&ctrlr->taskqueue, 1, PI_DISK, "nvme taskq"); + ctrlr->is_resetting = 0; + return (0); } Modified: head/sys/dev/nvme/nvme_private.h ============================================================================== --- head/sys/dev/nvme/nvme_private.h Tue Mar 26 20:32:57 2013 (r248754) +++ head/sys/dev/nvme/nvme_private.h Tue Mar 26 20:56:58 2013 (r248755) @@ -100,7 +100,7 @@ MALLOC_DECLARE(M_NVME); #define NVME_MAX_CONSUMERS (2) #define NVME_MAX_ASYNC_EVENTS (8) -#define NVME_DEFAULT_TIMEOUT_PERIOD (30) /* in seconds */ +#define NVME_DEFAULT_TIMEOUT_PERIOD (30) /* in seconds */ #define NVME_MIN_TIMEOUT_PERIOD (5) #define NVME_MAX_TIMEOUT_PERIOD (120) @@ -280,6 +280,8 @@ struct nvme_controller { void *cons_cookie[NVME_MAX_CONSUMERS]; + uint32_t is_resetting; + #ifdef CHATHAM2 uint64_t chatham_size; uint64_t chatham_lbas; Modified: head/sys/dev/nvme/nvme_qpair.c ============================================================================== --- head/sys/dev/nvme/nvme_qpair.c Tue Mar 26 20:32:57 2013 (r248754) +++ head/sys/dev/nvme/nvme_qpair.c Tue Mar 26 20:56:58 2013 (r248755) @@ -142,7 +142,13 @@ nvme_qpair_complete_tracker(struct nvme_ TAILQ_REMOVE(&qpair->outstanding_tr, tr, tailq); TAILQ_INSERT_HEAD(&qpair->free_tr, tr, tailq); - if (!STAILQ_EMPTY(&qpair->queued_req)) { + /* + * If the controller is in the middle of resetting, don't + * try to submit queued requests here - let the reset logic + * handle that instead. + */ + if (!STAILQ_EMPTY(&qpair->queued_req) && + !qpair->ctrlr->is_resetting) { req = STAILQ_FIRST(&qpair->queued_req); STAILQ_REMOVE_HEAD(&qpair->queued_req, stailq); _nvme_qpair_submit_request(qpair, req); @@ -462,8 +468,6 @@ nvme_timeout(void *arg) /* Read csts to get value of cfs - controller fatal status. */ csts.raw = nvme_mmio_read_4(ctrlr, csts); - device_printf(ctrlr->dev, "i/o timeout, csts.cfs=%d\n", csts.bits.cfs); - nvme_dump_command(&tr->req->cmd); if (ctrlr->enable_aborts && csts.bits.cfs == 0) { /* @@ -606,8 +610,12 @@ nvme_io_qpair_enable(struct nvme_qpair * nvme_qpair_enable(qpair); - TAILQ_FOREACH(tr, &qpair->outstanding_tr, tailq) + TAILQ_FOREACH(tr, &qpair->outstanding_tr, tailq) { + device_printf(qpair->ctrlr->dev, + "resubmitting outstanding i/o\n"); + nvme_dump_command(&tr->req->cmd); nvme_qpair_submit_tracker(qpair, tr); + } STAILQ_INIT(&temp); STAILQ_SWAP(&qpair->queued_req, &temp, nvme_request); @@ -615,6 +623,9 @@ nvme_io_qpair_enable(struct nvme_qpair * while (!STAILQ_EMPTY(&temp)) { req = STAILQ_FIRST(&temp); STAILQ_REMOVE_HEAD(&temp, stailq); + device_printf(qpair->ctrlr->dev, + "resubmitting queued i/o\n"); + nvme_dump_command(&req->cmd); _nvme_qpair_submit_request(qpair, req); } _______________________________________________ svn-src-head@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"