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