1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (c) 2020, Western Digital Corporation. All rights reserved.
3 * Copyright (c) 2021 Mellanox Technologies LTD. All rights reserved.
4 */
5
6 #include "spdk/nvme_zns.h"
7 #include "nvme_internal.h"
8
9 const struct spdk_nvme_zns_ns_data *
spdk_nvme_zns_ns_get_data(struct spdk_nvme_ns * ns)10 spdk_nvme_zns_ns_get_data(struct spdk_nvme_ns *ns)
11 {
12 return ns->nsdata_zns;
13 }
14
15 uint64_t
spdk_nvme_zns_ns_get_zone_size_sectors(struct spdk_nvme_ns * ns)16 spdk_nvme_zns_ns_get_zone_size_sectors(struct spdk_nvme_ns *ns)
17 {
18 const struct spdk_nvme_zns_ns_data *nsdata_zns = spdk_nvme_zns_ns_get_data(ns);
19 const struct spdk_nvme_ns_data *nsdata = spdk_nvme_ns_get_data(ns);
20 uint32_t format_index;
21
22 format_index = spdk_nvme_ns_get_format_index(nsdata);
23
24 return nsdata_zns->lbafe[format_index].zsze;
25 }
26
27 uint64_t
spdk_nvme_zns_ns_get_zone_size(struct spdk_nvme_ns * ns)28 spdk_nvme_zns_ns_get_zone_size(struct spdk_nvme_ns *ns)
29 {
30 return spdk_nvme_zns_ns_get_zone_size_sectors(ns) * spdk_nvme_ns_get_sector_size(ns);
31 }
32
33 uint64_t
spdk_nvme_zns_ns_get_num_zones(struct spdk_nvme_ns * ns)34 spdk_nvme_zns_ns_get_num_zones(struct spdk_nvme_ns *ns)
35 {
36 return spdk_nvme_ns_get_num_sectors(ns) / spdk_nvme_zns_ns_get_zone_size_sectors(ns);
37 }
38
39 uint32_t
spdk_nvme_zns_ns_get_max_open_zones(struct spdk_nvme_ns * ns)40 spdk_nvme_zns_ns_get_max_open_zones(struct spdk_nvme_ns *ns)
41 {
42 const struct spdk_nvme_zns_ns_data *nsdata_zns = spdk_nvme_zns_ns_get_data(ns);
43
44 return nsdata_zns->mor + 1;
45 }
46
47 uint32_t
spdk_nvme_zns_ns_get_max_active_zones(struct spdk_nvme_ns * ns)48 spdk_nvme_zns_ns_get_max_active_zones(struct spdk_nvme_ns *ns)
49 {
50 const struct spdk_nvme_zns_ns_data *nsdata_zns = spdk_nvme_zns_ns_get_data(ns);
51
52 return nsdata_zns->mar + 1;
53 }
54
55 const struct spdk_nvme_zns_ctrlr_data *
spdk_nvme_zns_ctrlr_get_data(struct spdk_nvme_ctrlr * ctrlr)56 spdk_nvme_zns_ctrlr_get_data(struct spdk_nvme_ctrlr *ctrlr)
57 {
58 return ctrlr->cdata_zns;
59 }
60
61 uint32_t
spdk_nvme_zns_ctrlr_get_max_zone_append_size(const struct spdk_nvme_ctrlr * ctrlr)62 spdk_nvme_zns_ctrlr_get_max_zone_append_size(const struct spdk_nvme_ctrlr *ctrlr)
63 {
64 return ctrlr->max_zone_append_size;
65 }
66
67 int
spdk_nvme_zns_zone_append(struct spdk_nvme_ns * ns,struct spdk_nvme_qpair * qpair,void * buffer,uint64_t zslba,uint32_t lba_count,spdk_nvme_cmd_cb cb_fn,void * cb_arg,uint32_t io_flags)68 spdk_nvme_zns_zone_append(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
69 void *buffer, uint64_t zslba,
70 uint32_t lba_count, spdk_nvme_cmd_cb cb_fn, void *cb_arg,
71 uint32_t io_flags)
72 {
73 return nvme_ns_cmd_zone_append_with_md(ns, qpair, buffer, NULL, zslba, lba_count,
74 cb_fn, cb_arg, io_flags, 0, 0);
75 }
76
77 int
spdk_nvme_zns_zone_append_with_md(struct spdk_nvme_ns * ns,struct spdk_nvme_qpair * qpair,void * buffer,void * metadata,uint64_t zslba,uint32_t lba_count,spdk_nvme_cmd_cb cb_fn,void * cb_arg,uint32_t io_flags,uint16_t apptag_mask,uint16_t apptag)78 spdk_nvme_zns_zone_append_with_md(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
79 void *buffer, void *metadata, uint64_t zslba,
80 uint32_t lba_count, spdk_nvme_cmd_cb cb_fn, void *cb_arg,
81 uint32_t io_flags, uint16_t apptag_mask, uint16_t apptag)
82 {
83 return nvme_ns_cmd_zone_append_with_md(ns, qpair, buffer, metadata, zslba, lba_count,
84 cb_fn, cb_arg, io_flags, apptag_mask, apptag);
85 }
86
87 int
spdk_nvme_zns_zone_appendv(struct spdk_nvme_ns * ns,struct spdk_nvme_qpair * qpair,uint64_t zslba,uint32_t lba_count,spdk_nvme_cmd_cb cb_fn,void * cb_arg,uint32_t io_flags,spdk_nvme_req_reset_sgl_cb reset_sgl_fn,spdk_nvme_req_next_sge_cb next_sge_fn)88 spdk_nvme_zns_zone_appendv(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
89 uint64_t zslba, uint32_t lba_count,
90 spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags,
91 spdk_nvme_req_reset_sgl_cb reset_sgl_fn,
92 spdk_nvme_req_next_sge_cb next_sge_fn)
93 {
94 return nvme_ns_cmd_zone_appendv_with_md(ns, qpair, zslba, lba_count, cb_fn, cb_arg,
95 io_flags, reset_sgl_fn, next_sge_fn,
96 NULL, 0, 0);
97 }
98
99 int
spdk_nvme_zns_zone_appendv_with_md(struct spdk_nvme_ns * ns,struct spdk_nvme_qpair * qpair,uint64_t zslba,uint32_t lba_count,spdk_nvme_cmd_cb cb_fn,void * cb_arg,uint32_t io_flags,spdk_nvme_req_reset_sgl_cb reset_sgl_fn,spdk_nvme_req_next_sge_cb next_sge_fn,void * metadata,uint16_t apptag_mask,uint16_t apptag)100 spdk_nvme_zns_zone_appendv_with_md(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
101 uint64_t zslba, uint32_t lba_count,
102 spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags,
103 spdk_nvme_req_reset_sgl_cb reset_sgl_fn,
104 spdk_nvme_req_next_sge_cb next_sge_fn, void *metadata,
105 uint16_t apptag_mask, uint16_t apptag)
106 {
107 return nvme_ns_cmd_zone_appendv_with_md(ns, qpair, zslba, lba_count, cb_fn, cb_arg,
108 io_flags, reset_sgl_fn, next_sge_fn,
109 metadata, apptag_mask, apptag);
110 }
111
112 static int
nvme_zns_zone_mgmt_recv(struct spdk_nvme_ns * ns,struct spdk_nvme_qpair * qpair,void * payload,uint32_t payload_size,uint64_t slba,uint8_t zone_recv_action,uint8_t zra_spec_field,bool zra_spec_feats,spdk_nvme_cmd_cb cb_fn,void * cb_arg)113 nvme_zns_zone_mgmt_recv(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
114 void *payload, uint32_t payload_size, uint64_t slba,
115 uint8_t zone_recv_action, uint8_t zra_spec_field, bool zra_spec_feats,
116 spdk_nvme_cmd_cb cb_fn, void *cb_arg)
117 {
118 struct nvme_request *req;
119 struct spdk_nvme_cmd *cmd;
120
121 req = nvme_allocate_request_user_copy(qpair, payload, payload_size, cb_fn, cb_arg, false);
122 if (req == NULL) {
123 return -ENOMEM;
124 }
125
126 cmd = &req->cmd;
127 cmd->opc = SPDK_NVME_OPC_ZONE_MGMT_RECV;
128 cmd->nsid = ns->id;
129
130 *(uint64_t *)&cmd->cdw10 = slba;
131 cmd->cdw12 = spdk_nvme_bytes_to_numd(payload_size);
132 cmd->cdw13 = zone_recv_action | zra_spec_field << 8 | zra_spec_feats << 16;
133
134 return nvme_qpair_submit_request(qpair, req);
135 }
136
137 int
spdk_nvme_zns_report_zones(struct spdk_nvme_ns * ns,struct spdk_nvme_qpair * qpair,void * payload,uint32_t payload_size,uint64_t slba,enum spdk_nvme_zns_zra_report_opts report_opts,bool partial_report,spdk_nvme_cmd_cb cb_fn,void * cb_arg)138 spdk_nvme_zns_report_zones(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
139 void *payload, uint32_t payload_size, uint64_t slba,
140 enum spdk_nvme_zns_zra_report_opts report_opts, bool partial_report,
141 spdk_nvme_cmd_cb cb_fn, void *cb_arg)
142 {
143 return nvme_zns_zone_mgmt_recv(ns, qpair, payload, payload_size, slba,
144 SPDK_NVME_ZONE_REPORT, report_opts, partial_report,
145 cb_fn, cb_arg);
146 }
147
148 int
spdk_nvme_zns_ext_report_zones(struct spdk_nvme_ns * ns,struct spdk_nvme_qpair * qpair,void * payload,uint32_t payload_size,uint64_t slba,enum spdk_nvme_zns_zra_report_opts report_opts,bool partial_report,spdk_nvme_cmd_cb cb_fn,void * cb_arg)149 spdk_nvme_zns_ext_report_zones(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
150 void *payload, uint32_t payload_size, uint64_t slba,
151 enum spdk_nvme_zns_zra_report_opts report_opts, bool partial_report,
152 spdk_nvme_cmd_cb cb_fn, void *cb_arg)
153 {
154 return nvme_zns_zone_mgmt_recv(ns, qpair, payload, payload_size, slba,
155 SPDK_NVME_ZONE_EXTENDED_REPORT, report_opts, partial_report,
156 cb_fn, cb_arg);
157 }
158
159 static int
nvme_zns_zone_mgmt_send(struct spdk_nvme_ns * ns,struct spdk_nvme_qpair * qpair,uint64_t slba,bool select_all,uint8_t zone_send_action,spdk_nvme_cmd_cb cb_fn,void * cb_arg)160 nvme_zns_zone_mgmt_send(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
161 uint64_t slba, bool select_all, uint8_t zone_send_action,
162 spdk_nvme_cmd_cb cb_fn, void *cb_arg)
163 {
164 struct nvme_request *req;
165 struct spdk_nvme_cmd *cmd;
166
167 req = nvme_allocate_request_null(qpair, cb_fn, cb_arg);
168 if (req == NULL) {
169 return -ENOMEM;
170 }
171
172 cmd = &req->cmd;
173 cmd->opc = SPDK_NVME_OPC_ZONE_MGMT_SEND;
174 cmd->nsid = ns->id;
175
176 if (!select_all) {
177 *(uint64_t *)&cmd->cdw10 = slba;
178 }
179
180 cmd->cdw13 = zone_send_action | select_all << 8;
181
182 return nvme_qpair_submit_request(qpair, req);
183 }
184
185 int
spdk_nvme_zns_close_zone(struct spdk_nvme_ns * ns,struct spdk_nvme_qpair * qpair,uint64_t slba,bool select_all,spdk_nvme_cmd_cb cb_fn,void * cb_arg)186 spdk_nvme_zns_close_zone(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, uint64_t slba,
187 bool select_all, spdk_nvme_cmd_cb cb_fn, void *cb_arg)
188 {
189 return nvme_zns_zone_mgmt_send(ns, qpair, slba, select_all, SPDK_NVME_ZONE_CLOSE,
190 cb_fn, cb_arg);
191 }
192
193 int
spdk_nvme_zns_finish_zone(struct spdk_nvme_ns * ns,struct spdk_nvme_qpair * qpair,uint64_t slba,bool select_all,spdk_nvme_cmd_cb cb_fn,void * cb_arg)194 spdk_nvme_zns_finish_zone(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, uint64_t slba,
195 bool select_all, spdk_nvme_cmd_cb cb_fn, void *cb_arg)
196 {
197 return nvme_zns_zone_mgmt_send(ns, qpair, slba, select_all, SPDK_NVME_ZONE_FINISH,
198 cb_fn, cb_arg);
199 }
200
201 int
spdk_nvme_zns_open_zone(struct spdk_nvme_ns * ns,struct spdk_nvme_qpair * qpair,uint64_t slba,bool select_all,spdk_nvme_cmd_cb cb_fn,void * cb_arg)202 spdk_nvme_zns_open_zone(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, uint64_t slba,
203 bool select_all, spdk_nvme_cmd_cb cb_fn, void *cb_arg)
204 {
205 return nvme_zns_zone_mgmt_send(ns, qpair, slba, select_all, SPDK_NVME_ZONE_OPEN,
206 cb_fn, cb_arg);
207 }
208
209 int
spdk_nvme_zns_reset_zone(struct spdk_nvme_ns * ns,struct spdk_nvme_qpair * qpair,uint64_t slba,bool select_all,spdk_nvme_cmd_cb cb_fn,void * cb_arg)210 spdk_nvme_zns_reset_zone(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, uint64_t slba,
211 bool select_all, spdk_nvme_cmd_cb cb_fn, void *cb_arg)
212 {
213 return nvme_zns_zone_mgmt_send(ns, qpair, slba, select_all, SPDK_NVME_ZONE_RESET,
214 cb_fn, cb_arg);
215 }
216
217 int
spdk_nvme_zns_offline_zone(struct spdk_nvme_ns * ns,struct spdk_nvme_qpair * qpair,uint64_t slba,bool select_all,spdk_nvme_cmd_cb cb_fn,void * cb_arg)218 spdk_nvme_zns_offline_zone(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, uint64_t slba,
219 bool select_all, spdk_nvme_cmd_cb cb_fn, void *cb_arg)
220 {
221 return nvme_zns_zone_mgmt_send(ns, qpair, slba, select_all, SPDK_NVME_ZONE_OFFLINE,
222 cb_fn, cb_arg);
223 }
224
225 int
spdk_nvme_zns_set_zone_desc_ext(struct spdk_nvme_ns * ns,struct spdk_nvme_qpair * qpair,uint64_t slba,void * buffer,uint32_t payload_size,spdk_nvme_cmd_cb cb_fn,void * cb_arg)226 spdk_nvme_zns_set_zone_desc_ext(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
227 uint64_t slba, void *buffer, uint32_t payload_size,
228 spdk_nvme_cmd_cb cb_fn, void *cb_arg)
229 {
230 struct nvme_request *req;
231 struct spdk_nvme_cmd *cmd;
232
233 if (payload_size == 0) {
234 return -EINVAL;
235 }
236
237 if (buffer == NULL) {
238 return -EINVAL;
239 }
240
241 req = nvme_allocate_request_user_copy(qpair, buffer, payload_size, cb_fn, cb_arg, true);
242 if (req == NULL) {
243 return -ENOMEM;
244 }
245
246 cmd = &req->cmd;
247 cmd->opc = SPDK_NVME_OPC_ZONE_MGMT_SEND;
248 cmd->nsid = ns->id;
249
250 *(uint64_t *)&cmd->cdw10 = slba;
251
252 cmd->cdw13 = SPDK_NVME_ZONE_SET_ZDE;
253
254 return nvme_qpair_submit_request(qpair, req);
255 }
256