From 9963f1805c9972a2271976b0fb6fede63a18dac2 Mon Sep 17 00:00:00 2001 From: Chuck Tuffli Date: Mon, 29 Jun 2020 00:31:17 +0000 Subject: [PATCH] bhyve: implement NVMe Flush command This adds support for the NVMe I/O command Flush. For block-based devices, submit a DIOCGFLUSH to the backing storage. Otherwise, command is treated like a NOP and completes with a Successful status. Tested by: Jason Tubnor MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D24880 --- usr.sbin/bhyve/pci_nvme.c | 44 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/usr.sbin/bhyve/pci_nvme.c b/usr.sbin/bhyve/pci_nvme.c index 85d06c46eddd..3ba13639a142 100644 --- a/usr.sbin/bhyve/pci_nvme.c +++ b/usr.sbin/bhyve/pci_nvme.c @@ -58,6 +58,7 @@ #include __FBSDID("$FreeBSD$"); +#include #include #include @@ -1387,6 +1388,46 @@ pci_nvme_io_partial(struct blockif_req *br, int err) pthread_cond_signal(&req->cv); } +/* + * Implements the Flush command. The specification states: + * If a volatile write cache is not present, Flush commands complete + * successfully and have no effect + * in the description of the Volatile Write Cache (VWC) field of the Identify + * Controller data. Therefore, set status to Success if the command is + * not supported (i.e. RAM or as indicated by the blockif). + */ +static bool +nvme_opc_flush(struct pci_nvme_softc *sc, + struct nvme_command *cmd, + struct pci_nvme_blockstore *nvstore, + struct pci_nvme_ioreq *req, + uint16_t *status) +{ + bool pending = false; + + if (nvstore->type == NVME_STOR_RAM) { + pci_nvme_status_genc(status, NVME_SC_SUCCESS); + } else { + int err; + + req->io_req.br_callback = pci_nvme_io_done; + + err = blockif_flush(nvstore->ctx, &req->io_req); + switch (err) { + case 0: + pending = true; + break; + case EOPNOTSUPP: + pci_nvme_status_genc(status, NVME_SC_SUCCESS); + break; + default: + pci_nvme_status_genc(status, NVME_SC_INTERNAL_DEVICE_ERROR); + } + } + + return (pending); +} + static bool nvme_opc_write_read(struct pci_nvme_softc *sc, struct nvme_command *cmd, @@ -1682,7 +1723,8 @@ pci_nvme_handle_io_cmd(struct pci_nvme_softc* sc, uint16_t idx) switch (cmd->opc) { case NVME_OPC_FLUSH: - pci_nvme_status_genc(&status, NVME_SC_SUCCESS); + pending = nvme_opc_flush(sc, cmd, &sc->nvstore, + req, &status); break; case NVME_OPC_WRITE: case NVME_OPC_READ: