1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * 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_ocssd.h" 35 #include "nvme_internal.h" 36 37 int 38 spdk_nvme_ocssd_ns_cmd_vector_reset(struct spdk_nvme_ns *ns, 39 struct spdk_nvme_qpair *qpair, 40 uint64_t *lba_list, uint32_t num_lbas, 41 struct spdk_ocssd_chunk_information_entry *chunk_info, 42 spdk_nvme_cmd_cb cb_fn, void *cb_arg) 43 { 44 struct nvme_request *req; 45 struct spdk_nvme_cmd *cmd; 46 47 if (!lba_list || (num_lbas == 0) || 48 (num_lbas > SPDK_NVME_OCSSD_MAX_LBAL_ENTRIES)) { 49 return -EINVAL; 50 } 51 52 req = nvme_allocate_request_null(qpair, cb_fn, cb_arg); 53 if (req == NULL) { 54 return -ENOMEM; 55 } 56 57 cmd = &req->cmd; 58 cmd->opc = SPDK_OCSSD_OPC_VECTOR_RESET; 59 cmd->nsid = ns->id; 60 61 if (chunk_info != NULL) { 62 cmd->mptr = spdk_vtophys(chunk_info, NULL); 63 } 64 65 /* 66 * Dword 10 and 11 store a pointer to the list of logical block addresses. 67 * If there is a single entry in the LBA list, the logical block 68 * address should be stored instead. 69 */ 70 if (num_lbas == 1) { 71 *(uint64_t *)&cmd->cdw10 = *lba_list; 72 } else { 73 *(uint64_t *)&cmd->cdw10 = spdk_vtophys(lba_list, NULL); 74 } 75 76 cmd->cdw12 = num_lbas - 1; 77 78 return nvme_qpair_submit_request(qpair, req); 79 } 80 81 static int 82 _nvme_ocssd_ns_cmd_vector_rw_with_md(struct spdk_nvme_ns *ns, 83 struct spdk_nvme_qpair *qpair, 84 void *buffer, void *metadata, 85 uint64_t *lba_list, uint32_t num_lbas, 86 spdk_nvme_cmd_cb cb_fn, void *cb_arg, 87 enum spdk_ocssd_io_opcode opc, 88 uint32_t io_flags) 89 { 90 struct nvme_request *req; 91 struct spdk_nvme_cmd *cmd; 92 struct nvme_payload payload; 93 uint32_t valid_flags = SPDK_OCSSD_IO_FLAGS_LIMITED_RETRY; 94 95 if (io_flags & ~valid_flags) { 96 return -EINVAL; 97 } 98 99 if (!buffer || !lba_list || (num_lbas == 0) || 100 (num_lbas > SPDK_NVME_OCSSD_MAX_LBAL_ENTRIES)) { 101 return -EINVAL; 102 } 103 104 payload = NVME_PAYLOAD_CONTIG(buffer, metadata); 105 106 req = nvme_allocate_request(qpair, &payload, num_lbas * ns->sector_size, num_lbas * ns->md_size, 107 cb_fn, cb_arg); 108 if (req == NULL) { 109 return -ENOMEM; 110 } 111 112 cmd = &req->cmd; 113 cmd->opc = opc; 114 cmd->nsid = ns->id; 115 116 /* 117 * Dword 10 and 11 store a pointer to the list of logical block addresses. 118 * If there is a single entry in the LBA list, the logical block 119 * address should be stored instead. 120 */ 121 if (num_lbas == 1) { 122 *(uint64_t *)&cmd->cdw10 = *lba_list; 123 } else { 124 *(uint64_t *)&cmd->cdw10 = spdk_vtophys(lba_list, NULL); 125 } 126 127 cmd->cdw12 = num_lbas - 1; 128 cmd->cdw12 |= io_flags; 129 130 return nvme_qpair_submit_request(qpair, req); 131 } 132 133 int 134 spdk_nvme_ocssd_ns_cmd_vector_write_with_md(struct spdk_nvme_ns *ns, 135 struct spdk_nvme_qpair *qpair, 136 void *buffer, void *metadata, 137 uint64_t *lba_list, uint32_t num_lbas, 138 spdk_nvme_cmd_cb cb_fn, void *cb_arg, 139 uint32_t io_flags) 140 { 141 return _nvme_ocssd_ns_cmd_vector_rw_with_md(ns, qpair, buffer, metadata, lba_list, 142 num_lbas, cb_fn, cb_arg, SPDK_OCSSD_OPC_VECTOR_WRITE, io_flags); 143 } 144 145 int 146 spdk_nvme_ocssd_ns_cmd_vector_write(struct spdk_nvme_ns *ns, 147 struct spdk_nvme_qpair *qpair, 148 void *buffer, 149 uint64_t *lba_list, uint32_t num_lbas, 150 spdk_nvme_cmd_cb cb_fn, void *cb_arg, 151 uint32_t io_flags) 152 { 153 return _nvme_ocssd_ns_cmd_vector_rw_with_md(ns, qpair, buffer, NULL, lba_list, 154 num_lbas, cb_fn, cb_arg, SPDK_OCSSD_OPC_VECTOR_WRITE, io_flags); 155 } 156 157 int 158 spdk_nvme_ocssd_ns_cmd_vector_read_with_md(struct spdk_nvme_ns *ns, 159 struct spdk_nvme_qpair *qpair, 160 void *buffer, void *metadata, 161 uint64_t *lba_list, uint32_t num_lbas, 162 spdk_nvme_cmd_cb cb_fn, void *cb_arg, 163 uint32_t io_flags) 164 { 165 return _nvme_ocssd_ns_cmd_vector_rw_with_md(ns, qpair, buffer, metadata, lba_list, 166 num_lbas, cb_fn, cb_arg, SPDK_OCSSD_OPC_VECTOR_READ, io_flags); 167 } 168 169 int 170 spdk_nvme_ocssd_ns_cmd_vector_read(struct spdk_nvme_ns *ns, 171 struct spdk_nvme_qpair *qpair, 172 void *buffer, 173 uint64_t *lba_list, uint32_t num_lbas, 174 spdk_nvme_cmd_cb cb_fn, void *cb_arg, 175 uint32_t io_flags) 176 { 177 return _nvme_ocssd_ns_cmd_vector_rw_with_md(ns, qpair, buffer, NULL, lba_list, 178 num_lbas, cb_fn, cb_arg, SPDK_OCSSD_OPC_VECTOR_READ, io_flags); 179 } 180 181 int 182 spdk_nvme_ocssd_ns_cmd_vector_copy(struct spdk_nvme_ns *ns, 183 struct spdk_nvme_qpair *qpair, 184 uint64_t *dst_lba_list, 185 uint64_t *src_lba_list, 186 uint32_t num_lbas, 187 spdk_nvme_cmd_cb cb_fn, void *cb_arg, 188 uint32_t io_flags) 189 { 190 struct nvme_request *req; 191 struct spdk_nvme_cmd *cmd; 192 193 uint32_t valid_flags = SPDK_OCSSD_IO_FLAGS_LIMITED_RETRY; 194 195 if (io_flags & ~valid_flags) { 196 return -EINVAL; 197 } 198 199 if (!dst_lba_list || !src_lba_list || (num_lbas == 0) || 200 (num_lbas > SPDK_NVME_OCSSD_MAX_LBAL_ENTRIES)) { 201 return -EINVAL; 202 } 203 204 req = nvme_allocate_request_null(qpair, cb_fn, cb_arg); 205 if (req == NULL) { 206 return -ENOMEM; 207 } 208 209 cmd = &req->cmd; 210 cmd->opc = SPDK_OCSSD_OPC_VECTOR_COPY; 211 cmd->nsid = ns->id; 212 213 /* 214 * Dword 10 and 11 store a pointer to the list of source logical 215 * block addresses. 216 * Dword 14 and 15 store a pointer to the list of destination logical 217 * block addresses. 218 * If there is a single entry in the LBA list, the logical block 219 * address should be stored instead. 220 */ 221 if (num_lbas == 1) { 222 *(uint64_t *)&cmd->cdw10 = *src_lba_list; 223 *(uint64_t *)&cmd->cdw14 = *dst_lba_list; 224 } else { 225 *(uint64_t *)&cmd->cdw10 = spdk_vtophys(src_lba_list, NULL); 226 *(uint64_t *)&cmd->cdw14 = spdk_vtophys(dst_lba_list, NULL); 227 } 228 229 cmd->cdw12 = num_lbas - 1; 230 cmd->cdw12 |= io_flags; 231 232 return nvme_qpair_submit_request(qpair, req); 233 } 234