commit 813b7d848545c44b1a81a347e21a14a7e56242bd Author: Kyle Evans Date: Sun Mar 5 22:28:25 2023 -0600 Convert to kobj diff --git a/sys/conf/files b/sys/conf/files index 1d16ac012e3d..a0653f2ceb0c 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -2530,6 +2530,7 @@ dev/nvme/nvme.c optional nvme dev/nvme/nvme_ahci.c optional nvme ahci dev/nvme/nvme_ctrlr.c optional nvme dev/nvme/nvme_ctrlr_cmd.c optional nvme +dev/nvme/nvme_if.m optional nvme dev/nvme/nvme_ns.c optional nvme dev/nvme/nvme_ns_cmd.c optional nvme dev/nvme/nvme_pci.c optional nvme pci diff --git a/sys/dev/nvme/nvme.c b/sys/dev/nvme/nvme.c index 1b06d490af82..b75d558a36d5 100644 --- a/sys/dev/nvme/nvme.c +++ b/sys/dev/nvme/nvme.c @@ -51,16 +51,6 @@ struct nvme_consumer nvme_consumer[NVME_MAX_CONSUMERS]; int32_t nvme_retry_count; -/* Standard/default set of nvme_ops */ -struct nvme_ops nvme_ops = { - .enable = NULL, - - .sq_enter = nvme_qpair_sq_enter, - .sq_leave = nvme_qpair_sq_leave, - /* more to come */ - -}; - MALLOC_DEFINE(M_NVME, "nvme", "nvme(4) memory allocations"); static void @@ -140,8 +130,6 @@ nvme_attach(device_t dev) ctrlr->config_hook.ich_func = nvme_ctrlr_start_config_hook; ctrlr->config_hook.ich_arg = ctrlr; - if (ctrlr->ops == NULL) - ctrlr->ops = &nvme_ops; if (config_intrhook_establish(&ctrlr->config_hook) != 0) return (ENOMEM); diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c index c6c554f5d0b0..1c4edbef79cf 100644 --- a/sys/dev/nvme/nvme_ctrlr.c +++ b/sys/dev/nvme/nvme_ctrlr.c @@ -48,6 +48,8 @@ __FBSDID("$FreeBSD$"); #include "nvme_private.h" +#include "nvme_if.h" + #define B4_CHK_RDY_DELAY_MS 2300 /* work around controller bug */ static void nvme_ctrlr_construct_and_submit_aer(struct nvme_controller *ctrlr, @@ -363,8 +365,7 @@ nvme_ctrlr_enable(struct nvme_controller *ctrlr) return (nvme_ctrlr_wait_for_ready(ctrlr, 1)); } - if (ctrlr->ops->enable != NULL) - ctrlr->ops->enable(ctrlr); + NVME_ENABLE(ctrlr->dev, ctrlr); /* EN == 0 already wait for RDY == 0 or timeout & fail */ err = nvme_ctrlr_wait_for_ready(ctrlr, 0); diff --git a/sys/dev/nvme/nvme_if.m b/sys/dev/nvme/nvme_if.m new file mode 100644 index 000000000000..bfffe2991c4c --- /dev/null +++ b/sys/dev/nvme/nvme_if.m @@ -0,0 +1,57 @@ +#- +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2022 Kyle Evans +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +#include + +INTERFACE nvme; + +CODE { + static void + null_nvme_enable(struct nvme_controller *ctrlr) + { + + } +}; + +METHOD void enable { + device_t dev; + struct nvme_controller *ctrlr; +} DEFAULT null_nvme_enable; + +METHOD uint32_t sq_enter { + device_t dev; + struct nvme_controller *ctrlr; + struct nvme_qpair *qpair; +} DEFAULT nvme_qpair_sq_enter; + +METHOD void sq_leave { + device_t dev; + struct nvme_controller *ctrlr; + struct nvme_qpair *qpair; +} DEFAULT nvme_qpair_sq_leave; diff --git a/sys/dev/nvme/nvme_private.h b/sys/dev/nvme/nvme_private.h index 948064f445d0..5fe33009872d 100644 --- a/sys/dev/nvme/nvme_private.h +++ b/sys/dev/nvme/nvme_private.h @@ -226,15 +226,6 @@ struct nvme_namespace { struct mtx lock; }; -struct nvme_ops { - void (*enable)(struct nvme_controller *); - uint32_t (*sq_enter)(struct nvme_controller *, - struct nvme_qpair *); - void (*sq_leave)(struct nvme_controller *, - struct nvme_qpair *); -}; - -extern struct nvme_ops nvme_ops; uint32_t nvme_qpair_sq_enter(struct nvme_controller *ctrlr, struct nvme_qpair *qpair); void nvme_qpair_sq_leave(struct nvme_controller *ctrlr, @@ -260,7 +251,6 @@ struct nvme_controller { bus_space_handle_t bus_handle; int resource_id; struct resource *resource; - struct nvme_ops *ops; /* * The NVMe spec allows for the MSI-X table to be placed in BAR 4/5, diff --git a/sys/dev/nvme/nvme_qpair.c b/sys/dev/nvme/nvme_qpair.c index e27af15d17bb..c04e7eed03e0 100644 --- a/sys/dev/nvme/nvme_qpair.c +++ b/sys/dev/nvme/nvme_qpair.c @@ -39,6 +39,8 @@ __FBSDID("$FreeBSD$"); #include "nvme_private.h" +#include "nvme_if.h" + typedef enum error_print { ERROR_PRINT_NONE, ERROR_PRINT_NO_RETRY, ERROR_PRINT_ALL } error_print_t; #define DO_NOT_RETRY 1 @@ -1097,9 +1099,9 @@ nvme_qpair_submit_tracker(struct nvme_qpair *qpair, struct nvme_tracker *tr) tr->deadline = SBT_MAX; /* Copy the command from the tracker to the submission queue. */ - indx = (ctrlr->ops->sq_enter)(ctrlr, qpair); + indx = NVME_SQ_ENTER(ctrlr->dev, ctrlr, qpair); memcpy(&qpair->cmd[indx], &req->cmd, sizeof(req->cmd)); - (ctrlr->ops->sq_leave)(ctrlr, qpair); + NVME_SQ_LEAVE(ctrlr->dev, ctrlr, qpair); qpair->num_cmds++; } diff --git a/sys/modules/nvme/Makefile b/sys/modules/nvme/Makefile index 7aad95d55e60..8467dc527c40 100644 --- a/sys/modules/nvme/Makefile +++ b/sys/modules/nvme/Makefile @@ -8,6 +8,7 @@ SRCS = nvme.c \ nvme_ahci.c \ nvme_ctrlr.c \ nvme_ctrlr_cmd.c \ + nvme_if.c \ nvme_ns.c \ nvme_ns_cmd.c \ nvme_pci.c \ @@ -19,6 +20,7 @@ SRCS = nvme.c \ \ bus_if.h \ device_if.h \ + nvme_if.h \ opt_cam.h \ opt_nvme.h \ pci_if.h diff --git a/sys/dev/nvme/nvme_ans.c b/sys/dev/nvme/nvme_ans.c new file mode 100644 index 000000000000..fa01d760a8eb --- /dev/null +++ b/sys/dev/nvme/nvme_ans.c @@ -0,0 +1,385 @@ +/* Copyright TBD */ +/* derived in part from nvms_ahci.c, also OpenBSD aplns.c */ +/*- + * Copyright (C) 2017 Olivier Houchard + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* $OpenBSD: aplns.c,v 1.12 2022/06/12 16:00:12 kettenis Exp $ */ +/* + * Copyright (c) 2014, 2021 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "nvme_private.h" +#include "nvme_if.h" + +#define ANS_CPU_CTRL 0x0044 +#define ANS_CPU_CTRL_RUN (1 << 4) + +#define ANS_MAX_PEND_CMDS_CTRL 0x01210 +#define ANS_MAX_QUEUE_DEPTH 64 +#define ANS_BOOT_STATUS 0x01300 +#define ANS_BOOT_STATUS_OK 0xde71ce55 +#define ANS_MODESEL_REG 0x01304 +#define ANS_UNKNOWN_CTRL 0x24008 +#define ANS_PRP_NULL_CHECK (1 << 11) +#define ANS_LINEAR_SQ_CTRL 0x24908 +#define ANS_LINEAR_SQ_CTRL_EN (1 << 0) +#define ANS_LINEAR_ASQ_DB 0x2490c +#define ANS_LINEAR_IOSQ_DB 0x24910 + +#define ANS_NVMMU_NUM 0x28100 +#define ANS_NVMMU_BASE_ASQ 0x28108 +#define ANS_NVMMU_BASE_IOSQ 0x28110 +#define ANS_NVMMU_TCB_INVAL 0x28118 +#define ANS_NVMMU_TCB_STAT 0x28120 + +#define ANS_NVMMU_TCB_SIZE 0x4000 +#define ANS_NVMMU_TCB_PITCH 0x80 + +struct ans_nvmmu_tcb { + uint8_t tcb_opcode; + uint8_t tcb_flags; +#define ANS_NVMMU_TCB_WRITE (1 << 0) +#define ANS_NVMMU_TCB_READ (1 << 1) + uint8_t tcb_cid; + uint8_t tcb_pad0[1]; + + uint32_t tcb_prpl_len; + uint8_t tcb_pad1[16]; + + uint64_t tcb_prp[2]; +}; + +struct nvme_ans_controller { + struct nvme_controller nvme; /* base class, must be first */ + /* SART info */ + bus_space_tag_t bus_tag; + bus_space_handle_t bus_handle; + int resource_id; + struct resource *resource; + + uint32_t sart; + struct rtkit rtkit; + struct rtkit_state *rtkit_state; + struct nvme_dmamem *nvmmu; + mbox_t mbox; +}; + +#define ANSDEVICE2SOFTC(dev) \ + ((struct nvme_ans_controller *) device_get_softc(dev)) + +/* + * The following two macros work on an nvme_ans_controller (for SART) + * as well as nvme_controller (for NVME and Apple/ANS) by virtue of + * common structure element names. + */ +#define NVME_ANS_READ_4(_sc, reg) \ + bus_space_read_4((_sc)->bus_tag, (_sc)->bus_handle, (reg)) +#define NVME_ANS_WRITE_4(_sc, reg, val) \ + bus_space_write_4((_sc)->bus_tag, (_sc)->bus_handle, (reg), (val)) + +static int nvme_ans_probe(device_t dev); +static int nvme_ans_attach(device_t dev); +//static int nvme_ans_detach(device_t dev); + +static int nvme_ans_sart_map(void *, bus_addr_t, bus_size_t); +//extern int apple_sart_map(uint32_t, bus_addr_t, bus_size_t); +void nvme_ans_enable(device_t dev, struct nvme_controller *ctrlr); +uint32_t nvme_ans_sq_enter(device_t dev, + struct nvme_controller *ctrlr, + struct nvme_qpair *qpair); +void nvme_ans_sq_leave(device_t dev, + struct nvme_controller *ctrlr, + struct nvme_qpair *qpair); + +static device_method_t nvme_ans_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, nvme_ans_probe), + DEVMETHOD(device_attach, nvme_ans_attach), + DEVMETHOD(device_detach, nvme_detach), + DEVMETHOD(device_shutdown, nvme_shutdown), + + /* NVME interface */ + DEVMETHOD(nvme_enable, nvme_ans_enable), + DEVMETHOD(nvme_sq_enter, nvme_ans_sq_enter), + DEVMETHOD(nvme_sq_leave, nvme_ans_sq_leave), + + { 0, 0 } +}; + +static driver_t nvme_ans_driver = { + "nvme", + nvme_ans_methods, + sizeof(struct nvme_ans_controller), +}; + +DRIVER_MODULE(nvme, simplebus, nvme_ans_driver, NULL, NULL); + +static struct ofw_compat_data compat_data[] = { + {"apple,nvme-m1", 1}, + {"apple,nvme-ans2", 1}, + {NULL, 0} +}; + +static int +nvme_ans_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) + return (ENXIO); + + device_set_desc(dev, "Apple NVME Storage controller"); + return (BUS_PROBE_DEFAULT); +} + +static int +nvme_ans_attach(device_t dev) +{ + struct nvme_ans_controller *sc = ANSDEVICE2SOFTC(dev); + struct nvme_controller *ctrlr = &sc->nvme; + phandle_t node; + uint32_t ctrl, status; + ssize_t sret; + int ret; + + /* need registers for NVME, SART */ + +//printf("ANS attach\n"); DELAY(5000000); + /* Map NVME registers */ + node = ofw_bus_get_node(dev); + if (ofw_bus_find_string_index(node, "reg-names", "nvme", + &ctrlr->resource_id) != 0) { + device_printf(dev, "couldn't get \"nvme\" regs\n"); + ret = ENXIO; + goto bad; + } +//printf("found nvme\n"); DELAY(2000000); + ctrlr->resource = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &ctrlr->resource_id, RF_ACTIVE); + + if (ctrlr->resource == NULL) { + device_printf(dev, "unable to allocate NVME mem resource\n"); + ret = ENOMEM; + goto bad; + } + ctrlr->bus_tag = rman_get_bustag(ctrlr->resource); + ctrlr->bus_handle = rman_get_bushandle(ctrlr->resource); + ctrlr->regs = (struct nvme_registers *)ctrlr->bus_handle; + +//printf("SART "); DELAY(2000000); + /* Map SART registers */ + if (ofw_bus_find_string_index(node, "reg-names", "ans", + &sc->resource_id) != 0) { + device_printf(dev, "couldn't get \"ans\" regs\n"); + ret = ENXIO; + goto bad; + } + sc->resource = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->resource_id, RF_ACTIVE); + + if (sc->resource == NULL) { + device_printf(dev, "unable to allocate SART mem resource\n"); + ret = ENOMEM; + goto bad; + } + sc->bus_tag = rman_get_bustag(sc->resource); + sc->bus_handle = rman_get_bushandle(sc->resource); + + //power_domain_enable(faa->fa_node); + +//printf("IRQ "); DELAY(2000000); + /* Allocate and setup IRQ */ + ctrlr->rid = 0; + ctrlr->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &ctrlr->rid, RF_SHAREABLE | RF_ACTIVE); + if (ctrlr->res == NULL) { + device_printf(dev, "unable to allocate interrupt\n"); + ret = ENOMEM; + goto bad; + } + + ctrlr->msi_count = 0; + ctrlr->num_io_queues = 1; + + /* + * We're attached via this funky mechanism. Flag the controller so that + * it avoids things that can't work when we do that, like asking for + * PCI config space entries. + */ + ctrlr->quirks |= QUIRK_ANS; + + sret = OF_getencprop(node, "apple,sart", &sc->sart, + sizeof(sc->sart)); /* XXX ??? */ + if (sret != sizeof(sc->sart)) + device_printf(dev, "OF_getprop apple,sart %jd\n", + (intmax_t) sret); + sc->rtkit.rk_cookie = sc; + //sc->rtkit.rk_dmat = ; bus_dma_tag_create(...) /* XXX ??? */ + ret = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent? */ + PAGE_SIZE, 0, /* alignment, bounds */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + 64 * 1024, /* maxsize ??? */ + 1, /* nsegments */ + 64 * 1024, /* maxsegsize ??? */ + 0 /*BUS_DMA_ALLOCNOW*/, /* flags */ + NULL, /* lockfunc */ + NULL, /* lockarg */ + &sc->rtkit.rk_dmat); + if (ret != 0) { + device_printf(dev, "bus_dma_tag_create failed %d\n", ret); + goto bad; + } + sc->rtkit.rk_map = nvme_ans_sart_map; + + ret = mbox_get_by_ofw_idx(dev, node, 0, &sc->mbox); + if (ret < 0) { + device_printf(dev, "can't set up rtkit mailbox ret %d\n", ret); + ret = ENXIO; + goto bad; + } + sc->rtkit_state = rtkit_init(node, NULL, &sc->rtkit, sc->mbox); + if (sc->rtkit_state == NULL) { + device_printf(dev, "can't set up rtkit\n"); + ret = ENXIO; + goto bad; + } + /* XXX how do we set up mbox callback? */ + +//printf("hit regs\n"); DELAY(2000000); + ctrl = NVME_ANS_READ_4(sc, ANS_CPU_CTRL); + NVME_ANS_WRITE_4(sc, ANS_CPU_CTRL, ctrl | ANS_CPU_CTRL_RUN); + + status = NVME_ANS_READ_4(ctrlr, ANS_BOOT_STATUS); + if (status != ANS_BOOT_STATUS_OK) + rtkit_boot(sc->rtkit_state); + + status = NVME_ANS_READ_4(ctrlr, ANS_BOOT_STATUS); + if (status != ANS_BOOT_STATUS_OK) { + device_printf(dev, "firmware not ready\n"); + ret = ENXIO; + goto bad; + } + + if (bus_setup_intr(dev, ctrlr->res, + INTR_TYPE_MISC | INTR_MPSAFE, NULL, nvme_ctrlr_shared_handler, + ctrlr, &ctrlr->tag) != 0) { + device_printf(dev, "unable to setup interrupt\n"); + ret = ENOMEM; + goto bad; + } + ctrlr->tag = (void *)0x1; + + NVME_ANS_WRITE_4(ctrlr, ANS_LINEAR_SQ_CTRL, ANS_LINEAR_SQ_CTRL_EN); + NVME_ANS_WRITE_4(ctrlr, ANS_MAX_PEND_CMDS_CTRL, + (ANS_MAX_QUEUE_DEPTH << 16) | ANS_MAX_QUEUE_DEPTH); + + ctrl = NVME_ANS_READ_4(ctrlr, ANS_UNKNOWN_CTRL); + NVME_ANS_WRITE_4(ctrlr, ANS_UNKNOWN_CTRL, ctrl & ~ANS_PRP_NULL_CHECK); + + //ctrlr->sc_ios = faa->fa_reg[0].size; /* XXX */ + //ctrlr->sc_openings = 1; + +//printf("nvme_attach\n"); DELAY(2000000); + return (nvme_attach(dev)); /* Note: failure frees resources */ +bad: +printf("bad:\n"); DELAY(5000000); + if (ctrlr->resource != NULL) { + bus_release_resource(dev, SYS_RES_MEMORY, + ctrlr->resource_id, ctrlr->resource); + } + if (sc->resource != NULL) { + bus_release_resource(dev, SYS_RES_MEMORY, + sc->resource_id, sc->resource); + } + if (ctrlr->res) { + bus_release_resource(dev, SYS_RES_IRQ, + rman_get_rid(ctrlr->res), ctrlr->res); + } + + return (ret); +} + +static int +nvme_ans_sart_map(void *cookie, bus_addr_t addr, bus_size_t size) +{ + struct nvme_ans_controller *sc = cookie; + + return (apple_sart_map(sc->sart, addr, size)); +} + +void +nvme_ans_enable(device_t dev, struct nvme_controller *ctrlr) +{ +nvme_printf(ctrlr, "enable\n"); + bus_space_write_4(ctrlr->bus_tag, ctrlr->bus_handle, ANS_NVMMU_NUM, + (ANS_NVMMU_TCB_SIZE / ANS_NVMMU_TCB_PITCH) - 1); + bus_space_write_4(ctrlr->bus_tag, ctrlr->bus_handle, ANS_MODESEL_REG, 0); +} + +uint32_t +nvme_ans_sq_enter(device_t dev, struct nvme_controller *ctrlr, + struct nvme_qpair *qpair) +{ +nvme_printf(ctrlr, "sq_enter\n"); + return (0/*notyet*/); +} + +void +nvme_ans_sq_leave(device_t dev, struct nvme_controller *ctrlr, + struct nvme_qpair *qpair) +{ +nvme_printf(ctrlr, "sq_leave\n"); +}