mirror of
https://github.com/opnsense/src.git
synced 2026-06-07 07:42:26 -04:00
This is the client (initiator in SCSI terms) for NVMe over Fabrics. Userland is responsible for creating a set of queue pairs and then handing them off via an ioctl to this driver, e.g. via the 'connect' command from nvmecontrol(8). An nvmeX new-bus device is created at the top-level to represent the remote controller similar to PCI nvmeX devices for PCI-express controllers. As with nvme(4), namespace devices named /dev/nvmeXnsY are created and pass through commands can be submitted to either the namespace devices or the controller device. For example, 'nvmecontrol identify nvmeX' works for a remote Fabrics controller the same as for a PCI-express controller. nvmf exports remote namespaces via nda(4) devices using the new NVMF CAM transport. nvmf does not support nvd(4), only nda(4). Sponsored by: Chelsio Communications Differential Revision: https://reviews.freebsd.org/D44714
171 lines
4.4 KiB
C
171 lines
4.4 KiB
C
/*-
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*
|
|
* Copyright (c) 2023-2024 Chelsio Communications, Inc.
|
|
* Written by: John Baldwin <jhb@FreeBSD.org>
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/memdesc.h>
|
|
#include <sys/systm.h>
|
|
#include <dev/nvme/nvme.h>
|
|
#include <dev/nvmf/nvmf.h>
|
|
#include <dev/nvmf/nvmf_proto.h>
|
|
#include <dev/nvmf/host/nvmf_var.h>
|
|
|
|
bool
|
|
nvmf_cmd_get_property(struct nvmf_softc *sc, uint32_t offset, uint8_t size,
|
|
nvmf_request_complete_t *cb, void *cb_arg, int how)
|
|
{
|
|
struct nvmf_fabric_prop_get_cmd cmd;
|
|
struct nvmf_request *req;
|
|
|
|
memset(&cmd, 0, sizeof(cmd));
|
|
cmd.opcode = NVME_OPC_FABRICS_COMMANDS;
|
|
cmd.fctype = NVMF_FABRIC_COMMAND_PROPERTY_GET;
|
|
switch (size) {
|
|
case 4:
|
|
cmd.attrib.size = NVMF_PROP_SIZE_4;
|
|
break;
|
|
case 8:
|
|
cmd.attrib.size = NVMF_PROP_SIZE_8;
|
|
break;
|
|
default:
|
|
panic("Invalid property size");
|
|
}
|
|
cmd.ofst = htole32(offset);
|
|
|
|
req = nvmf_allocate_request(sc->admin, &cmd, cb, cb_arg, how);
|
|
if (req != NULL)
|
|
nvmf_submit_request(req);
|
|
return (req != NULL);
|
|
}
|
|
|
|
bool
|
|
nvmf_cmd_set_property(struct nvmf_softc *sc, uint32_t offset, uint8_t size,
|
|
uint64_t value, nvmf_request_complete_t *cb, void *cb_arg, int how)
|
|
{
|
|
struct nvmf_fabric_prop_set_cmd cmd;
|
|
struct nvmf_request *req;
|
|
|
|
memset(&cmd, 0, sizeof(cmd));
|
|
cmd.opcode = NVME_OPC_FABRICS_COMMANDS;
|
|
cmd.fctype = NVMF_FABRIC_COMMAND_PROPERTY_SET;
|
|
switch (size) {
|
|
case 4:
|
|
cmd.attrib.size = NVMF_PROP_SIZE_4;
|
|
cmd.value.u32.low = htole32(value);
|
|
break;
|
|
case 8:
|
|
cmd.attrib.size = NVMF_PROP_SIZE_8;
|
|
cmd.value.u64 = htole64(value);
|
|
break;
|
|
default:
|
|
panic("Invalid property size");
|
|
}
|
|
cmd.ofst = htole32(offset);
|
|
|
|
req = nvmf_allocate_request(sc->admin, &cmd, cb, cb_arg, how);
|
|
if (req != NULL)
|
|
nvmf_submit_request(req);
|
|
return (req != NULL);
|
|
}
|
|
|
|
bool
|
|
nvmf_cmd_keep_alive(struct nvmf_softc *sc, nvmf_request_complete_t *cb,
|
|
void *cb_arg, int how)
|
|
{
|
|
struct nvme_command cmd;
|
|
struct nvmf_request *req;
|
|
|
|
memset(&cmd, 0, sizeof(cmd));
|
|
cmd.opc = NVME_OPC_KEEP_ALIVE;
|
|
|
|
req = nvmf_allocate_request(sc->admin, &cmd, cb, cb_arg, how);
|
|
if (req != NULL)
|
|
nvmf_submit_request(req);
|
|
return (req != NULL);
|
|
}
|
|
|
|
bool
|
|
nvmf_cmd_identify_active_namespaces(struct nvmf_softc *sc, uint32_t id,
|
|
struct nvme_ns_list *nslist, nvmf_request_complete_t *req_cb,
|
|
void *req_cb_arg, nvmf_io_complete_t *io_cb, void *io_cb_arg, int how)
|
|
{
|
|
struct nvme_command cmd;
|
|
struct memdesc mem;
|
|
struct nvmf_request *req;
|
|
|
|
memset(&cmd, 0, sizeof(cmd));
|
|
cmd.opc = NVME_OPC_IDENTIFY;
|
|
|
|
/* 5.15.1 Use CNS of 0x02 for namespace data. */
|
|
cmd.cdw10 = htole32(2);
|
|
cmd.nsid = htole32(id);
|
|
|
|
req = nvmf_allocate_request(sc->admin, &cmd, req_cb, req_cb_arg, how);
|
|
if (req == NULL)
|
|
return (false);
|
|
mem = memdesc_vaddr(nslist, sizeof(*nslist));
|
|
nvmf_capsule_append_data(req->nc, &mem, sizeof(*nslist), false,
|
|
io_cb, io_cb_arg);
|
|
nvmf_submit_request(req);
|
|
return (true);
|
|
}
|
|
|
|
bool
|
|
nvmf_cmd_identify_namespace(struct nvmf_softc *sc, uint32_t id,
|
|
struct nvme_namespace_data *nsdata, nvmf_request_complete_t *req_cb,
|
|
void *req_cb_arg, nvmf_io_complete_t *io_cb, void *io_cb_arg, int how)
|
|
{
|
|
struct nvme_command cmd;
|
|
struct memdesc mem;
|
|
struct nvmf_request *req;
|
|
|
|
memset(&cmd, 0, sizeof(cmd));
|
|
cmd.opc = NVME_OPC_IDENTIFY;
|
|
|
|
/* 5.15.1 Use CNS of 0x00 for namespace data. */
|
|
cmd.cdw10 = htole32(0);
|
|
cmd.nsid = htole32(id);
|
|
|
|
req = nvmf_allocate_request(sc->admin, &cmd, req_cb, req_cb_arg, how);
|
|
if (req == NULL)
|
|
return (false);
|
|
mem = memdesc_vaddr(nsdata, sizeof(*nsdata));
|
|
nvmf_capsule_append_data(req->nc, &mem, sizeof(*nsdata), false,
|
|
io_cb, io_cb_arg);
|
|
nvmf_submit_request(req);
|
|
return (true);
|
|
}
|
|
|
|
bool
|
|
nvmf_cmd_get_log_page(struct nvmf_softc *sc, uint32_t nsid, uint8_t lid,
|
|
uint64_t offset, void *buf, size_t len, nvmf_request_complete_t *req_cb,
|
|
void *req_cb_arg, nvmf_io_complete_t *io_cb, void *io_cb_arg, int how)
|
|
{
|
|
struct nvme_command cmd;
|
|
struct memdesc mem;
|
|
struct nvmf_request *req;
|
|
size_t numd;
|
|
|
|
MPASS(len != 0 && len % 4 == 0);
|
|
MPASS(offset % 4 == 0);
|
|
|
|
numd = (len / 4) - 1;
|
|
memset(&cmd, 0, sizeof(cmd));
|
|
cmd.opc = NVME_OPC_GET_LOG_PAGE;
|
|
cmd.nsid = htole32(nsid);
|
|
cmd.cdw10 = htole32(numd << 16 | lid);
|
|
cmd.cdw11 = htole32(numd >> 16);
|
|
cmd.cdw12 = htole32(offset);
|
|
cmd.cdw13 = htole32(offset >> 32);
|
|
|
|
req = nvmf_allocate_request(sc->admin, &cmd, req_cb, req_cb_arg, how);
|
|
if (req == NULL)
|
|
return (false);
|
|
mem = memdesc_vaddr(buf, len);
|
|
nvmf_capsule_append_data(req->nc, &mem, len, false, io_cb, io_cb_arg);
|
|
nvmf_submit_request(req);
|
|
return (true);
|
|
}
|