From owner-svn-src-head@freebsd.org Mon Jun 29 00:32:10 2020 Return-Path: Delivered-To: svn-src-head@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 9B72E359554; Mon, 29 Jun 2020 00:32:10 +0000 (UTC) (envelope-from chuck@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 49w7jP2BTnz43Q7; Mon, 29 Jun 2020 00:32:08 +0000 (UTC) (envelope-from chuck@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 80A8C1EA5A; Mon, 29 Jun 2020 00:31:48 +0000 (UTC) (envelope-from chuck@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 05T0Vmcp047379; Mon, 29 Jun 2020 00:31:48 GMT (envelope-from chuck@FreeBSD.org) Received: (from chuck@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 05T0Vmlf047378; Mon, 29 Jun 2020 00:31:48 GMT (envelope-from chuck@FreeBSD.org) Message-Id: <202006290031.05T0Vmlf047378@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: chuck set sender to chuck@FreeBSD.org using -f From: Chuck Tuffli Date: Mon, 29 Jun 2020 00:31:48 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r362755 - head/usr.sbin/bhyve X-SVN-Group: head X-SVN-Commit-Author: chuck X-SVN-Commit-Paths: head/usr.sbin/bhyve X-SVN-Commit-Revision: 362755 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.33 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 29 Jun 2020 00:32:10 -0000 Author: chuck Date: Mon Jun 29 00:31:47 2020 New Revision: 362755 URL: https://svnweb.freebsd.org/changeset/base/362755 Log: bhyve: implement NVMe Format NVM command The Format NVM command mainly allows the host to specify the block size and protection information used for the Namespace. As the bhyve implementation simply maps the capabilities of the backing storage through to the guest, there isn't anything to implement. But a side effect of the format is the NVMe Controller shall not return any data previously written (i.e. erase previously written data). This patch implements this later behavior to provide a compliant implementation. Fixes UNH Test 1.6 Tested by: Jason Tubnor MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D24889 Modified: head/usr.sbin/bhyve/pci_nvme.c Modified: head/usr.sbin/bhyve/pci_nvme.c ============================================================================== --- head/usr.sbin/bhyve/pci_nvme.c Mon Jun 29 00:31:44 2020 (r362754) +++ head/usr.sbin/bhyve/pci_nvme.c Mon Jun 29 00:31:47 2020 (r362755) @@ -280,6 +280,9 @@ struct pci_nvme_softc { static void pci_nvme_io_partial(struct blockif_req *br, int err); +static struct pci_nvme_ioreq *pci_nvme_get_ioreq(struct pci_nvme_softc *); +static void pci_nvme_release_ioreq(struct pci_nvme_softc *, struct pci_nvme_ioreq *); +static void pci_nvme_io_done(struct blockif_req *, int); /* Controller Configuration utils */ #define NVME_CC_GET_EN(cc) \ @@ -645,6 +648,7 @@ pci_nvme_init_controller(struct vmctx *ctx, struct pci sc->compl_queues[0].size = acqs; sc->compl_queues[0].qbase = vm_map_gpa(ctx, sc->regs.acq, sizeof(struct nvme_completion) * acqs); + sc->compl_queues[0].intr_en = NVME_CQ_INTEN; DPRINTF("%s mapping Admin-CQ guest 0x%lx, host: %p", __func__, sc->regs.acq, sc->compl_queues[0].qbase); @@ -1255,6 +1259,71 @@ nvme_opc_get_features(struct pci_nvme_softc* sc, struc } static int +nvme_opc_format_nvm(struct pci_nvme_softc* sc, struct nvme_command* command, + struct nvme_completion* compl) +{ + uint8_t ses, lbaf, pi; + + /* Only supports Secure Erase Setting - User Data Erase */ + ses = (command->cdw10 >> 9) & 0x7; + if (ses > 0x1) { + pci_nvme_status_genc(&compl->status, NVME_SC_INVALID_FIELD); + return (1); + } + + /* Only supports a single LBA Format */ + lbaf = command->cdw10 & 0xf; + if (lbaf != 0) { + pci_nvme_status_tc(&compl->status, NVME_SCT_COMMAND_SPECIFIC, + NVME_SC_INVALID_FORMAT); + return (1); + } + + /* Doesn't support Protection Infomation */ + pi = (command->cdw10 >> 5) & 0x7; + if (pi != 0) { + pci_nvme_status_genc(&compl->status, NVME_SC_INVALID_FIELD); + return (1); + } + + if (sc->nvstore.type == NVME_STOR_RAM) { + if (sc->nvstore.ctx) + free(sc->nvstore.ctx); + sc->nvstore.ctx = calloc(1, sc->nvstore.size); + pci_nvme_status_genc(&compl->status, NVME_SC_SUCCESS); + } else { + struct pci_nvme_ioreq *req; + int err; + + req = pci_nvme_get_ioreq(sc); + if (req == NULL) { + pci_nvme_status_genc(&compl->status, + NVME_SC_INTERNAL_DEVICE_ERROR); + WPRINTF("%s: unable to allocate IO req", __func__); + return (1); + } + req->nvme_sq = &sc->submit_queues[0]; + req->sqid = 0; + req->opc = command->opc; + req->cid = command->cid; + req->nsid = command->nsid; + + req->io_req.br_offset = 0; + req->io_req.br_resid = sc->nvstore.size; + req->io_req.br_callback = pci_nvme_io_done; + + err = blockif_delete(sc->nvstore.ctx, &req->io_req); + if (err) { + pci_nvme_status_genc(&compl->status, + NVME_SC_INTERNAL_DEVICE_ERROR); + pci_nvme_release_ioreq(sc, req); + } + } + + return (1); +} + +static int nvme_opc_abort(struct pci_nvme_softc* sc, struct nvme_command* command, struct nvme_completion* compl) { @@ -1351,6 +1420,15 @@ pci_nvme_handle_admin_cmd(struct pci_nvme_softc* sc, u nvme_opc_async_event_req(sc, cmd, &compl); */ compl.status = NVME_NO_STATUS; + break; + case NVME_OPC_FORMAT_NVM: + DPRINTF("%s command FORMAT_NVM", __func__); + if ((sc->ctrldata.oacs & + (1 << NVME_CTRLR_DATA_OACS_FORMAT_SHIFT)) == 0) { + pci_nvme_status_genc(&compl.status, NVME_SC_INVALID_OPCODE); + } + compl.status = NVME_NO_STATUS; + nvme_opc_format_nvm(sc, cmd, &compl); break; default: DPRINTF("0x%x command is not implemented",