* [PATCH 0/3] NVMe PCI endpoint target fixes
@ 2025-04-08 2:47 Damien Le Moal
2025-04-08 2:47 ` [PATCH 1/3] nvmet: pci-epf: Always fully initialize completion entries Damien Le Moal
` (3 more replies)
0 siblings, 4 replies; 19+ messages in thread
From: Damien Le Moal @ 2025-04-08 2:47 UTC (permalink / raw)
To: linux-nvme, Keith Busch, Christoph Hellwig, Sagi Grimberg
Two bug fix patch and one cleanup patch in this series.
The first patch fixes an issue with completion queue entries
initialization in the case of failed commands.
The second patch fixes
the initialization of the CC register to ensure that we can always
detect that the host is attempting to enable the controller (with
CC.EN).
The last patch cleans up/simplifies the management of the PCI link
state.
Damien Le Moal (3):
nvmet: pci-epf: Always fully initialize completion entries
nvmet: pci-epf: Clear CC and CSTS when disabling the controller
nvmet: pci-epf: Cleanup link state management
drivers/nvme/target/pci-epf.c | 65 ++++++++++++++++++++++-------------
1 file changed, 42 insertions(+), 23 deletions(-)
--
2.49.0
^ permalink raw reply [flat|nested] 19+ messages in thread* [PATCH 1/3] nvmet: pci-epf: Always fully initialize completion entries 2025-04-08 2:47 [PATCH 0/3] NVMe PCI endpoint target fixes Damien Le Moal @ 2025-04-08 2:47 ` Damien Le Moal 2025-04-10 8:24 ` Keith Busch ` (3 more replies) 2025-04-08 2:47 ` [PATCH 2/3] nvmet: pci-epf: Clear CC and CSTS when disabling the controller Damien Le Moal ` (2 subsequent siblings) 3 siblings, 4 replies; 19+ messages in thread From: Damien Le Moal @ 2025-04-08 2:47 UTC (permalink / raw) To: linux-nvme, Keith Busch, Christoph Hellwig, Sagi Grimberg For a command that is normally processed through the command request execute() function, the completion entry for the command is initialized by __nvmet_req_complete() and nvmet_pci_epf_cq_work() only needs to set the status field and the phase of the completion entry before posting the entry to the completion queue. However, for commands that are failed due to an internal error (e.g. the command data buffer allocation fails), the command request execute() function is not called and __nvmet_req_complete() is never executed for the command, leaving the command completion entry uninitialized. For such command failed before calling req->execute(), the host ends up seeing completion entries with an invalid submission queue ID and command ID. Avoid such issue by always fully initilizing a command completion entry in nvmet_pci_epf_cq_work(), setting the entry submission queue ID and command ID. Fixes: 0faa0fe6f90e ("nvmet: New NVMe PCI endpoint function target driver") Cc: stable@vger.kernel.org Signed-off-by: Damien Le Moal <dlemoal@kernel.org> --- drivers/nvme/target/pci-epf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c index 51c27b32248d..f6b22ef4c267 100644 --- a/drivers/nvme/target/pci-epf.c +++ b/drivers/nvme/target/pci-epf.c @@ -1763,6 +1763,8 @@ static void nvmet_pci_epf_cq_work(struct work_struct *work) /* Post the IOD completion entry. */ cqe = &iod->cqe; + cqe->sq_id = cpu_to_le16(iod->sq->qid); + cqe->command_id = iod->cmd.common.command_id; cqe->status = cpu_to_le16((iod->status << 1) | cq->phase); dev_dbg(ctrl->dev, -- 2.49.0 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH 1/3] nvmet: pci-epf: Always fully initialize completion entries 2025-04-08 2:47 ` [PATCH 1/3] nvmet: pci-epf: Always fully initialize completion entries Damien Le Moal @ 2025-04-10 8:24 ` Keith Busch 2025-04-10 8:38 ` Christoph Hellwig ` (2 subsequent siblings) 3 siblings, 0 replies; 19+ messages in thread From: Keith Busch @ 2025-04-10 8:24 UTC (permalink / raw) To: Damien Le Moal; +Cc: linux-nvme, Christoph Hellwig, Sagi Grimberg On Tue, Apr 08, 2025 at 11:47:31AM +0900, Damien Le Moal wrote: > For a command that is normally processed through the command request > execute() function, the completion entry for the command is initialized > by __nvmet_req_complete() and nvmet_pci_epf_cq_work() only needs to set > the status field and the phase of the completion entry before posting > the entry to the completion queue. > > However, for commands that are failed due to an internal error (e.g. the > command data buffer allocation fails), the command request execute() > function is not called and __nvmet_req_complete() is never executed for > the command, leaving the command completion entry uninitialized. For > such command failed before calling req->execute(), the host ends up > seeing completion entries with an invalid submission queue ID and > command ID. > > Avoid such issue by always fully initilizing a command completion entry > in nvmet_pci_epf_cq_work(), setting the entry submission queue ID and > command ID. Looks good. Reviewed-by: Keith Busch <kbusch@kernel.org> ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/3] nvmet: pci-epf: Always fully initialize completion entries 2025-04-08 2:47 ` [PATCH 1/3] nvmet: pci-epf: Always fully initialize completion entries Damien Le Moal 2025-04-10 8:24 ` Keith Busch @ 2025-04-10 8:38 ` Christoph Hellwig 2025-04-10 9:15 ` Niklas Cassel 2025-04-14 22:03 ` Sagi Grimberg 3 siblings, 0 replies; 19+ messages in thread From: Christoph Hellwig @ 2025-04-10 8:38 UTC (permalink / raw) To: Damien Le Moal; +Cc: linux-nvme, Keith Busch, Christoph Hellwig, Sagi Grimberg On Tue, Apr 08, 2025 at 11:47:31AM +0900, Damien Le Moal wrote: > @@ -1763,6 +1763,8 @@ static void nvmet_pci_epf_cq_work(struct work_struct *work) > > /* Post the IOD completion entry. */ > cqe = &iod->cqe; > + cqe->sq_id = cpu_to_le16(iod->sq->qid); > + cqe->command_id = iod->cmd.common.command_id; This could use a comment explaining why we are doing this seemingly duplicate work here. Otherwise this looks good to me. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/3] nvmet: pci-epf: Always fully initialize completion entries 2025-04-08 2:47 ` [PATCH 1/3] nvmet: pci-epf: Always fully initialize completion entries Damien Le Moal 2025-04-10 8:24 ` Keith Busch 2025-04-10 8:38 ` Christoph Hellwig @ 2025-04-10 9:15 ` Niklas Cassel 2025-04-14 22:03 ` Sagi Grimberg 3 siblings, 0 replies; 19+ messages in thread From: Niklas Cassel @ 2025-04-10 9:15 UTC (permalink / raw) To: Damien Le Moal; +Cc: linux-nvme, Keith Busch, Christoph Hellwig, Sagi Grimberg On Tue, Apr 08, 2025 at 11:47:31AM +0900, Damien Le Moal wrote: > For a command that is normally processed through the command request > execute() function, the completion entry for the command is initialized > by __nvmet_req_complete() and nvmet_pci_epf_cq_work() only needs to set > the status field and the phase of the completion entry before posting > the entry to the completion queue. > > However, for commands that are failed due to an internal error (e.g. the > command data buffer allocation fails), the command request execute() > function is not called and __nvmet_req_complete() is never executed for > the command, leaving the command completion entry uninitialized. For > such command failed before calling req->execute(), the host ends up > seeing completion entries with an invalid submission queue ID and > command ID. > > Avoid such issue by always fully initilizing a command completion entry > in nvmet_pci_epf_cq_work(), setting the entry submission queue ID and > command ID. > > Fixes: 0faa0fe6f90e ("nvmet: New NVMe PCI endpoint function target driver") > Cc: stable@vger.kernel.org > Signed-off-by: Damien Le Moal <dlemoal@kernel.org> > --- > drivers/nvme/target/pci-epf.c | 2 ++ > 1 file changed, 2 insertions(+) > > diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c > index 51c27b32248d..f6b22ef4c267 100644 > --- a/drivers/nvme/target/pci-epf.c > +++ b/drivers/nvme/target/pci-epf.c > @@ -1763,6 +1763,8 @@ static void nvmet_pci_epf_cq_work(struct work_struct *work) > > /* Post the IOD completion entry. */ > cqe = &iod->cqe; > + cqe->sq_id = cpu_to_le16(iod->sq->qid); > + cqe->command_id = iod->cmd.common.command_id; > cqe->status = cpu_to_le16((iod->status << 1) | cq->phase); Looking at e.g. __nvmet_req_complete() and __nvmet_fc_fcp_nvme_cmd_done() in addition to setting sq_id, command_id, and status, they also set: cqe->sq_head. (__nvmet_req_complete() -> nvmet_update_sq_head() -> req->cqe->sq_head = ...) Should we perhaps set sq_head too? Kind regards, Niklas ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/3] nvmet: pci-epf: Always fully initialize completion entries 2025-04-08 2:47 ` [PATCH 1/3] nvmet: pci-epf: Always fully initialize completion entries Damien Le Moal ` (2 preceding siblings ...) 2025-04-10 9:15 ` Niklas Cassel @ 2025-04-14 22:03 ` Sagi Grimberg 3 siblings, 0 replies; 19+ messages in thread From: Sagi Grimberg @ 2025-04-14 22:03 UTC (permalink / raw) To: Damien Le Moal, linux-nvme, Keith Busch, Christoph Hellwig Reviewed-by: Sagi Grimberg <sagi@grimberg.me> ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 2/3] nvmet: pci-epf: Clear CC and CSTS when disabling the controller 2025-04-08 2:47 [PATCH 0/3] NVMe PCI endpoint target fixes Damien Le Moal 2025-04-08 2:47 ` [PATCH 1/3] nvmet: pci-epf: Always fully initialize completion entries Damien Le Moal @ 2025-04-08 2:47 ` Damien Le Moal 2025-04-10 8:34 ` Keith Busch ` (2 more replies) 2025-04-08 2:47 ` [PATCH 3/3] nvmet: pci-epf: Cleanup link state management Damien Le Moal 2025-04-10 8:05 ` [PATCH 0/3] NVMe PCI endpoint target fixes Damien Le Moal 3 siblings, 3 replies; 19+ messages in thread From: Damien Le Moal @ 2025-04-08 2:47 UTC (permalink / raw) To: linux-nvme, Keith Busch, Christoph Hellwig, Sagi Grimberg When a host shuts down the controller when shutting down but does so without first disabling the controller, the enable bit remains set in the controller configuration register. When the host restarts and attempts to enable the controller again, the nvmet_pci_epf_poll_cc_work() function is unable to detect the change from 0 to 1 of the enable bit, and thus the controller is not enabled again, which result in a device scan timeout on the host. This problem also occurs if the host shuts down uncleanly or if the PCIe link goes down: as the CC.EN value is not reset, the controller is not enabled again when the host restarts. Fix this by introducing the function nvmet_pci_epf_clear_ctrl_config() to clear the CC and CSTS registers of the controller when the PCIe link is lost (nvmet_pci_epf_stop_ctrl() function), and when starting the controller fails (nvmet_pci_epf_enable_ctrl() fails). Also use this function in nvmet_pci_epf_init_bar() to simplify the initialization of the CC and CSTS registers. Furthermore, modify the function nvmet_pci_epf_disable_ctrl() to clear the CC.EN bit and write this updated value to the BAR register when the controller is shutdown by the host, to ensure that upon restart, we can detect the host setting CC.EN. Fixes: 0faa0fe6f90e ("nvmet: New NVMe PCI endpoint function target driver") Cc: stable@vger.kernel.org Signed-off-by: Damien Le Moal <dlemoal@kernel.org> --- drivers/nvme/target/pci-epf.c | 49 +++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c index f6b22ef4c267..f18faf407eab 100644 --- a/drivers/nvme/target/pci-epf.c +++ b/drivers/nvme/target/pci-epf.c @@ -1802,6 +1802,21 @@ static void nvmet_pci_epf_cq_work(struct work_struct *work) NVMET_PCI_EPF_CQ_RETRY_INTERVAL); } +static void nvmet_pci_epf_clear_ctrl_config(struct nvmet_pci_epf_ctrl *ctrl) +{ + struct nvmet_ctrl *tctrl = ctrl->tctrl; + + /* Initialize controller status. */ + tctrl->csts = 0; + ctrl->csts = 0; + nvmet_pci_epf_bar_write32(ctrl, NVME_REG_CSTS, ctrl->csts); + + /* Initialize controller configuration and start polling. */ + tctrl->cc = 0; + ctrl->cc = 0; + nvmet_pci_epf_bar_write32(ctrl, NVME_REG_CC, ctrl->cc); +} + static int nvmet_pci_epf_enable_ctrl(struct nvmet_pci_epf_ctrl *ctrl) { u64 pci_addr, asq, acq; @@ -1867,18 +1882,20 @@ static int nvmet_pci_epf_enable_ctrl(struct nvmet_pci_epf_ctrl *ctrl) return 0; err: - ctrl->csts = 0; + nvmet_pci_epf_clear_ctrl_config(ctrl); return -EINVAL; } -static void nvmet_pci_epf_disable_ctrl(struct nvmet_pci_epf_ctrl *ctrl) +static void nvmet_pci_epf_disable_ctrl(struct nvmet_pci_epf_ctrl *ctrl, + bool shutdown) { int qid; if (!ctrl->enabled) return; - dev_info(ctrl->dev, "Disabling controller\n"); + dev_info(ctrl->dev, "%s controller\n", + shutdown ? "Shutting down" : "Disabling"); ctrl->enabled = false; cancel_delayed_work_sync(&ctrl->poll_sqs); @@ -1895,6 +1912,11 @@ static void nvmet_pci_epf_disable_ctrl(struct nvmet_pci_epf_ctrl *ctrl) nvmet_pci_epf_delete_cq(ctrl->tctrl, 0); ctrl->csts &= ~NVME_CSTS_RDY; + if (shutdown) { + ctrl->csts |= NVME_CSTS_SHST_CMPLT; + ctrl->cc &= ~NVME_CC_ENABLE; + nvmet_pci_epf_bar_write32(ctrl, NVME_REG_CC, ctrl->cc); + } } static void nvmet_pci_epf_poll_cc_work(struct work_struct *work) @@ -1921,12 +1943,10 @@ static void nvmet_pci_epf_poll_cc_work(struct work_struct *work) } if (!nvmet_cc_en(new_cc) && nvmet_cc_en(old_cc)) - nvmet_pci_epf_disable_ctrl(ctrl); + nvmet_pci_epf_disable_ctrl(ctrl, false); - if (nvmet_cc_shn(new_cc) && !nvmet_cc_shn(old_cc)) { - nvmet_pci_epf_disable_ctrl(ctrl); - ctrl->csts |= NVME_CSTS_SHST_CMPLT; - } + if (nvmet_cc_shn(new_cc) && !nvmet_cc_shn(old_cc)) + nvmet_pci_epf_disable_ctrl(ctrl, true); if (!nvmet_cc_shn(new_cc) && nvmet_cc_shn(old_cc)) ctrl->csts &= ~NVME_CSTS_SHST_CMPLT; @@ -1965,16 +1985,10 @@ static void nvmet_pci_epf_init_bar(struct nvmet_pci_epf_ctrl *ctrl) /* Clear Controller Memory Buffer Supported (CMBS). */ ctrl->cap &= ~(0x1ULL << 57); - /* Controller configuration. */ - ctrl->cc = tctrl->cc & (~NVME_CC_ENABLE); - - /* Controller status. */ - ctrl->csts = ctrl->tctrl->csts; - nvmet_pci_epf_bar_write64(ctrl, NVME_REG_CAP, ctrl->cap); nvmet_pci_epf_bar_write32(ctrl, NVME_REG_VS, tctrl->subsys->ver); - nvmet_pci_epf_bar_write32(ctrl, NVME_REG_CSTS, ctrl->csts); - nvmet_pci_epf_bar_write32(ctrl, NVME_REG_CC, ctrl->cc); + + nvmet_pci_epf_clear_ctrl_config(ctrl); } static int nvmet_pci_epf_create_ctrl(struct nvmet_pci_epf *nvme_epf, @@ -2079,7 +2093,8 @@ static void nvmet_pci_epf_stop_ctrl(struct nvmet_pci_epf_ctrl *ctrl) { cancel_delayed_work_sync(&ctrl->poll_cc); - nvmet_pci_epf_disable_ctrl(ctrl); + nvmet_pci_epf_disable_ctrl(ctrl, false); + nvmet_pci_epf_clear_ctrl_config(ctrl); } static void nvmet_pci_epf_destroy_ctrl(struct nvmet_pci_epf_ctrl *ctrl) -- 2.49.0 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH 2/3] nvmet: pci-epf: Clear CC and CSTS when disabling the controller 2025-04-08 2:47 ` [PATCH 2/3] nvmet: pci-epf: Clear CC and CSTS when disabling the controller Damien Le Moal @ 2025-04-10 8:34 ` Keith Busch 2025-04-11 0:32 ` Damien Le Moal 2025-04-10 11:54 ` Niklas Cassel 2025-04-14 22:07 ` Sagi Grimberg 2 siblings, 1 reply; 19+ messages in thread From: Keith Busch @ 2025-04-10 8:34 UTC (permalink / raw) To: Damien Le Moal; +Cc: linux-nvme, Christoph Hellwig, Sagi Grimberg On Tue, Apr 08, 2025 at 11:47:32AM +0900, Damien Le Moal wrote: > @@ -1895,6 +1912,11 @@ static void nvmet_pci_epf_disable_ctrl(struct nvmet_pci_epf_ctrl *ctrl) > nvmet_pci_epf_delete_cq(ctrl->tctrl, 0); > > ctrl->csts &= ~NVME_CSTS_RDY; > + if (shutdown) { > + ctrl->csts |= NVME_CSTS_SHST_CMPLT; > + ctrl->cc &= ~NVME_CC_ENABLE; > + nvmet_pci_epf_bar_write32(ctrl, NVME_REG_CC, ctrl->cc); > + } > } I think this is probably okay, but I don't know if it's necessary to be messing with CC.EN that the host didn't request. The qemu emulated nvme doesn't do this, at least. But it looks like that would all work out in the end anyway, so again, I think it's fine. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/3] nvmet: pci-epf: Clear CC and CSTS when disabling the controller 2025-04-10 8:34 ` Keith Busch @ 2025-04-11 0:32 ` Damien Le Moal 2025-04-14 17:58 ` Keith Busch 0 siblings, 1 reply; 19+ messages in thread From: Damien Le Moal @ 2025-04-11 0:32 UTC (permalink / raw) To: Keith Busch; +Cc: linux-nvme, Christoph Hellwig, Sagi Grimberg On 4/10/25 17:34, Keith Busch wrote: > On Tue, Apr 08, 2025 at 11:47:32AM +0900, Damien Le Moal wrote: >> @@ -1895,6 +1912,11 @@ static void nvmet_pci_epf_disable_ctrl(struct nvmet_pci_epf_ctrl *ctrl) >> nvmet_pci_epf_delete_cq(ctrl->tctrl, 0); >> >> ctrl->csts &= ~NVME_CSTS_RDY; >> + if (shutdown) { >> + ctrl->csts |= NVME_CSTS_SHST_CMPLT; >> + ctrl->cc &= ~NVME_CC_ENABLE; >> + nvmet_pci_epf_bar_write32(ctrl, NVME_REG_CC, ctrl->cc); >> + } >> } > > I think this is probably okay, but I don't know if it's necessary to be > messing with CC.EN that the host didn't request. The qemu emulated nvme > doesn't do this, at least. But it looks like that would all work out in > the end anyway, so again, I think it's fine. Maybe qemu clears/resets all the registers of the BAR when it does a shutdown ? I did not check the code. But here, if we do not clear EN, *and* the host does not first disable the controller before trying to re-enable it (like the linux host pci driver does), after the shutdown, we fail to detect that the host set EN again since we can only detect that by polling and comparing to the previous value. I also thought about using ctrl->enabled for determining what needs to be done, but then again, if we do not clear EN from the register, the next CC poll loop will see EN set and think that it is the host trying to re-enable the controller and we will re-enable right away. I think that clearing EN is not necessary with qemu because there is no polling, since (I think) that qemu nvme driver will be looking at CC.EN only and only when the guest touches it (as that will trigger a guest exit into the hypervisor). So the qemu nvme driver always sees the newest value of CC, not the old one like we do with the endpoint. -- Damien Le Moal Western Digital Research ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/3] nvmet: pci-epf: Clear CC and CSTS when disabling the controller 2025-04-11 0:32 ` Damien Le Moal @ 2025-04-14 17:58 ` Keith Busch 0 siblings, 0 replies; 19+ messages in thread From: Keith Busch @ 2025-04-14 17:58 UTC (permalink / raw) To: Damien Le Moal; +Cc: linux-nvme, Christoph Hellwig, Sagi Grimberg On Fri, Apr 11, 2025 at 09:32:53AM +0900, Damien Le Moal wrote: > On 4/10/25 17:34, Keith Busch wrote: > > On Tue, Apr 08, 2025 at 11:47:32AM +0900, Damien Le Moal wrote: > >> @@ -1895,6 +1912,11 @@ static void nvmet_pci_epf_disable_ctrl(struct nvmet_pci_epf_ctrl *ctrl) > >> nvmet_pci_epf_delete_cq(ctrl->tctrl, 0); > >> > >> ctrl->csts &= ~NVME_CSTS_RDY; > >> + if (shutdown) { > >> + ctrl->csts |= NVME_CSTS_SHST_CMPLT; > >> + ctrl->cc &= ~NVME_CC_ENABLE; > >> + nvmet_pci_epf_bar_write32(ctrl, NVME_REG_CC, ctrl->cc); > >> + } > >> } > > > > I think this is probably okay, but I don't know if it's necessary to be > > messing with CC.EN that the host didn't request. The qemu emulated nvme > > doesn't do this, at least. But it looks like that would all work out in > > the end anyway, so again, I think it's fine. > > Maybe qemu clears/resets all the registers of the BAR when it does a shutdown ? > I did not check the code. But here, if we do not clear EN, *and* the host does > not first disable the controller before trying to re-enable it (like the linux > host pci driver does), after the shutdown, we fail to detect that the host set > EN again since we can only detect that by polling and comparing to the previous > value. The spec has some text explaining the host needs to handle a shutdown controller with CC.EN set in section 3.6.1: To start executing commands on the controller after that controller reports controller shutdown processing complete (...) utilizing the CC.EN bit: o if the CC.EN bit is set to `1´, then a Controller Level Reset is required to clear the CC.EN bit to `0´ on that controller and the CC.EN bit is subsequently required to be set to `1´ as part of the initialization sequence So I guess some hosts just aren't handling this? No biggie, linux will react accordingly either way. I didn't find anything that requires a shutdown controller retain CC.EN, so clearing it on the condition is probably fine. I never really fully understood why a disabled vs shutdown-ready controller needed such distinctions anyway. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/3] nvmet: pci-epf: Clear CC and CSTS when disabling the controller 2025-04-08 2:47 ` [PATCH 2/3] nvmet: pci-epf: Clear CC and CSTS when disabling the controller Damien Le Moal 2025-04-10 8:34 ` Keith Busch @ 2025-04-10 11:54 ` Niklas Cassel 2025-04-11 0:35 ` Damien Le Moal 2025-04-14 22:07 ` Sagi Grimberg 2 siblings, 1 reply; 19+ messages in thread From: Niklas Cassel @ 2025-04-10 11:54 UTC (permalink / raw) To: Damien Le Moal; +Cc: linux-nvme, Keith Busch, Christoph Hellwig, Sagi Grimberg On Tue, Apr 08, 2025 at 11:47:32AM +0900, Damien Le Moal wrote: > When a host shuts down the controller when shutting down but does so > without first disabling the controller, the enable bit remains set in > the controller configuration register. When the host restarts and > attempts to enable the controller again, the > nvmet_pci_epf_poll_cc_work() function is unable to detect the change > from 0 to 1 of the enable bit, and thus the controller is not enabled > again, which result in a device scan timeout on the host. This problem > also occurs if the host shuts down uncleanly or if the PCIe link goes > down: as the CC.EN value is not reset, the controller is not enabled > again when the host restarts. > > Fix this by introducing the function nvmet_pci_epf_clear_ctrl_config() > to clear the CC and CSTS registers of the controller when the PCIe link > is lost (nvmet_pci_epf_stop_ctrl() function), and when starting the s/, and when/, or when/ > controller fails (nvmet_pci_epf_enable_ctrl() fails). Also use this > function in nvmet_pci_epf_init_bar() to simplify the initialization of > the CC and CSTS registers. > > Furthermore, modify the function nvmet_pci_epf_disable_ctrl() to clear > the CC.EN bit and write this updated value to the BAR register when the > controller is shutdown by the host, to ensure that upon restart, we can > detect the host setting CC.EN. > > Fixes: 0faa0fe6f90e ("nvmet: New NVMe PCI endpoint function target driver") > Cc: stable@vger.kernel.org > Signed-off-by: Damien Le Moal <dlemoal@kernel.org> > --- > drivers/nvme/target/pci-epf.c | 49 +++++++++++++++++++++++------------ > 1 file changed, 32 insertions(+), 17 deletions(-) > > diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c > index f6b22ef4c267..f18faf407eab 100644 > --- a/drivers/nvme/target/pci-epf.c > +++ b/drivers/nvme/target/pci-epf.c > @@ -1802,6 +1802,21 @@ static void nvmet_pci_epf_cq_work(struct work_struct *work) > NVMET_PCI_EPF_CQ_RETRY_INTERVAL); > } > > +static void nvmet_pci_epf_clear_ctrl_config(struct nvmet_pci_epf_ctrl *ctrl) > +{ > + struct nvmet_ctrl *tctrl = ctrl->tctrl; > + > + /* Initialize controller status. */ > + tctrl->csts = 0; > + ctrl->csts = 0; This can be written on one line: tctrl->csts = ctrl->csts = 0; > + nvmet_pci_epf_bar_write32(ctrl, NVME_REG_CSTS, ctrl->csts); > + > + /* Initialize controller configuration and start polling. */ > + tctrl->cc = 0; > + ctrl->cc = 0; Same here. Otherwise, this looks good to me: Reviewed-by: Niklas Cassel <cassel@kernel.org> ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/3] nvmet: pci-epf: Clear CC and CSTS when disabling the controller 2025-04-10 11:54 ` Niklas Cassel @ 2025-04-11 0:35 ` Damien Le Moal 0 siblings, 0 replies; 19+ messages in thread From: Damien Le Moal @ 2025-04-11 0:35 UTC (permalink / raw) To: Niklas Cassel; +Cc: linux-nvme, Keith Busch, Christoph Hellwig, Sagi Grimberg On 4/10/25 20:54, Niklas Cassel wrote: >> +static void nvmet_pci_epf_clear_ctrl_config(struct nvmet_pci_epf_ctrl *ctrl) >> +{ >> + struct nvmet_ctrl *tctrl = ctrl->tctrl; >> + >> + /* Initialize controller status. */ >> + tctrl->csts = 0; >> + ctrl->csts = 0; > > This can be written on one line: > tctrl->csts = ctrl->csts = 0; I am aware of this, but really dislike this style as I think it makes the code less readable. So unless the nvme maintainers insist on this change, I prefer leaving this as I wrote it. -- Damien Le Moal Western Digital Research ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/3] nvmet: pci-epf: Clear CC and CSTS when disabling the controller 2025-04-08 2:47 ` [PATCH 2/3] nvmet: pci-epf: Clear CC and CSTS when disabling the controller Damien Le Moal 2025-04-10 8:34 ` Keith Busch 2025-04-10 11:54 ` Niklas Cassel @ 2025-04-14 22:07 ` Sagi Grimberg 2 siblings, 0 replies; 19+ messages in thread From: Sagi Grimberg @ 2025-04-14 22:07 UTC (permalink / raw) To: Damien Le Moal, linux-nvme, Keith Busch, Christoph Hellwig Reviewed-by: Sagi Grimberg <sagi@grimberg.me> ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 3/3] nvmet: pci-epf: Cleanup link state management 2025-04-08 2:47 [PATCH 0/3] NVMe PCI endpoint target fixes Damien Le Moal 2025-04-08 2:47 ` [PATCH 1/3] nvmet: pci-epf: Always fully initialize completion entries Damien Le Moal 2025-04-08 2:47 ` [PATCH 2/3] nvmet: pci-epf: Clear CC and CSTS when disabling the controller Damien Le Moal @ 2025-04-08 2:47 ` Damien Le Moal 2025-04-10 8:35 ` Keith Busch ` (2 more replies) 2025-04-10 8:05 ` [PATCH 0/3] NVMe PCI endpoint target fixes Damien Le Moal 3 siblings, 3 replies; 19+ messages in thread From: Damien Le Moal @ 2025-04-08 2:47 UTC (permalink / raw) To: linux-nvme, Keith Busch, Christoph Hellwig, Sagi Grimberg Since the link_up boolean field of struct nvmet_pci_epf_ctrl is always set to true when nvmet_pci_epf_start_ctrl() is called, assign true to this field in nvmet_pci_epf_start_ctrl(). Conversely, since this field is set to false when nvmet_pci_epf_stop_ctrl() is called, set this field to false directly inside that function. While at it, also add information messages to notify the user of the PCI link state changes to help troubleshoot any link stability issues without needing to enable debug messages. Signed-off-by: Damien Le Moal <dlemoal@kernel.org> --- drivers/nvme/target/pci-epf.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c index f18faf407eab..db2da0595423 100644 --- a/drivers/nvme/target/pci-epf.c +++ b/drivers/nvme/target/pci-epf.c @@ -2086,11 +2086,18 @@ static int nvmet_pci_epf_create_ctrl(struct nvmet_pci_epf *nvme_epf, static void nvmet_pci_epf_start_ctrl(struct nvmet_pci_epf_ctrl *ctrl) { + + dev_info(ctrl->dev, "PCI link up\n"); + ctrl->link_up = true; + schedule_delayed_work(&ctrl->poll_cc, NVMET_PCI_EPF_CC_POLL_INTERVAL); } static void nvmet_pci_epf_stop_ctrl(struct nvmet_pci_epf_ctrl *ctrl) { + dev_info(ctrl->dev, "PCI link down\n"); + ctrl->link_up = false; + cancel_delayed_work_sync(&ctrl->poll_cc); nvmet_pci_epf_disable_ctrl(ctrl, false); @@ -2317,10 +2324,8 @@ static int nvmet_pci_epf_epc_init(struct pci_epf *epf) if (ret) goto out_clear_bar; - if (!epc_features->linkup_notifier) { - ctrl->link_up = true; + if (!epc_features->linkup_notifier) nvmet_pci_epf_start_ctrl(&nvme_epf->ctrl); - } return 0; @@ -2336,7 +2341,6 @@ static void nvmet_pci_epf_epc_deinit(struct pci_epf *epf) struct nvmet_pci_epf *nvme_epf = epf_get_drvdata(epf); struct nvmet_pci_epf_ctrl *ctrl = &nvme_epf->ctrl; - ctrl->link_up = false; nvmet_pci_epf_destroy_ctrl(ctrl); nvmet_pci_epf_deinit_dma(nvme_epf); @@ -2348,7 +2352,6 @@ static int nvmet_pci_epf_link_up(struct pci_epf *epf) struct nvmet_pci_epf *nvme_epf = epf_get_drvdata(epf); struct nvmet_pci_epf_ctrl *ctrl = &nvme_epf->ctrl; - ctrl->link_up = true; nvmet_pci_epf_start_ctrl(ctrl); return 0; @@ -2359,7 +2362,6 @@ static int nvmet_pci_epf_link_down(struct pci_epf *epf) struct nvmet_pci_epf *nvme_epf = epf_get_drvdata(epf); struct nvmet_pci_epf_ctrl *ctrl = &nvme_epf->ctrl; - ctrl->link_up = false; nvmet_pci_epf_stop_ctrl(ctrl); return 0; -- 2.49.0 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH 3/3] nvmet: pci-epf: Cleanup link state management 2025-04-08 2:47 ` [PATCH 3/3] nvmet: pci-epf: Cleanup link state management Damien Le Moal @ 2025-04-10 8:35 ` Keith Busch 2025-04-10 11:56 ` Niklas Cassel 2025-04-14 22:05 ` Sagi Grimberg 2 siblings, 0 replies; 19+ messages in thread From: Keith Busch @ 2025-04-10 8:35 UTC (permalink / raw) To: Damien Le Moal; +Cc: linux-nvme, Christoph Hellwig, Sagi Grimberg On Tue, Apr 08, 2025 at 11:47:33AM +0900, Damien Le Moal wrote: > Since the link_up boolean field of struct nvmet_pci_epf_ctrl is always > set to true when nvmet_pci_epf_start_ctrl() is called, assign true to > this field in nvmet_pci_epf_start_ctrl(). Conversely, since this field > is set to false when nvmet_pci_epf_stop_ctrl() is called, set this field > to false directly inside that function. > > While at it, also add information messages to notify the user of the PCI > link state changes to help troubleshoot any link stability issues > without needing to enable debug messages. Looks good. Reviewed-by: Keith Busch <kbusch@kernel.org> ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 3/3] nvmet: pci-epf: Cleanup link state management 2025-04-08 2:47 ` [PATCH 3/3] nvmet: pci-epf: Cleanup link state management Damien Le Moal 2025-04-10 8:35 ` Keith Busch @ 2025-04-10 11:56 ` Niklas Cassel 2025-04-14 22:05 ` Sagi Grimberg 2 siblings, 0 replies; 19+ messages in thread From: Niklas Cassel @ 2025-04-10 11:56 UTC (permalink / raw) To: Damien Le Moal; +Cc: linux-nvme, Keith Busch, Christoph Hellwig, Sagi Grimberg On Tue, Apr 08, 2025 at 11:47:33AM +0900, Damien Le Moal wrote: > Since the link_up boolean field of struct nvmet_pci_epf_ctrl is always > set to true when nvmet_pci_epf_start_ctrl() is called, assign true to > this field in nvmet_pci_epf_start_ctrl(). Conversely, since this field > is set to false when nvmet_pci_epf_stop_ctrl() is called, set this field > to false directly inside that function. > > While at it, also add information messages to notify the user of the PCI > link state changes to help troubleshoot any link stability issues > without needing to enable debug messages. > > Signed-off-by: Damien Le Moal <dlemoal@kernel.org> > --- Reviewed-by: Niklas Cassel <cassel@kernel.org> ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 3/3] nvmet: pci-epf: Cleanup link state management 2025-04-08 2:47 ` [PATCH 3/3] nvmet: pci-epf: Cleanup link state management Damien Le Moal 2025-04-10 8:35 ` Keith Busch 2025-04-10 11:56 ` Niklas Cassel @ 2025-04-14 22:05 ` Sagi Grimberg 2 siblings, 0 replies; 19+ messages in thread From: Sagi Grimberg @ 2025-04-14 22:05 UTC (permalink / raw) To: Damien Le Moal, linux-nvme, Keith Busch, Christoph Hellwig Reviewed-by: Sagi Grimberg <sagi@grimberg.me> ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 0/3] NVMe PCI endpoint target fixes 2025-04-08 2:47 [PATCH 0/3] NVMe PCI endpoint target fixes Damien Le Moal ` (2 preceding siblings ...) 2025-04-08 2:47 ` [PATCH 3/3] nvmet: pci-epf: Cleanup link state management Damien Le Moal @ 2025-04-10 8:05 ` Damien Le Moal 2025-04-10 8:12 ` Christoph Hellwig 3 siblings, 1 reply; 19+ messages in thread From: Damien Le Moal @ 2025-04-10 8:05 UTC (permalink / raw) To: linux-nvme, Keith Busch, Christoph Hellwig, Sagi Grimberg On 4/8/25 11:47 AM, Damien Le Moal wrote: > Two bug fix patch and one cleanup patch in this series. > > The first patch fixes an issue with completion queue entries > initialization in the case of failed commands. > > The second patch fixes > the initialization of the CC register to ensure that we can always > detect that the host is attempting to enable the controller (with > CC.EN). > > The last patch cleans up/simplifies the management of the PCI link > state. Ping ? > > Damien Le Moal (3): > nvmet: pci-epf: Always fully initialize completion entries > nvmet: pci-epf: Clear CC and CSTS when disabling the controller > nvmet: pci-epf: Cleanup link state management > > drivers/nvme/target/pci-epf.c | 65 ++++++++++++++++++++++------------- > 1 file changed, 42 insertions(+), 23 deletions(-) > -- Damien Le Moal Western Digital Research ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 0/3] NVMe PCI endpoint target fixes 2025-04-10 8:05 ` [PATCH 0/3] NVMe PCI endpoint target fixes Damien Le Moal @ 2025-04-10 8:12 ` Christoph Hellwig 0 siblings, 0 replies; 19+ messages in thread From: Christoph Hellwig @ 2025-04-10 8:12 UTC (permalink / raw) To: Damien Le Moal; +Cc: linux-nvme, Keith Busch, Sagi Grimberg, Niklas Cassel > > The last patch cleans up/simplifies the management of the PCI link > > state. > > Ping ? Can I get someone else to look over them for an extra review? Niklas? ^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2025-04-14 22:09 UTC | newest] Thread overview: 19+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-04-08 2:47 [PATCH 0/3] NVMe PCI endpoint target fixes Damien Le Moal 2025-04-08 2:47 ` [PATCH 1/3] nvmet: pci-epf: Always fully initialize completion entries Damien Le Moal 2025-04-10 8:24 ` Keith Busch 2025-04-10 8:38 ` Christoph Hellwig 2025-04-10 9:15 ` Niklas Cassel 2025-04-14 22:03 ` Sagi Grimberg 2025-04-08 2:47 ` [PATCH 2/3] nvmet: pci-epf: Clear CC and CSTS when disabling the controller Damien Le Moal 2025-04-10 8:34 ` Keith Busch 2025-04-11 0:32 ` Damien Le Moal 2025-04-14 17:58 ` Keith Busch 2025-04-10 11:54 ` Niklas Cassel 2025-04-11 0:35 ` Damien Le Moal 2025-04-14 22:07 ` Sagi Grimberg 2025-04-08 2:47 ` [PATCH 3/3] nvmet: pci-epf: Cleanup link state management Damien Le Moal 2025-04-10 8:35 ` Keith Busch 2025-04-10 11:56 ` Niklas Cassel 2025-04-14 22:05 ` Sagi Grimberg 2025-04-10 8:05 ` [PATCH 0/3] NVMe PCI endpoint target fixes Damien Le Moal 2025-04-10 8:12 ` Christoph Hellwig
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.