1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2023-2024 Chelsio Communications, Inc.
5 * Written by: John Baldwin <jhb@FreeBSD.org>
6 */
7
8#include <sys/types.h>
9#include <sys/memdesc.h>
10#include <sys/systm.h>
11#include <dev/nvme/nvme.h>
12#include <dev/nvmf/nvmf.h>
13#include <dev/nvmf/nvmf_proto.h>
14#include <dev/nvmf/host/nvmf_var.h>
15
16bool
17nvmf_cmd_get_property(struct nvmf_softc *sc, uint32_t offset, uint8_t size,
18    nvmf_request_complete_t *cb, void *cb_arg, int how)
19{
20	struct nvmf_fabric_prop_get_cmd cmd;
21	struct nvmf_request *req;
22
23	memset(&cmd, 0, sizeof(cmd));
24	cmd.opcode = NVME_OPC_FABRICS_COMMANDS;
25	cmd.fctype = NVMF_FABRIC_COMMAND_PROPERTY_GET;
26	switch (size) {
27	case 4:
28		cmd.attrib.size = NVMF_PROP_SIZE_4;
29		break;
30	case 8:
31		cmd.attrib.size = NVMF_PROP_SIZE_8;
32		break;
33	default:
34		panic("Invalid property size");
35	}
36	cmd.ofst = htole32(offset);
37
38	req = nvmf_allocate_request(sc->admin, &cmd, cb, cb_arg, how);
39	if (req != NULL)
40		nvmf_submit_request(req);
41	return (req != NULL);
42}
43
44bool
45nvmf_cmd_set_property(struct nvmf_softc *sc, uint32_t offset, uint8_t size,
46    uint64_t value, nvmf_request_complete_t *cb, void *cb_arg, int how)
47{
48	struct nvmf_fabric_prop_set_cmd cmd;
49	struct nvmf_request *req;
50
51	memset(&cmd, 0, sizeof(cmd));
52	cmd.opcode = NVME_OPC_FABRICS_COMMANDS;
53	cmd.fctype = NVMF_FABRIC_COMMAND_PROPERTY_SET;
54	switch (size) {
55	case 4:
56		cmd.attrib.size = NVMF_PROP_SIZE_4;
57		cmd.value.u32.low = htole32(value);
58		break;
59	case 8:
60		cmd.attrib.size = NVMF_PROP_SIZE_8;
61		cmd.value.u64 = htole64(value);
62		break;
63	default:
64		panic("Invalid property size");
65	}
66	cmd.ofst = htole32(offset);
67
68	req = nvmf_allocate_request(sc->admin, &cmd, cb, cb_arg, how);
69	if (req != NULL)
70		nvmf_submit_request(req);
71	return (req != NULL);
72}
73
74bool
75nvmf_cmd_keep_alive(struct nvmf_softc *sc, nvmf_request_complete_t *cb,
76    void *cb_arg, int how)
77{
78	struct nvme_command cmd;
79	struct nvmf_request *req;
80
81	memset(&cmd, 0, sizeof(cmd));
82	cmd.opc = NVME_OPC_KEEP_ALIVE;
83
84	req = nvmf_allocate_request(sc->admin, &cmd, cb, cb_arg, how);
85	if (req != NULL)
86		nvmf_submit_request(req);
87	return (req != NULL);
88}
89
90bool
91nvmf_cmd_identify_active_namespaces(struct nvmf_softc *sc, uint32_t id,
92    struct nvme_ns_list *nslist, nvmf_request_complete_t *req_cb,
93    void *req_cb_arg, nvmf_io_complete_t *io_cb, void *io_cb_arg, int how)
94{
95	struct nvme_command cmd;
96	struct memdesc mem;
97	struct nvmf_request *req;
98
99	memset(&cmd, 0, sizeof(cmd));
100	cmd.opc = NVME_OPC_IDENTIFY;
101
102	/* 5.15.1 Use CNS of 0x02 for namespace data. */
103	cmd.cdw10 = htole32(2);
104	cmd.nsid = htole32(id);
105
106	req = nvmf_allocate_request(sc->admin, &cmd, req_cb, req_cb_arg, how);
107	if (req == NULL)
108		return (false);
109	mem = memdesc_vaddr(nslist, sizeof(*nslist));
110	nvmf_capsule_append_data(req->nc, &mem, sizeof(*nslist), false,
111	    io_cb, io_cb_arg);
112	nvmf_submit_request(req);
113	return (true);
114}
115
116bool
117nvmf_cmd_identify_namespace(struct nvmf_softc *sc, uint32_t id,
118    struct nvme_namespace_data *nsdata, nvmf_request_complete_t *req_cb,
119    void *req_cb_arg, nvmf_io_complete_t *io_cb, void *io_cb_arg, int how)
120{
121	struct nvme_command cmd;
122	struct memdesc mem;
123	struct nvmf_request *req;
124
125	memset(&cmd, 0, sizeof(cmd));
126	cmd.opc = NVME_OPC_IDENTIFY;
127
128	/* 5.15.1 Use CNS of 0x00 for namespace data. */
129	cmd.cdw10 = htole32(0);
130	cmd.nsid = htole32(id);
131
132	req = nvmf_allocate_request(sc->admin, &cmd, req_cb, req_cb_arg, how);
133	if (req == NULL)
134		return (false);
135	mem = memdesc_vaddr(nsdata, sizeof(*nsdata));
136	nvmf_capsule_append_data(req->nc, &mem, sizeof(*nsdata), false,
137	    io_cb, io_cb_arg);
138	nvmf_submit_request(req);
139	return (true);
140}
141
142bool
143nvmf_cmd_get_log_page(struct nvmf_softc *sc, uint32_t nsid, uint8_t lid,
144    uint64_t offset, void *buf, size_t len, nvmf_request_complete_t *req_cb,
145    void *req_cb_arg, nvmf_io_complete_t *io_cb, void *io_cb_arg, int how)
146{
147	struct nvme_command cmd;
148	struct memdesc mem;
149	struct nvmf_request *req;
150	size_t numd;
151
152	MPASS(len != 0 && len % 4 == 0);
153	MPASS(offset % 4 == 0);
154
155	numd = (len / 4) - 1;
156	memset(&cmd, 0, sizeof(cmd));
157	cmd.opc = NVME_OPC_GET_LOG_PAGE;
158	cmd.nsid = htole32(nsid);
159	cmd.cdw10 = htole32(numd << 16 | lid);
160	cmd.cdw11 = htole32(numd >> 16);
161	cmd.cdw12 = htole32(offset);
162	cmd.cdw13 = htole32(offset >> 32);
163
164	req = nvmf_allocate_request(sc->admin, &cmd, req_cb, req_cb_arg, how);
165	if (req == NULL)
166		return (false);
167	mem = memdesc_vaddr(buf, len);
168	nvmf_capsule_append_data(req->nc, &mem, len, false, io_cb, io_cb_arg);
169	nvmf_submit_request(req);
170	return (true);
171}
172