On May 10 10:57, Mateusz Nowicki 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 > > 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++) {
I think this needs to run over n->conf_ioqpairs to also work for SR-IOV
VFs? Same goes for patch 2 I think.
> + 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
>
>
signature.asc
Description: PGP signature
