* Mateusz Nowicki ([email protected]) wrote: > 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
I won't claim to know what those NVMe magic numbers mean, but I'll trust you they're useful. > 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 ++++++++++ So that lot looks OK from an HMP point of view, I wonder if qapi/machine.json is the right place for it. Markus? Acked-by: Dr. David Alan Gilbert <[email protected]> > 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 > -- -----Open up your eyes, open up your mind, open up your code ------- / Dr. David Alan Gilbert | Running GNU/Linux | Happy \ \ dave @ treblig.org | | In Hex / \ _________________________|_____ http://www.treblig.org |_______/
