xref: /spdk/lib/nvme/nvme_ns_cmd.c (revision f93b6fb0a4ebcee203e7c44c9e170c20bbce96cc)
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 "nvme_internal.h"
35 
36 static struct nvme_request *_nvme_ns_cmd_rw(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
37 		const struct nvme_payload *payload, uint32_t payload_offset, uint32_t md_offset,
38 		uint64_t lba, uint32_t lba_count, spdk_nvme_cmd_cb cb_fn,
39 		void *cb_arg, uint32_t opc, uint32_t io_flags,
40 		uint16_t apptag_mask, uint16_t apptag, bool check_sgl);
41 
42 
43 static bool
44 spdk_nvme_ns_check_request_length(uint32_t lba_count, uint32_t sectors_per_max_io,
45 				  uint32_t sectors_per_stripe, uint32_t qdepth)
46 {
47 	uint32_t child_per_io;
48 
49 	if (sectors_per_stripe > 0) {
50 		child_per_io = (lba_count + sectors_per_stripe - 1) / sectors_per_stripe;
51 	} else {
52 		child_per_io = (lba_count + sectors_per_max_io - 1) / sectors_per_max_io;
53 	}
54 
55 	SPDK_DEBUGLOG(SPDK_LOG_NVME, "checking maximum i/o length %d\n", child_per_io);
56 
57 	return child_per_io >= qdepth;
58 }
59 
60 static void
61 nvme_cb_complete_child(void *child_arg, const struct spdk_nvme_cpl *cpl)
62 {
63 	struct nvme_request *child = child_arg;
64 	struct nvme_request *parent = child->parent;
65 
66 	nvme_request_remove_child(parent, child);
67 
68 	if (spdk_nvme_cpl_is_error(cpl)) {
69 		memcpy(&parent->parent_status, cpl, sizeof(*cpl));
70 	}
71 
72 	if (parent->num_children == 0) {
73 		nvme_complete_request(parent->cb_fn, parent->cb_arg, parent, &parent->parent_status);
74 		nvme_free_request(parent);
75 	}
76 }
77 
78 static void
79 nvme_request_add_child(struct nvme_request *parent, struct nvme_request *child)
80 {
81 	assert(parent->num_children != UINT16_MAX);
82 
83 	if (parent->num_children == 0) {
84 		/*
85 		 * Defer initialization of the children TAILQ since it falls
86 		 *  on a separate cacheline.  This ensures we do not touch this
87 		 *  cacheline except on request splitting cases, which are
88 		 *  relatively rare.
89 		 */
90 		TAILQ_INIT(&parent->children);
91 		parent->parent = NULL;
92 		memset(&parent->parent_status, 0, sizeof(struct spdk_nvme_cpl));
93 	}
94 
95 	parent->num_children++;
96 	TAILQ_INSERT_TAIL(&parent->children, child, child_tailq);
97 	child->parent = parent;
98 	child->cb_fn = nvme_cb_complete_child;
99 	child->cb_arg = child;
100 }
101 
102 void
103 nvme_request_remove_child(struct nvme_request *parent, struct nvme_request *child)
104 {
105 	assert(parent != NULL);
106 	assert(child != NULL);
107 	assert(child->parent == parent);
108 	assert(parent->num_children != 0);
109 
110 	parent->num_children--;
111 	TAILQ_REMOVE(&parent->children, child, child_tailq);
112 }
113 
114 static void
115 nvme_request_free_children(struct nvme_request *req)
116 {
117 	struct nvme_request *child, *tmp;
118 
119 	if (req->num_children == 0) {
120 		return;
121 	}
122 
123 	/* free all child nvme_request */
124 	TAILQ_FOREACH_SAFE(child, &req->children, child_tailq, tmp) {
125 		nvme_request_remove_child(req, child);
126 		nvme_request_free_children(child);
127 		nvme_free_request(child);
128 	}
129 }
130 
131 static struct nvme_request *
132 _nvme_add_child_request(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
133 			const struct nvme_payload *payload,
134 			uint32_t payload_offset, uint32_t md_offset,
135 			uint64_t lba, uint32_t lba_count, spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t opc,
136 			uint32_t io_flags, uint16_t apptag_mask, uint16_t apptag,
137 			struct nvme_request *parent, bool check_sgl)
138 {
139 	struct nvme_request	*child;
140 
141 	child = _nvme_ns_cmd_rw(ns, qpair, payload, payload_offset, md_offset, lba, lba_count, cb_fn,
142 				cb_arg, opc, io_flags, apptag_mask, apptag, check_sgl);
143 	if (child == NULL) {
144 		nvme_request_free_children(parent);
145 		nvme_free_request(parent);
146 		return NULL;
147 	}
148 
149 	nvme_request_add_child(parent, child);
150 	return child;
151 }
152 
153 static struct nvme_request *
154 _nvme_ns_cmd_split_request(struct spdk_nvme_ns *ns,
155 			   struct spdk_nvme_qpair *qpair,
156 			   const struct nvme_payload *payload,
157 			   uint32_t payload_offset, uint32_t md_offset,
158 			   uint64_t lba, uint32_t lba_count,
159 			   spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t opc,
160 			   uint32_t io_flags, struct nvme_request *req,
161 			   uint32_t sectors_per_max_io, uint32_t sector_mask,
162 			   uint16_t apptag_mask, uint16_t apptag)
163 {
164 	uint32_t		sector_size;
165 	uint32_t		md_size = ns->md_size;
166 	uint32_t		remaining_lba_count = lba_count;
167 	struct nvme_request	*child;
168 
169 	sector_size = ns->extended_lba_size;
170 
171 	if ((io_flags & SPDK_NVME_IO_FLAGS_PRACT) &&
172 	    (ns->flags & SPDK_NVME_NS_EXTENDED_LBA_SUPPORTED) &&
173 	    (ns->flags & SPDK_NVME_NS_DPS_PI_SUPPORTED) &&
174 	    (md_size == 8)) {
175 		sector_size -= 8;
176 	}
177 
178 	while (remaining_lba_count > 0) {
179 		lba_count = sectors_per_max_io - (lba & sector_mask);
180 		lba_count = spdk_min(remaining_lba_count, lba_count);
181 
182 		child = _nvme_add_child_request(ns, qpair, payload, payload_offset, md_offset,
183 						lba, lba_count, cb_fn, cb_arg, opc,
184 						io_flags, apptag_mask, apptag, req, true);
185 		if (child == NULL) {
186 			return NULL;
187 		}
188 
189 		remaining_lba_count -= lba_count;
190 		lba += lba_count;
191 		payload_offset += lba_count * sector_size;
192 		md_offset += lba_count * md_size;
193 	}
194 
195 	return req;
196 }
197 
198 static void
199 _nvme_ns_cmd_setup_request(struct spdk_nvme_ns *ns, struct nvme_request *req,
200 			   uint32_t opc, uint64_t lba, uint32_t lba_count,
201 			   uint32_t io_flags, uint16_t apptag_mask, uint16_t apptag)
202 {
203 	struct spdk_nvme_cmd	*cmd;
204 
205 	cmd = &req->cmd;
206 	cmd->opc = opc;
207 	cmd->nsid = ns->id;
208 
209 	*(uint64_t *)&cmd->cdw10 = lba;
210 
211 	if (ns->flags & SPDK_NVME_NS_DPS_PI_SUPPORTED) {
212 		switch (ns->pi_type) {
213 		case SPDK_NVME_FMT_NVM_PROTECTION_TYPE1:
214 		case SPDK_NVME_FMT_NVM_PROTECTION_TYPE2:
215 			cmd->cdw14 = (uint32_t)lba;
216 			break;
217 		}
218 	}
219 
220 	cmd->cdw12 = lba_count - 1;
221 	cmd->cdw12 |= io_flags;
222 
223 	cmd->cdw15 = apptag_mask;
224 	cmd->cdw15 = (cmd->cdw15 << 16 | apptag);
225 }
226 
227 static struct nvme_request *
228 _nvme_ns_cmd_split_request_prp(struct spdk_nvme_ns *ns,
229 			       struct spdk_nvme_qpair *qpair,
230 			       const struct nvme_payload *payload,
231 			       uint32_t payload_offset, uint32_t md_offset,
232 			       uint64_t lba, uint32_t lba_count,
233 			       spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t opc,
234 			       uint32_t io_flags, struct nvme_request *req,
235 			       uint16_t apptag_mask, uint16_t apptag)
236 {
237 	spdk_nvme_req_reset_sgl_cb reset_sgl_fn = req->payload.reset_sgl_fn;
238 	spdk_nvme_req_next_sge_cb next_sge_fn = req->payload.next_sge_fn;
239 	void *sgl_cb_arg = req->payload.contig_or_cb_arg;
240 	bool start_valid, end_valid, last_sge, child_equals_parent;
241 	uint64_t child_lba = lba;
242 	uint32_t req_current_length = 0;
243 	uint32_t child_length = 0;
244 	uint32_t sge_length;
245 	uint32_t page_size = qpair->ctrlr->page_size;
246 	uintptr_t address;
247 
248 	reset_sgl_fn(sgl_cb_arg, payload_offset);
249 	next_sge_fn(sgl_cb_arg, (void **)&address, &sge_length);
250 	while (req_current_length < req->payload_size) {
251 
252 		if (sge_length == 0) {
253 			continue;
254 		} else if (req_current_length + sge_length > req->payload_size) {
255 			sge_length = req->payload_size - req_current_length;
256 		}
257 
258 		/*
259 		 * The start of the SGE is invalid if the start address is not page aligned,
260 		 *  unless it is the first SGE in the child request.
261 		 */
262 		start_valid = child_length == 0 || _is_page_aligned(address, page_size);
263 
264 		/* Boolean for whether this is the last SGE in the parent request. */
265 		last_sge = (req_current_length + sge_length == req->payload_size);
266 
267 		/*
268 		 * The end of the SGE is invalid if the end address is not page aligned,
269 		 *  unless it is the last SGE in the parent request.
270 		 */
271 		end_valid = last_sge || _is_page_aligned(address + sge_length, page_size);
272 
273 		/*
274 		 * This child request equals the parent request, meaning that no splitting
275 		 *  was required for the parent request (the one passed into this function).
276 		 *  In this case, we do not create a child request at all - we just send
277 		 *  the original request as a single request at the end of this function.
278 		 */
279 		child_equals_parent = (child_length + sge_length == req->payload_size);
280 
281 		if (start_valid) {
282 			/*
283 			 * The start of the SGE is valid, so advance the length parameters,
284 			 *  to include this SGE with previous SGEs for this child request
285 			 *  (if any).  If it is not valid, we do not advance the length
286 			 *  parameters nor get the next SGE, because we must send what has
287 			 *  been collected before this SGE as a child request.
288 			 */
289 			child_length += sge_length;
290 			req_current_length += sge_length;
291 			if (req_current_length < req->payload_size) {
292 				next_sge_fn(sgl_cb_arg, (void **)&address, &sge_length);
293 			}
294 			/*
295 			 * If the next SGE is not page aligned, we will need to create a child
296 			 *  request for what we have so far, and then start a new child request for
297 			 *  the next SGE.
298 			 */
299 			start_valid = _is_page_aligned(address, page_size);
300 		}
301 
302 		if (start_valid && end_valid && !last_sge) {
303 			continue;
304 		}
305 
306 		/*
307 		 * We need to create a split here.  Send what we have accumulated so far as a child
308 		 *  request.  Checking if child_equals_parent allows us to *not* create a child request
309 		 *  when no splitting is required - in that case we will fall-through and just create
310 		 *  a single request with no children for the entire I/O.
311 		 */
312 		if (!child_equals_parent) {
313 			struct nvme_request *child;
314 			uint32_t child_lba_count;
315 
316 			if ((child_length % ns->extended_lba_size) != 0) {
317 				SPDK_ERRLOG("child_length %u not even multiple of lba_size %u\n",
318 					    child_length, ns->extended_lba_size);
319 				return NULL;
320 			}
321 			child_lba_count = child_length / ns->extended_lba_size;
322 			/*
323 			 * Note the last parameter is set to "false" - this tells the recursive
324 			 *  call to _nvme_ns_cmd_rw() to not bother with checking for SGL splitting
325 			 *  since we have already verified it here.
326 			 */
327 			child = _nvme_add_child_request(ns, qpair, payload, payload_offset, md_offset,
328 							child_lba, child_lba_count,
329 							cb_fn, cb_arg, opc, io_flags,
330 							apptag_mask, apptag, req, false);
331 			if (child == NULL) {
332 				return NULL;
333 			}
334 			payload_offset += child_length;
335 			md_offset += child_lba_count * ns->md_size;
336 			child_lba += child_lba_count;
337 			child_length = 0;
338 		}
339 	}
340 
341 	if (child_length == req->payload_size) {
342 		/* No splitting was required, so setup the whole payload as one request. */
343 		_nvme_ns_cmd_setup_request(ns, req, opc, lba, lba_count, io_flags, apptag_mask, apptag);
344 	}
345 
346 	return req;
347 }
348 
349 static struct nvme_request *
350 _nvme_ns_cmd_split_request_sgl(struct spdk_nvme_ns *ns,
351 			       struct spdk_nvme_qpair *qpair,
352 			       const struct nvme_payload *payload,
353 			       uint32_t payload_offset, uint32_t md_offset,
354 			       uint64_t lba, uint32_t lba_count,
355 			       spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t opc,
356 			       uint32_t io_flags, struct nvme_request *req,
357 			       uint16_t apptag_mask, uint16_t apptag)
358 {
359 	spdk_nvme_req_reset_sgl_cb reset_sgl_fn = req->payload.reset_sgl_fn;
360 	spdk_nvme_req_next_sge_cb next_sge_fn = req->payload.next_sge_fn;
361 	void *sgl_cb_arg = req->payload.contig_or_cb_arg;
362 	uint64_t child_lba = lba;
363 	uint32_t req_current_length = 0;
364 	uint32_t child_length = 0;
365 	uint32_t sge_length;
366 	uint16_t max_sges, num_sges;
367 	uintptr_t address;
368 
369 	max_sges = ns->ctrlr->max_sges;
370 
371 	reset_sgl_fn(sgl_cb_arg, payload_offset);
372 	num_sges = 0;
373 
374 	while (req_current_length < req->payload_size) {
375 		next_sge_fn(sgl_cb_arg, (void **)&address, &sge_length);
376 
377 		if (req_current_length + sge_length > req->payload_size) {
378 			sge_length = req->payload_size - req_current_length;
379 		}
380 
381 		child_length += sge_length;
382 		req_current_length += sge_length;
383 		num_sges++;
384 
385 		if (num_sges < max_sges && req_current_length < req->payload_size) {
386 			continue;
387 		}
388 
389 		/*
390 		 * We need to create a split here.  Send what we have accumulated so far as a child
391 		 *  request.  Checking if the child equals the full payload allows us to *not*
392 		 *  create a child request when no splitting is required - in that case we will
393 		 *  fall-through and just create a single request with no children for the entire I/O.
394 		 */
395 		if (child_length != req->payload_size) {
396 			struct nvme_request *child;
397 			uint32_t child_lba_count;
398 
399 			if ((child_length % ns->extended_lba_size) != 0) {
400 				SPDK_ERRLOG("child_length %u not even multiple of lba_size %u\n",
401 					    child_length, ns->extended_lba_size);
402 				return NULL;
403 			}
404 			child_lba_count = child_length / ns->extended_lba_size;
405 			/*
406 			 * Note the last parameter is set to "false" - this tells the recursive
407 			 *  call to _nvme_ns_cmd_rw() to not bother with checking for SGL splitting
408 			 *  since we have already verified it here.
409 			 */
410 			child = _nvme_add_child_request(ns, qpair, payload, payload_offset, md_offset,
411 							child_lba, child_lba_count,
412 							cb_fn, cb_arg, opc, io_flags,
413 							apptag_mask, apptag, req, false);
414 			if (child == NULL) {
415 				return NULL;
416 			}
417 			payload_offset += child_length;
418 			md_offset += child_lba_count * ns->md_size;
419 			child_lba += child_lba_count;
420 			child_length = 0;
421 			num_sges = 0;
422 		}
423 	}
424 
425 	if (child_length == req->payload_size) {
426 		/* No splitting was required, so setup the whole payload as one request. */
427 		_nvme_ns_cmd_setup_request(ns, req, opc, lba, lba_count, io_flags, apptag_mask, apptag);
428 	}
429 
430 	return req;
431 }
432 
433 static struct nvme_request *
434 _nvme_ns_cmd_rw(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
435 		const struct nvme_payload *payload, uint32_t payload_offset, uint32_t md_offset,
436 		uint64_t lba, uint32_t lba_count, spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t opc,
437 		uint32_t io_flags, uint16_t apptag_mask, uint16_t apptag, bool check_sgl)
438 {
439 	struct nvme_request	*req;
440 	uint32_t		sector_size;
441 	uint32_t		sectors_per_max_io;
442 	uint32_t		sectors_per_stripe;
443 
444 	if (io_flags & 0xFFFF) {
445 		/* The bottom 16 bits must be empty */
446 		SPDK_ERRLOG("io_flags 0x%x bottom 16 bits is not empty\n",
447 			    io_flags);
448 		return NULL;
449 	}
450 
451 	sector_size = ns->extended_lba_size;
452 	sectors_per_max_io = ns->sectors_per_max_io;
453 	sectors_per_stripe = ns->sectors_per_stripe;
454 
455 	if ((io_flags & SPDK_NVME_IO_FLAGS_PRACT) &&
456 	    (ns->flags & SPDK_NVME_NS_EXTENDED_LBA_SUPPORTED) &&
457 	    (ns->flags & SPDK_NVME_NS_DPS_PI_SUPPORTED) &&
458 	    (ns->md_size == 8)) {
459 		sector_size -= 8;
460 	}
461 
462 	req = nvme_allocate_request(qpair, payload, lba_count * sector_size, cb_fn, cb_arg);
463 	if (req == NULL) {
464 		return NULL;
465 	}
466 
467 	req->payload_offset = payload_offset;
468 	req->md_offset = md_offset;
469 
470 	/*
471 	 * Intel DC P3*00 NVMe controllers benefit from driver-assisted striping.
472 	 * If this controller defines a stripe boundary and this I/O spans a stripe
473 	 *  boundary, split the request into multiple requests and submit each
474 	 *  separately to hardware.
475 	 */
476 	if (sectors_per_stripe > 0 &&
477 	    (((lba & (sectors_per_stripe - 1)) + lba_count) > sectors_per_stripe)) {
478 
479 		return _nvme_ns_cmd_split_request(ns, qpair, payload, payload_offset, md_offset, lba, lba_count,
480 						  cb_fn,
481 						  cb_arg, opc,
482 						  io_flags, req, sectors_per_stripe, sectors_per_stripe - 1, apptag_mask, apptag);
483 	} else if (lba_count > sectors_per_max_io) {
484 		return _nvme_ns_cmd_split_request(ns, qpair, payload, payload_offset, md_offset, lba, lba_count,
485 						  cb_fn,
486 						  cb_arg, opc,
487 						  io_flags, req, sectors_per_max_io, 0, apptag_mask, apptag);
488 	} else if (nvme_payload_type(&req->payload) == NVME_PAYLOAD_TYPE_SGL && check_sgl) {
489 		if (ns->ctrlr->flags & SPDK_NVME_CTRLR_SGL_SUPPORTED) {
490 			return _nvme_ns_cmd_split_request_sgl(ns, qpair, payload, payload_offset, md_offset,
491 							      lba, lba_count, cb_fn, cb_arg, opc, io_flags,
492 							      req, apptag_mask, apptag);
493 		} else {
494 			return _nvme_ns_cmd_split_request_prp(ns, qpair, payload, payload_offset, md_offset,
495 							      lba, lba_count, cb_fn, cb_arg, opc, io_flags,
496 							      req, apptag_mask, apptag);
497 		}
498 	}
499 
500 	_nvme_ns_cmd_setup_request(ns, req, opc, lba, lba_count, io_flags, apptag_mask, apptag);
501 	return req;
502 }
503 
504 int
505 spdk_nvme_ns_cmd_compare(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, void *buffer,
506 			 uint64_t lba,
507 			 uint32_t lba_count, spdk_nvme_cmd_cb cb_fn, void *cb_arg,
508 			 uint32_t io_flags)
509 {
510 	struct nvme_request *req;
511 	struct nvme_payload payload;
512 
513 	payload = NVME_PAYLOAD_CONTIG(buffer, NULL);
514 
515 	req = _nvme_ns_cmd_rw(ns, qpair, &payload, 0, 0, lba, lba_count, cb_fn, cb_arg,
516 			      SPDK_NVME_OPC_COMPARE,
517 			      io_flags, 0,
518 			      0, true);
519 	if (req != NULL) {
520 		return nvme_qpair_submit_request(qpair, req);
521 	} else if (spdk_nvme_ns_check_request_length(lba_count,
522 			ns->sectors_per_max_io,
523 			ns->sectors_per_stripe,
524 			qpair->ctrlr->opts.io_queue_requests)) {
525 		return -EINVAL;
526 	} else {
527 		return -ENOMEM;
528 	}
529 }
530 
531 int
532 spdk_nvme_ns_cmd_compare_with_md(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
533 				 void *buffer,
534 				 void *metadata,
535 				 uint64_t lba,
536 				 uint32_t lba_count, spdk_nvme_cmd_cb cb_fn, void *cb_arg,
537 				 uint32_t io_flags, uint16_t apptag_mask, uint16_t apptag)
538 {
539 	struct nvme_request *req;
540 	struct nvme_payload payload;
541 
542 	payload = NVME_PAYLOAD_CONTIG(buffer, metadata);
543 
544 	req = _nvme_ns_cmd_rw(ns, qpair, &payload, 0, 0, lba, lba_count, cb_fn, cb_arg,
545 			      SPDK_NVME_OPC_COMPARE,
546 			      io_flags,
547 			      apptag_mask, apptag, true);
548 	if (req != NULL) {
549 		return nvme_qpair_submit_request(qpair, req);
550 	} else if (spdk_nvme_ns_check_request_length(lba_count,
551 			ns->sectors_per_max_io,
552 			ns->sectors_per_stripe,
553 			qpair->ctrlr->opts.io_queue_requests)) {
554 		return -EINVAL;
555 	} else {
556 		return -ENOMEM;
557 	}
558 }
559 
560 int
561 spdk_nvme_ns_cmd_comparev(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
562 			  uint64_t lba, uint32_t lba_count,
563 			  spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags,
564 			  spdk_nvme_req_reset_sgl_cb reset_sgl_fn,
565 			  spdk_nvme_req_next_sge_cb next_sge_fn)
566 {
567 	struct nvme_request *req;
568 	struct nvme_payload payload;
569 
570 	if (reset_sgl_fn == NULL || next_sge_fn == NULL) {
571 		return -EINVAL;
572 	}
573 
574 	payload = NVME_PAYLOAD_SGL(reset_sgl_fn, next_sge_fn, cb_arg, NULL);
575 
576 	req = _nvme_ns_cmd_rw(ns, qpair, &payload, 0, 0, lba, lba_count, cb_fn, cb_arg,
577 			      SPDK_NVME_OPC_COMPARE,
578 			      io_flags, 0, 0, true);
579 	if (req != NULL) {
580 		return nvme_qpair_submit_request(qpair, req);
581 	} else if (spdk_nvme_ns_check_request_length(lba_count,
582 			ns->sectors_per_max_io,
583 			ns->sectors_per_stripe,
584 			qpair->ctrlr->opts.io_queue_requests)) {
585 		return -EINVAL;
586 	} else {
587 		return -ENOMEM;
588 	}
589 }
590 
591 int
592 spdk_nvme_ns_cmd_read(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, void *buffer,
593 		      uint64_t lba,
594 		      uint32_t lba_count, spdk_nvme_cmd_cb cb_fn, void *cb_arg,
595 		      uint32_t io_flags)
596 {
597 	struct nvme_request *req;
598 	struct nvme_payload payload;
599 
600 	payload = NVME_PAYLOAD_CONTIG(buffer, NULL);
601 
602 	req = _nvme_ns_cmd_rw(ns, qpair, &payload, 0, 0, lba, lba_count, cb_fn, cb_arg, SPDK_NVME_OPC_READ,
603 			      io_flags, 0,
604 			      0, true);
605 	if (req != NULL) {
606 		return nvme_qpair_submit_request(qpair, req);
607 	} else if (spdk_nvme_ns_check_request_length(lba_count,
608 			ns->sectors_per_max_io,
609 			ns->sectors_per_stripe,
610 			qpair->ctrlr->opts.io_queue_requests)) {
611 		return -EINVAL;
612 	} else {
613 		return -ENOMEM;
614 	}
615 }
616 
617 int
618 spdk_nvme_ns_cmd_read_with_md(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, void *buffer,
619 			      void *metadata,
620 			      uint64_t lba,
621 			      uint32_t lba_count, spdk_nvme_cmd_cb cb_fn, void *cb_arg,
622 			      uint32_t io_flags, uint16_t apptag_mask, uint16_t apptag)
623 {
624 	struct nvme_request *req;
625 	struct nvme_payload payload;
626 
627 	payload = NVME_PAYLOAD_CONTIG(buffer, metadata);
628 
629 	req = _nvme_ns_cmd_rw(ns, qpair, &payload, 0, 0, lba, lba_count, cb_fn, cb_arg, SPDK_NVME_OPC_READ,
630 			      io_flags,
631 			      apptag_mask, apptag, true);
632 	if (req != NULL) {
633 		return nvme_qpair_submit_request(qpair, req);
634 	} else if (spdk_nvme_ns_check_request_length(lba_count,
635 			ns->sectors_per_max_io,
636 			ns->sectors_per_stripe,
637 			qpair->ctrlr->opts.io_queue_requests)) {
638 		return -EINVAL;
639 	} else {
640 		return -ENOMEM;
641 	}
642 }
643 
644 int
645 spdk_nvme_ns_cmd_readv(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
646 		       uint64_t lba, uint32_t lba_count,
647 		       spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags,
648 		       spdk_nvme_req_reset_sgl_cb reset_sgl_fn,
649 		       spdk_nvme_req_next_sge_cb next_sge_fn)
650 {
651 	struct nvme_request *req;
652 	struct nvme_payload payload;
653 
654 	if (reset_sgl_fn == NULL || next_sge_fn == NULL) {
655 		return -EINVAL;
656 	}
657 
658 	payload = NVME_PAYLOAD_SGL(reset_sgl_fn, next_sge_fn, cb_arg, NULL);
659 
660 	req = _nvme_ns_cmd_rw(ns, qpair, &payload, 0, 0, lba, lba_count, cb_fn, cb_arg, SPDK_NVME_OPC_READ,
661 			      io_flags, 0, 0, true);
662 	if (req != NULL) {
663 		return nvme_qpair_submit_request(qpair, req);
664 	} else if (spdk_nvme_ns_check_request_length(lba_count,
665 			ns->sectors_per_max_io,
666 			ns->sectors_per_stripe,
667 			qpair->ctrlr->opts.io_queue_requests)) {
668 		return -EINVAL;
669 	} else {
670 		return -ENOMEM;
671 	}
672 }
673 
674 int
675 spdk_nvme_ns_cmd_readv_with_md(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
676 			       uint64_t lba, uint32_t lba_count,
677 			       spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags,
678 			       spdk_nvme_req_reset_sgl_cb reset_sgl_fn,
679 			       spdk_nvme_req_next_sge_cb next_sge_fn, void *metadata,
680 			       uint16_t apptag_mask, uint16_t apptag)
681 {
682 	struct nvme_request *req;
683 	struct nvme_payload payload;
684 
685 	if (reset_sgl_fn == NULL || next_sge_fn == NULL) {
686 		return -EINVAL;
687 	}
688 
689 	payload = NVME_PAYLOAD_SGL(reset_sgl_fn, next_sge_fn, cb_arg, metadata);
690 
691 	req = _nvme_ns_cmd_rw(ns, qpair, &payload, 0, 0, lba, lba_count, cb_fn, cb_arg, SPDK_NVME_OPC_READ,
692 			      io_flags, apptag_mask, apptag, true);
693 	if (req != NULL) {
694 		return nvme_qpair_submit_request(qpair, req);
695 	} else if (spdk_nvme_ns_check_request_length(lba_count,
696 			ns->sectors_per_max_io,
697 			ns->sectors_per_stripe,
698 			qpair->ctrlr->opts.io_queue_requests)) {
699 		return -EINVAL;
700 	} else {
701 		return -ENOMEM;
702 	}
703 }
704 
705 int
706 spdk_nvme_ns_cmd_write(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
707 		       void *buffer, uint64_t lba,
708 		       uint32_t lba_count, spdk_nvme_cmd_cb cb_fn, void *cb_arg,
709 		       uint32_t io_flags)
710 {
711 	struct nvme_request *req;
712 	struct nvme_payload payload;
713 
714 	payload = NVME_PAYLOAD_CONTIG(buffer, NULL);
715 
716 	req = _nvme_ns_cmd_rw(ns, qpair, &payload, 0, 0, lba, lba_count, cb_fn, cb_arg, SPDK_NVME_OPC_WRITE,
717 			      io_flags, 0, 0, true);
718 	if (req != NULL) {
719 		return nvme_qpair_submit_request(qpair, req);
720 	} else if (spdk_nvme_ns_check_request_length(lba_count,
721 			ns->sectors_per_max_io,
722 			ns->sectors_per_stripe,
723 			qpair->ctrlr->opts.io_queue_requests)) {
724 		return -EINVAL;
725 	} else {
726 		return -ENOMEM;
727 	}
728 }
729 
730 int
731 spdk_nvme_ns_cmd_write_with_md(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
732 			       void *buffer, void *metadata, uint64_t lba,
733 			       uint32_t lba_count, spdk_nvme_cmd_cb cb_fn, void *cb_arg,
734 			       uint32_t io_flags, uint16_t apptag_mask, uint16_t apptag)
735 {
736 	struct nvme_request *req;
737 	struct nvme_payload payload;
738 
739 	payload = NVME_PAYLOAD_CONTIG(buffer, metadata);
740 
741 	req = _nvme_ns_cmd_rw(ns, qpair, &payload, 0, 0, lba, lba_count, cb_fn, cb_arg, SPDK_NVME_OPC_WRITE,
742 			      io_flags, apptag_mask, apptag, true);
743 	if (req != NULL) {
744 		return nvme_qpair_submit_request(qpair, req);
745 	} else if (spdk_nvme_ns_check_request_length(lba_count,
746 			ns->sectors_per_max_io,
747 			ns->sectors_per_stripe,
748 			qpair->ctrlr->opts.io_queue_requests)) {
749 		return -EINVAL;
750 	} else {
751 		return -ENOMEM;
752 	}
753 }
754 
755 int
756 spdk_nvme_ns_cmd_writev(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
757 			uint64_t lba, uint32_t lba_count,
758 			spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags,
759 			spdk_nvme_req_reset_sgl_cb reset_sgl_fn,
760 			spdk_nvme_req_next_sge_cb next_sge_fn)
761 {
762 	struct nvme_request *req;
763 	struct nvme_payload payload;
764 
765 	if (reset_sgl_fn == NULL || next_sge_fn == NULL) {
766 		return -EINVAL;
767 	}
768 
769 	payload = NVME_PAYLOAD_SGL(reset_sgl_fn, next_sge_fn, cb_arg, NULL);
770 
771 	req = _nvme_ns_cmd_rw(ns, qpair, &payload, 0, 0, lba, lba_count, cb_fn, cb_arg, SPDK_NVME_OPC_WRITE,
772 			      io_flags, 0, 0, true);
773 	if (req != NULL) {
774 		return nvme_qpair_submit_request(qpair, req);
775 	} else if (spdk_nvme_ns_check_request_length(lba_count,
776 			ns->sectors_per_max_io,
777 			ns->sectors_per_stripe,
778 			qpair->ctrlr->opts.io_queue_requests)) {
779 		return -EINVAL;
780 	} else {
781 		return -ENOMEM;
782 	}
783 }
784 
785 int
786 spdk_nvme_ns_cmd_writev_with_md(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
787 				uint64_t lba, uint32_t lba_count,
788 				spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags,
789 				spdk_nvme_req_reset_sgl_cb reset_sgl_fn,
790 				spdk_nvme_req_next_sge_cb next_sge_fn, void *metadata,
791 				uint16_t apptag_mask, uint16_t apptag)
792 {
793 	struct nvme_request *req;
794 	struct nvme_payload payload;
795 
796 	if (reset_sgl_fn == NULL || next_sge_fn == NULL) {
797 		return -EINVAL;
798 	}
799 
800 	payload = NVME_PAYLOAD_SGL(reset_sgl_fn, next_sge_fn, cb_arg, metadata);
801 
802 	req = _nvme_ns_cmd_rw(ns, qpair, &payload, 0, 0, lba, lba_count, cb_fn, cb_arg, SPDK_NVME_OPC_WRITE,
803 			      io_flags, apptag_mask, apptag, true);
804 	if (req != NULL) {
805 		return nvme_qpair_submit_request(qpair, req);
806 	} else if (spdk_nvme_ns_check_request_length(lba_count,
807 			ns->sectors_per_max_io,
808 			ns->sectors_per_stripe,
809 			qpair->ctrlr->opts.io_queue_requests)) {
810 		return -EINVAL;
811 	} else {
812 		return -ENOMEM;
813 	}
814 }
815 
816 int
817 spdk_nvme_ns_cmd_write_zeroes(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
818 			      uint64_t lba, uint32_t lba_count,
819 			      spdk_nvme_cmd_cb cb_fn, void *cb_arg,
820 			      uint32_t io_flags)
821 {
822 	struct nvme_request	*req;
823 	struct spdk_nvme_cmd	*cmd;
824 	uint64_t		*tmp_lba;
825 
826 	if (lba_count == 0 || lba_count > UINT16_MAX + 1) {
827 		return -EINVAL;
828 	}
829 
830 	req = nvme_allocate_request_null(qpair, cb_fn, cb_arg);
831 	if (req == NULL) {
832 		return -ENOMEM;
833 	}
834 
835 	cmd = &req->cmd;
836 	cmd->opc = SPDK_NVME_OPC_WRITE_ZEROES;
837 	cmd->nsid = ns->id;
838 
839 	tmp_lba = (uint64_t *)&cmd->cdw10;
840 	*tmp_lba = lba;
841 	cmd->cdw12 = lba_count - 1;
842 	cmd->cdw12 |= io_flags;
843 
844 	return nvme_qpair_submit_request(qpair, req);
845 }
846 
847 int
848 spdk_nvme_ns_cmd_dataset_management(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
849 				    uint32_t type,
850 				    const struct spdk_nvme_dsm_range *ranges, uint16_t num_ranges,
851 				    spdk_nvme_cmd_cb cb_fn, void *cb_arg)
852 {
853 	struct nvme_request	*req;
854 	struct spdk_nvme_cmd	*cmd;
855 
856 	if (num_ranges == 0 || num_ranges > SPDK_NVME_DATASET_MANAGEMENT_MAX_RANGES) {
857 		return -EINVAL;
858 	}
859 
860 	if (ranges == NULL) {
861 		return -EINVAL;
862 	}
863 
864 	req = nvme_allocate_request_user_copy(qpair, (void *)ranges,
865 					      num_ranges * sizeof(struct spdk_nvme_dsm_range),
866 					      cb_fn, cb_arg, true);
867 	if (req == NULL) {
868 		return -ENOMEM;
869 	}
870 
871 	cmd = &req->cmd;
872 	cmd->opc = SPDK_NVME_OPC_DATASET_MANAGEMENT;
873 	cmd->nsid = ns->id;
874 
875 	cmd->cdw10 = num_ranges - 1;
876 	cmd->cdw11 = type;
877 
878 	return nvme_qpair_submit_request(qpair, req);
879 }
880 
881 int
882 spdk_nvme_ns_cmd_flush(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
883 		       spdk_nvme_cmd_cb cb_fn, void *cb_arg)
884 {
885 	struct nvme_request	*req;
886 	struct spdk_nvme_cmd	*cmd;
887 
888 	req = nvme_allocate_request_null(qpair, cb_fn, cb_arg);
889 	if (req == NULL) {
890 		return -ENOMEM;
891 	}
892 
893 	cmd = &req->cmd;
894 	cmd->opc = SPDK_NVME_OPC_FLUSH;
895 	cmd->nsid = ns->id;
896 
897 	return nvme_qpair_submit_request(qpair, req);
898 }
899 
900 int
901 spdk_nvme_ns_cmd_reservation_register(struct spdk_nvme_ns *ns,
902 				      struct spdk_nvme_qpair *qpair,
903 				      struct spdk_nvme_reservation_register_data *payload,
904 				      bool ignore_key,
905 				      enum spdk_nvme_reservation_register_action action,
906 				      enum spdk_nvme_reservation_register_cptpl cptpl,
907 				      spdk_nvme_cmd_cb cb_fn, void *cb_arg)
908 {
909 	struct nvme_request	*req;
910 	struct spdk_nvme_cmd	*cmd;
911 
912 	req = nvme_allocate_request_user_copy(qpair,
913 					      payload, sizeof(struct spdk_nvme_reservation_register_data),
914 					      cb_fn, cb_arg, true);
915 	if (req == NULL) {
916 		return -ENOMEM;
917 	}
918 
919 	cmd = &req->cmd;
920 	cmd->opc = SPDK_NVME_OPC_RESERVATION_REGISTER;
921 	cmd->nsid = ns->id;
922 
923 	/* Bits 0-2 */
924 	cmd->cdw10 = action;
925 	/* Bit 3 */
926 	cmd->cdw10 |= ignore_key ? 1 << 3 : 0;
927 	/* Bits 30-31 */
928 	cmd->cdw10 |= (uint32_t)cptpl << 30;
929 
930 	return nvme_qpair_submit_request(qpair, req);
931 }
932 
933 int
934 spdk_nvme_ns_cmd_reservation_release(struct spdk_nvme_ns *ns,
935 				     struct spdk_nvme_qpair *qpair,
936 				     struct spdk_nvme_reservation_key_data *payload,
937 				     bool ignore_key,
938 				     enum spdk_nvme_reservation_release_action action,
939 				     enum spdk_nvme_reservation_type type,
940 				     spdk_nvme_cmd_cb cb_fn, void *cb_arg)
941 {
942 	struct nvme_request	*req;
943 	struct spdk_nvme_cmd	*cmd;
944 
945 	req = nvme_allocate_request_user_copy(qpair,
946 					      payload, sizeof(struct spdk_nvme_reservation_key_data), cb_fn,
947 					      cb_arg, true);
948 	if (req == NULL) {
949 		return -ENOMEM;
950 	}
951 
952 	cmd = &req->cmd;
953 	cmd->opc = SPDK_NVME_OPC_RESERVATION_RELEASE;
954 	cmd->nsid = ns->id;
955 
956 	/* Bits 0-2 */
957 	cmd->cdw10 = action;
958 	/* Bit 3 */
959 	cmd->cdw10 |= ignore_key ? 1 << 3 : 0;
960 	/* Bits 8-15 */
961 	cmd->cdw10 |= (uint32_t)type << 8;
962 
963 	return nvme_qpair_submit_request(qpair, req);
964 }
965 
966 int
967 spdk_nvme_ns_cmd_reservation_acquire(struct spdk_nvme_ns *ns,
968 				     struct spdk_nvme_qpair *qpair,
969 				     struct spdk_nvme_reservation_acquire_data *payload,
970 				     bool ignore_key,
971 				     enum spdk_nvme_reservation_acquire_action action,
972 				     enum spdk_nvme_reservation_type type,
973 				     spdk_nvme_cmd_cb cb_fn, void *cb_arg)
974 {
975 	struct nvme_request	*req;
976 	struct spdk_nvme_cmd	*cmd;
977 
978 	req = nvme_allocate_request_user_copy(qpair,
979 					      payload, sizeof(struct spdk_nvme_reservation_acquire_data),
980 					      cb_fn, cb_arg, true);
981 	if (req == NULL) {
982 		return -ENOMEM;
983 	}
984 
985 	cmd = &req->cmd;
986 	cmd->opc = SPDK_NVME_OPC_RESERVATION_ACQUIRE;
987 	cmd->nsid = ns->id;
988 
989 	/* Bits 0-2 */
990 	cmd->cdw10 = action;
991 	/* Bit 3 */
992 	cmd->cdw10 |= ignore_key ? 1 << 3 : 0;
993 	/* Bits 8-15 */
994 	cmd->cdw10 |= (uint32_t)type << 8;
995 
996 	return nvme_qpair_submit_request(qpair, req);
997 }
998 
999 int
1000 spdk_nvme_ns_cmd_reservation_report(struct spdk_nvme_ns *ns,
1001 				    struct spdk_nvme_qpair *qpair,
1002 				    void *payload, uint32_t len,
1003 				    spdk_nvme_cmd_cb cb_fn, void *cb_arg)
1004 {
1005 	uint32_t		num_dwords;
1006 	struct nvme_request	*req;
1007 	struct spdk_nvme_cmd	*cmd;
1008 
1009 	if (len % 4) {
1010 		return -EINVAL;
1011 	}
1012 	num_dwords = len / 4;
1013 
1014 	req = nvme_allocate_request_user_copy(qpair, payload, len, cb_fn, cb_arg, false);
1015 	if (req == NULL) {
1016 		return -ENOMEM;
1017 	}
1018 
1019 	cmd = &req->cmd;
1020 	cmd->opc = SPDK_NVME_OPC_RESERVATION_REPORT;
1021 	cmd->nsid = ns->id;
1022 
1023 	cmd->cdw10 = num_dwords;
1024 
1025 	return nvme_qpair_submit_request(qpair, req);
1026 }
1027