xref: /spdk/lib/nvme/nvme_zns.c (revision cc6920a4763d4b9a43aa40583c8397d8f14fa100)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) 2020, Western Digital Corporation. All rights reserved.
5  *   Copyright (c) 2021 Mellanox Technologies LTD. All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/nvme_zns.h"
35 #include "nvme_internal.h"
36 
37 const struct spdk_nvme_zns_ns_data *
38 spdk_nvme_zns_ns_get_data(struct spdk_nvme_ns *ns)
39 {
40 	return ns->nsdata_zns;
41 }
42 
43 uint64_t
44 spdk_nvme_zns_ns_get_zone_size_sectors(struct spdk_nvme_ns *ns)
45 {
46 	const struct spdk_nvme_zns_ns_data *nsdata_zns = spdk_nvme_zns_ns_get_data(ns);
47 	const struct spdk_nvme_ns_data *nsdata = spdk_nvme_ns_get_data(ns);
48 
49 	return nsdata_zns->lbafe[nsdata->flbas.format].zsze;
50 }
51 
52 uint64_t
53 spdk_nvme_zns_ns_get_zone_size(struct spdk_nvme_ns *ns)
54 {
55 	return spdk_nvme_zns_ns_get_zone_size_sectors(ns) * spdk_nvme_ns_get_sector_size(ns);
56 }
57 
58 uint64_t
59 spdk_nvme_zns_ns_get_num_zones(struct spdk_nvme_ns *ns)
60 {
61 	return spdk_nvme_ns_get_num_sectors(ns) / spdk_nvme_zns_ns_get_zone_size_sectors(ns);
62 }
63 
64 uint32_t
65 spdk_nvme_zns_ns_get_max_open_zones(struct spdk_nvme_ns *ns)
66 {
67 	const struct spdk_nvme_zns_ns_data *nsdata_zns = spdk_nvme_zns_ns_get_data(ns);
68 
69 	return nsdata_zns->mor + 1;
70 }
71 
72 uint32_t
73 spdk_nvme_zns_ns_get_max_active_zones(struct spdk_nvme_ns *ns)
74 {
75 	const struct spdk_nvme_zns_ns_data *nsdata_zns = spdk_nvme_zns_ns_get_data(ns);
76 
77 	return nsdata_zns->mar + 1;
78 }
79 
80 const struct spdk_nvme_zns_ctrlr_data *
81 spdk_nvme_zns_ctrlr_get_data(struct spdk_nvme_ctrlr *ctrlr)
82 {
83 	return ctrlr->cdata_zns;
84 }
85 
86 uint32_t
87 spdk_nvme_zns_ctrlr_get_max_zone_append_size(const struct spdk_nvme_ctrlr *ctrlr)
88 {
89 	return ctrlr->max_zone_append_size;
90 }
91 
92 int
93 spdk_nvme_zns_zone_append(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
94 			  void *buffer, uint64_t zslba,
95 			  uint32_t lba_count, spdk_nvme_cmd_cb cb_fn, void *cb_arg,
96 			  uint32_t io_flags)
97 {
98 	return nvme_ns_cmd_zone_append_with_md(ns, qpair, buffer, NULL, zslba, lba_count,
99 					       cb_fn, cb_arg, io_flags, 0, 0);
100 }
101 
102 int
103 spdk_nvme_zns_zone_append_with_md(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
104 				  void *buffer, void *metadata, uint64_t zslba,
105 				  uint32_t lba_count, spdk_nvme_cmd_cb cb_fn, void *cb_arg,
106 				  uint32_t io_flags, uint16_t apptag_mask, uint16_t apptag)
107 {
108 	return nvme_ns_cmd_zone_append_with_md(ns, qpair, buffer, metadata, zslba, lba_count,
109 					       cb_fn, cb_arg, io_flags, apptag_mask, apptag);
110 }
111 
112 int
113 spdk_nvme_zns_zone_appendv(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
114 			   uint64_t zslba, uint32_t lba_count,
115 			   spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags,
116 			   spdk_nvme_req_reset_sgl_cb reset_sgl_fn,
117 			   spdk_nvme_req_next_sge_cb next_sge_fn)
118 {
119 	return nvme_ns_cmd_zone_appendv_with_md(ns, qpair, zslba, lba_count, cb_fn, cb_arg,
120 						io_flags, reset_sgl_fn, next_sge_fn,
121 						NULL, 0, 0);
122 }
123 
124 int
125 spdk_nvme_zns_zone_appendv_with_md(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
126 				   uint64_t zslba, uint32_t lba_count,
127 				   spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags,
128 				   spdk_nvme_req_reset_sgl_cb reset_sgl_fn,
129 				   spdk_nvme_req_next_sge_cb next_sge_fn, void *metadata,
130 				   uint16_t apptag_mask, uint16_t apptag)
131 {
132 	return nvme_ns_cmd_zone_appendv_with_md(ns, qpair, zslba, lba_count, cb_fn, cb_arg,
133 						io_flags, reset_sgl_fn, next_sge_fn,
134 						metadata, apptag_mask, apptag);
135 }
136 
137 static int
138 nvme_zns_zone_mgmt_recv(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
139 			void *payload, uint32_t payload_size, uint64_t slba,
140 			uint8_t zone_recv_action, uint8_t zra_spec_field, bool zra_spec_feats,
141 			spdk_nvme_cmd_cb cb_fn, void *cb_arg)
142 {
143 	struct nvme_request *req;
144 	struct spdk_nvme_cmd *cmd;
145 
146 	req = nvme_allocate_request_user_copy(qpair, payload, payload_size, cb_fn, cb_arg, false);
147 	if (req == NULL) {
148 		return -ENOMEM;
149 	}
150 
151 	cmd = &req->cmd;
152 	cmd->opc = SPDK_NVME_OPC_ZONE_MGMT_RECV;
153 	cmd->nsid = ns->id;
154 
155 	*(uint64_t *)&cmd->cdw10 = slba;
156 	cmd->cdw12 = spdk_nvme_bytes_to_numd(payload_size);
157 	cmd->cdw13 = zone_recv_action | zra_spec_field << 8 | zra_spec_feats << 16;
158 
159 	return nvme_qpair_submit_request(qpair, req);
160 }
161 
162 int
163 spdk_nvme_zns_report_zones(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
164 			   void *payload, uint32_t payload_size, uint64_t slba,
165 			   enum spdk_nvme_zns_zra_report_opts report_opts, bool partial_report,
166 			   spdk_nvme_cmd_cb cb_fn, void *cb_arg)
167 {
168 	return nvme_zns_zone_mgmt_recv(ns, qpair, payload, payload_size, slba,
169 				       SPDK_NVME_ZONE_REPORT, report_opts, partial_report,
170 				       cb_fn, cb_arg);
171 }
172 
173 int
174 spdk_nvme_zns_ext_report_zones(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
175 			       void *payload, uint32_t payload_size, uint64_t slba,
176 			       enum spdk_nvme_zns_zra_report_opts report_opts, bool partial_report,
177 			       spdk_nvme_cmd_cb cb_fn, void *cb_arg)
178 {
179 	return nvme_zns_zone_mgmt_recv(ns, qpair, payload, payload_size, slba,
180 				       SPDK_NVME_ZONE_EXTENDED_REPORT, report_opts, partial_report,
181 				       cb_fn, cb_arg);
182 }
183 
184 static int
185 nvme_zns_zone_mgmt_send(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
186 			uint64_t slba, bool select_all, uint8_t zone_send_action,
187 			spdk_nvme_cmd_cb cb_fn, void *cb_arg)
188 {
189 	struct nvme_request *req;
190 	struct spdk_nvme_cmd *cmd;
191 
192 	req = nvme_allocate_request_null(qpair, cb_fn, cb_arg);
193 	if (req == NULL) {
194 		return -ENOMEM;
195 	}
196 
197 	cmd = &req->cmd;
198 	cmd->opc = SPDK_NVME_OPC_ZONE_MGMT_SEND;
199 	cmd->nsid = ns->id;
200 
201 	if (!select_all) {
202 		*(uint64_t *)&cmd->cdw10 = slba;
203 	}
204 
205 	cmd->cdw13 = zone_send_action | select_all << 8;
206 
207 	return nvme_qpair_submit_request(qpair, req);
208 }
209 
210 int
211 spdk_nvme_zns_close_zone(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, uint64_t slba,
212 			 bool select_all, spdk_nvme_cmd_cb cb_fn, void *cb_arg)
213 {
214 	return nvme_zns_zone_mgmt_send(ns, qpair, slba, select_all, SPDK_NVME_ZONE_CLOSE,
215 				       cb_fn, cb_arg);
216 }
217 
218 int
219 spdk_nvme_zns_finish_zone(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, uint64_t slba,
220 			  bool select_all, spdk_nvme_cmd_cb cb_fn, void *cb_arg)
221 {
222 	return nvme_zns_zone_mgmt_send(ns, qpair, slba, select_all, SPDK_NVME_ZONE_FINISH,
223 				       cb_fn, cb_arg);
224 }
225 
226 int
227 spdk_nvme_zns_open_zone(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, uint64_t slba,
228 			bool select_all, spdk_nvme_cmd_cb cb_fn, void *cb_arg)
229 {
230 	return nvme_zns_zone_mgmt_send(ns, qpair, slba, select_all, SPDK_NVME_ZONE_OPEN,
231 				       cb_fn, cb_arg);
232 }
233 
234 int
235 spdk_nvme_zns_reset_zone(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, uint64_t slba,
236 			 bool select_all, spdk_nvme_cmd_cb cb_fn, void *cb_arg)
237 {
238 	return nvme_zns_zone_mgmt_send(ns, qpair, slba, select_all, SPDK_NVME_ZONE_RESET,
239 				       cb_fn, cb_arg);
240 }
241 
242 int
243 spdk_nvme_zns_offline_zone(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, uint64_t slba,
244 			   bool select_all, spdk_nvme_cmd_cb cb_fn, void *cb_arg)
245 {
246 	return nvme_zns_zone_mgmt_send(ns, qpair, slba, select_all, SPDK_NVME_ZONE_OFFLINE,
247 				       cb_fn, cb_arg);
248 }
249 
250 int
251 spdk_nvme_zns_set_zone_desc_ext(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
252 				uint64_t slba, void *buffer, uint32_t payload_size,
253 				spdk_nvme_cmd_cb cb_fn, void *cb_arg)
254 {
255 	struct nvme_request *req;
256 	struct spdk_nvme_cmd *cmd;
257 
258 	if (payload_size == 0) {
259 		return -EINVAL;
260 	}
261 
262 	if (buffer == NULL) {
263 		return -EINVAL;
264 	}
265 
266 	req = nvme_allocate_request_user_copy(qpair, buffer, payload_size, cb_fn, cb_arg, true);
267 	if (req == NULL) {
268 		return -ENOMEM;
269 	}
270 
271 	cmd = &req->cmd;
272 	cmd->opc = SPDK_NVME_OPC_ZONE_MGMT_SEND;
273 	cmd->nsid = ns->id;
274 
275 	*(uint64_t *)&cmd->cdw10 = slba;
276 
277 	cmd->cdw13 = SPDK_NVME_ZONE_SET_ZDE;
278 
279 	return nvme_qpair_submit_request(qpair, req);
280 }
281