Add an 'info nvme' HMP command for inspecting emulated NVMe
controllers from the QEMU monitor.
For each NVMe controller in the QOM tree the command prints:
- PCI BDF, vendor/device ID and BAR0 base address;
- Identify Controller fields visible to the host driver: SN, MN, FR
and CNTLID;
- the CC, CSTS and AQA registers (raw 32-bit values);
- the number of admin and active I/O submission/completion queues.
Useful when debugging the Linux NVMe driver against the QEMU emulation
without attaching gdb to the QEMU process.
Example:
(qemu) info nvme
/machine/peripheral-anon/device[0]
PCI: BDF 00:04.0 VID=8086 DID=5845 BAR0=0x00000000feb50000
ID: SN=NVME0001 MN=QEMU NVMe Ctrl FR=... CNTLID=0x0000
CC: 0x00460001
CSTS: 0x00000001
AQA: 0x001f001f
Queues: 1 admin + 4 IO SQ / 4 IO CQ
Signed-off-by: Mateusz Nowicki <[email protected]>
---
hmp-commands-info.hx | 13 ++++++++
hw/nvme/meson.build | 2 +-
hw/nvme/monitor.c | 76 ++++++++++++++++++++++++++++++++++++++++++++
qapi/machine.json | 17 ++++++++++
4 files changed, 107 insertions(+), 1 deletion(-)
create mode 100644 hw/nvme/monitor.c
diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index 82134eb6c2..b984691c3c 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -340,6 +340,19 @@ SRST
Show guest USB devices.
ERST
+ {
+ .name = "nvme",
+ .args_type = "",
+ .params = "",
+ .help = "show emulated NVMe controllers",
+ .cmd_info_hrt = qmp_x_query_nvme,
+ },
+
+SRST
+ ``info nvme``
+ Show emulated NVMe controllers.
+ERST
+
{
.name = "usbhost",
.args_type = "",
diff --git a/hw/nvme/meson.build b/hw/nvme/meson.build
index 7d5caa53c2..3017f058f9 100644
--- a/hw/nvme/meson.build
+++ b/hw/nvme/meson.build
@@ -1 +1 @@
-system_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('ctrl.c', 'dif.c',
'ns.c', 'subsys.c', 'nguid.c'))
\ No newline at end of file
+system_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('ctrl.c', 'dif.c',
'ns.c', 'subsys.c', 'nguid.c', 'monitor.c'))
\ No newline at end of file
diff --git a/hw/nvme/monitor.c b/hw/nvme/monitor.c
new file mode 100644
index 0000000000..95a6754437
--- /dev/null
+++ b/hw/nvme/monitor.c
@@ -0,0 +1,76 @@
+/*
+ * QEMU NVMe Controller monitor commands
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-machine.h"
+#include "qapi/type-helpers.h"
+#include "hw/pci/pci.h"
+
+#include "nvme.h"
+
+static int collect_one(Object *obj, void *opaque)
+{
+ GString *buf = opaque;
+ NvmeCtrl *n;
+ PCIDevice *pci;
+ pcibus_t bar0;
+ unsigned io_sq = 0, io_cq = 0;
+
+ if (!object_dynamic_cast(obj, TYPE_NVME)) {
+ return 0;
+ }
+ n = NVME(obj);
+ pci = PCI_DEVICE(n);
+ bar0 = pci_get_bar_addr(pci, 0);
+
+ for (unsigned i = 1; i <= n->params.max_ioqpairs; i++) {
+ if (n->sq && n->sq[i]) {
+ io_sq++;
+ }
+ if (n->cq && n->cq[i]) {
+ io_cq++;
+ }
+ }
+
+ g_string_append_printf(buf, "%s\n", object_get_canonical_path(obj));
+ g_string_append_printf(buf,
+ " PCI: BDF %02x:%02x.%x VID=%04x DID=%04x ",
+ pci_dev_bus_num(pci), PCI_SLOT(pci->devfn), PCI_FUNC(pci->devfn),
+ pci_get_word(pci->config + PCI_VENDOR_ID),
+ pci_get_word(pci->config + PCI_DEVICE_ID));
+ if (bar0 == PCI_BAR_UNMAPPED) {
+ g_string_append(buf, "BAR0=unmapped\n");
+ } else {
+ g_string_append_printf(buf, "BAR0=0x%016" PRIx64 "\n",
+ (uint64_t)bar0);
+ }
+ g_string_append_printf(buf,
+ " ID: SN=%.20s MN=%.40s FR=%.8s CNTLID=0x%04x\n",
+ n->id_ctrl.sn, n->id_ctrl.mn, n->id_ctrl.fr, n->cntlid);
+ g_string_append_printf(buf, " CC: 0x%08x\n",
+ ldl_le_p(&n->bar.cc));
+ g_string_append_printf(buf, " CSTS: 0x%08x\n",
+ ldl_le_p(&n->bar.csts));
+ g_string_append_printf(buf, " AQA: 0x%08x\n",
+ ldl_le_p(&n->bar.aqa));
+ g_string_append_printf(buf,
+ " Queues: 1 admin + %u IO SQ / %u IO CQ\n", io_sq, io_cq);
+ return 0;
+}
+
+HumanReadableText *qmp_x_query_nvme(Error **errp)
+{
+ g_autoptr(GString) buf = g_string_new("");
+
+ object_child_foreach_recursive(object_get_root(), collect_one, buf);
+
+ if (buf->len == 0) {
+ g_string_append(buf, "no NVMe controllers\n");
+ }
+
+ return human_readable_text_from_str(buf);
+}
diff --git a/qapi/machine.json b/qapi/machine.json
index 685e4e29b8..d4a589e768 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -1772,6 +1772,23 @@
'returns': 'HumanReadableText',
'features': [ 'unstable' ] }
+##
+# @x-query-nvme:
+#
+# Query state of emulated NVMe controllers.
+#
+# Features:
+#
+# @unstable: This command is meant for debugging.
+#
+# Returns: NVMe controller state as human-readable text
+#
+# Since: 11.1
+##
+{ 'command': 'x-query-nvme',
+ 'returns': 'HumanReadableText',
+ 'features': [ 'unstable' ] }
+
##
# @SmbiosEntryPointType:
#
--
2.53.0