xref: /freebsd/sys/dev/nvmf/host/nvmf_cmd.c (revision 8aac90f18aef7c9eea906c3ff9a001ca7b94f375)
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 
16 bool
17 nvmf_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 
44 bool
45 nvmf_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 
74 bool
75 nvmf_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 
90 bool
91 nvmf_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 
116 bool
117 nvmf_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 
142 bool
143 nvmf_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