xref: /haiku/src/add-ons/kernel/drivers/disk/nvme/libnvme/nvme_ns.c (revision af4a03df24c7d171cab14019f0c53a6804b79554)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation. All rights reserved.
5  *   Copyright (c) 2017, Western Digital Corporation or its affiliates.
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 
nvme_ns_get_data(struct nvme_ns * ns)36 static inline struct nvme_ns_data *nvme_ns_get_data(struct nvme_ns *ns)
37 {
38 	return &ns->ctrlr->nsdata[ns->id - 1];
39 }
40 
nvme_ns_identify_update(struct nvme_ns * ns)41 static int nvme_ns_identify_update(struct nvme_ns *ns)
42 {
43 	struct nvme_ctrlr *ctrlr = ns->ctrlr;
44 	struct nvme_ns_data *nsdata = nvme_ns_get_data(ns);
45 	uint32_t sector_size;
46 	int ret;
47 
48 	ret = nvme_admin_identify_ns(ctrlr, ns->id, nsdata);
49 	if (ret != 0) {
50 		nvme_err("nvme_identify_namespace failed\n");
51 		return ret;
52 	}
53 
54 	sector_size = 1 << nsdata->lbaf[nsdata->flbas.format].lbads;
55 
56 	ns->sector_size = sector_size;
57 	ns->sectors_per_max_io = ctrlr->max_xfer_size / sector_size;
58 	ns->sectors_per_stripe = ns->stripe_size / sector_size;
59 
60 	ns->flags = 0x0000;
61 
62 	if (ctrlr->cdata.oncs.dsm)
63 		ns->flags |= NVME_NS_DEALLOCATE_SUPPORTED;
64 
65 	if (ctrlr->cdata.vwc.present)
66 		ns->flags |= NVME_NS_FLUSH_SUPPORTED;
67 
68 	if (ctrlr->cdata.oncs.write_zeroes)
69 		ns->flags |= NVME_NS_WRITE_ZEROES_SUPPORTED;
70 
71 	if (nsdata->nsrescap.raw)
72 		ns->flags |= NVME_NS_RESERVATION_SUPPORTED;
73 
74 	ns->md_size = nsdata->lbaf[nsdata->flbas.format].ms;
75 	ns->pi_type = NVME_FMT_NVM_PROTECTION_DISABLE;
76 
77 	if (nsdata->lbaf[nsdata->flbas.format].ms && nsdata->dps.pit) {
78 		ns->flags |= NVME_NS_DPS_PI_SUPPORTED;
79 		ns->pi_type = nsdata->dps.pit;
80 		if (nsdata->flbas.extended)
81 			ns->flags |= NVME_NS_EXTENDED_LBA_SUPPORTED;
82 	}
83 
84 	return 0;
85 }
86 
87 /*
88  * Initialize a namespace.
89  */
nvme_ns_construct(struct nvme_ctrlr * ctrlr,struct nvme_ns * ns,unsigned int id)90 int nvme_ns_construct(struct nvme_ctrlr *ctrlr, struct nvme_ns *ns,
91 		      unsigned int id)
92 {
93 	uint32_t pci_devid;
94 
95 	ns->ctrlr = ctrlr;
96 	ns->id = id;
97 	ns->stripe_size = 0;
98 
99 	nvme_pcicfg_read32(ctrlr->pci_dev, &pci_devid, 0);
100 	if (pci_devid == INTEL_DC_P3X00_DEVID && ctrlr->cdata.vs[3] != 0)
101 		ns->stripe_size = (1 << ctrlr->cdata.vs[3])
102 			* ctrlr->min_page_size;
103 
104 	return nvme_ns_identify_update(ns);
105 }
106 
107 /*
108  * Open a namespace.
109  */
nvme_ns_open(struct nvme_ctrlr * ctrlr,unsigned int ns_id)110 struct nvme_ns *nvme_ns_open(struct nvme_ctrlr *ctrlr, unsigned int ns_id)
111 {
112 	struct nvme_ns *ns = NULL;
113 
114 	pthread_mutex_lock(&ctrlr->lock);
115 
116 	if (ns_id >= 1 && ns_id <= ctrlr->nr_ns) {
117 		ns = &ctrlr->ns[ns_id - 1];
118 		ns->open_count++;
119 	}
120 
121 	pthread_mutex_unlock(&ctrlr->lock);
122 
123 	return ns;
124 }
125 
126 /*
127  * Get the controller of an open name space and lock it,
128  * making sure in the process that the ns handle is valid.
129  */
nvme_ns_ctrlr_lock(struct nvme_ns * ns)130 static struct nvme_ctrlr *nvme_ns_ctrlr_lock(struct nvme_ns *ns)
131 {
132 	struct nvme_ctrlr *ctrlr;
133 
134 	if (!ns)
135 		return NULL;
136 
137 	ctrlr = ns->ctrlr;
138 	if (ns->id < 1 ||
139 	    ns->id > ctrlr->nr_ns ||
140 	    ns != &ctrlr->ns[ns->id - 1])
141 		return NULL;
142 
143 	pthread_mutex_lock(&ctrlr->lock);
144 
145 	/*
146 	 * Between the check and lock, the ns may have gone away.
147 	 * So check again, and make sure that the name space is open.
148 	 */
149 	if (ns->id > ctrlr->nr_ns ||
150 	    ns != &ctrlr->ns[ns->id - 1] ||
151 	    ns->open_count == 0) {
152 		pthread_mutex_unlock(&ctrlr->lock);
153 		return NULL;
154 	}
155 
156 	return ctrlr;
157 }
158 
159 /*
160  * Close an open namespace.
161  */
nvme_ns_close(struct nvme_ns * ns)162 int nvme_ns_close(struct nvme_ns *ns)
163 {
164 	struct nvme_ctrlr *ctrlr;
165 
166 	ctrlr = nvme_ns_ctrlr_lock(ns);
167 	if (!ctrlr) {
168 		nvme_err("Invalid name space handle\n");
169 		return EINVAL;
170 	}
171 
172 	ns->open_count--;
173 
174 	pthread_mutex_unlock(&ctrlr->lock);
175 
176 	return 0;
177 }
178 
179 /*
180  * Get namespace information
181  */
nvme_ns_stat(struct nvme_ns * ns,struct nvme_ns_stat * ns_stat)182 int nvme_ns_stat(struct nvme_ns *ns, struct nvme_ns_stat *ns_stat)
183 {
184 	struct nvme_ctrlr *ctrlr;
185 
186 	ctrlr = nvme_ns_ctrlr_lock(ns);
187 	if (!ctrlr) {
188 		nvme_err("Invalid name space handle\n");
189 		return EINVAL;
190 	}
191 
192 	ns_stat->id = ns->id;
193 	ns_stat->sector_size = ns->sector_size;
194 	ns_stat->sectors = nvme_ns_get_data(ns)->nsze;
195 	ns_stat->flags = ns->flags;
196 	ns_stat->pi_type = ns->pi_type;
197 	ns_stat->md_size = ns->md_size;
198 
199 	pthread_mutex_unlock(&ctrlr->lock);
200 
201 	return 0;
202 }
203 
204 /*
205  * Get namespace data
206  */
nvme_ns_data(struct nvme_ns * ns,struct nvme_ns_data * nsdata)207 int nvme_ns_data(struct nvme_ns *ns, struct nvme_ns_data *nsdata)
208 {
209 	struct nvme_ctrlr *ctrlr;
210 
211 	ctrlr = nvme_ns_ctrlr_lock(ns);
212 	if (!ctrlr) {
213 		nvme_err("Invalid name space handle\n");
214 		return EINVAL;
215 	}
216 
217 	memcpy(nsdata, nvme_ns_get_data(ns), sizeof(struct nvme_ns_data));
218 
219 	pthread_mutex_unlock(&ctrlr->lock);
220 
221 	return 0;
222 }
223 
224 static struct nvme_request *_nvme_ns_rw(struct nvme_ns *ns,
225 			struct nvme_qpair *qpair,
226 			const struct nvme_payload *payload, uint64_t lba,
227 			uint32_t lba_count, nvme_cmd_cb cb_fn,
228 			void *cb_arg, uint32_t opc, uint32_t io_flags,
229 			uint16_t apptag_mask, uint16_t apptag);
230 
231 static struct nvme_request *
_nvme_ns_split_request(struct nvme_ns * ns,struct nvme_qpair * qpair,const struct nvme_payload * payload,uint64_t lba,uint32_t lba_count,nvme_cmd_cb cb_fn,void * cb_arg,uint32_t opc,uint32_t io_flags,struct nvme_request * req,uint32_t sectors_per_max_io,uint32_t sector_mask,uint16_t apptag_mask,uint16_t apptag)232 _nvme_ns_split_request(struct nvme_ns *ns,
233 		       struct nvme_qpair *qpair,
234 		       const struct nvme_payload *payload,
235 		       uint64_t lba, uint32_t lba_count,
236 		       nvme_cmd_cb cb_fn, void *cb_arg,
237 		       uint32_t opc,
238 		       uint32_t io_flags,
239 		       struct nvme_request *req,
240 		       uint32_t sectors_per_max_io,
241 		       uint32_t sector_mask,
242 		       uint16_t apptag_mask,
243 		       uint16_t apptag)
244 {
245 	uint32_t sector_size = ns->sector_size;
246 	uint32_t md_size = ns->md_size;
247 	uint32_t remaining_lba_count = lba_count;
248 	uint32_t offset = 0;
249 	uint32_t md_offset = 0;
250 	struct nvme_request *child, *tmp;
251 
252 	if (ns->flags & NVME_NS_DPS_PI_SUPPORTED) {
253 		/* for extended LBA only */
254 		if ((ns->flags & NVME_NS_EXTENDED_LBA_SUPPORTED)
255 		    && !(io_flags & NVME_IO_FLAGS_PRACT))
256 			sector_size += ns->md_size;
257 	}
258 
259 	while (remaining_lba_count > 0) {
260 
261 		lba_count = sectors_per_max_io - (lba & sector_mask);
262 		lba_count = nvme_min(remaining_lba_count, lba_count);
263 
264 		child = _nvme_ns_rw(ns, qpair, payload, lba, lba_count, cb_fn,
265 				    cb_arg, opc, io_flags, apptag_mask, apptag);
266 		if (child == NULL) {
267 			if (req->child_reqs) {
268 				/* free all child nvme_request  */
269 				TAILQ_FOREACH_SAFE(child, &req->children,
270 						   child_tailq, tmp) {
271 					nvme_request_remove_child(req, child);
272 					nvme_request_free(child);
273 				}
274 			}
275 			return NULL;
276 		}
277 
278 		child->payload_offset = offset;
279 
280 		/* for separate metadata buffer only */
281 		if (payload->md)
282 			child->md_offset = md_offset;
283 
284 		nvme_request_add_child(req, child);
285 
286 		remaining_lba_count -= lba_count;
287 		lba += lba_count;
288 		offset += lba_count * sector_size;
289 		md_offset += lba_count * md_size;
290 
291 	}
292 
293 	return req;
294 }
295 
_nvme_ns_rw(struct nvme_ns * ns,struct nvme_qpair * qpair,const struct nvme_payload * payload,uint64_t lba,uint32_t lba_count,nvme_cmd_cb cb_fn,void * cb_arg,uint32_t opc,uint32_t io_flags,uint16_t apptag_mask,uint16_t apptag)296 static struct nvme_request *_nvme_ns_rw(struct nvme_ns *ns,
297 					struct nvme_qpair *qpair,
298 					const struct nvme_payload *payload,
299 					uint64_t lba, uint32_t lba_count,
300 					nvme_cmd_cb cb_fn, void *cb_arg,
301 					uint32_t opc,
302 					uint32_t io_flags,
303 					uint16_t apptag_mask,
304 					uint16_t apptag)
305 {
306 	struct nvme_request *req;
307 	struct nvme_cmd	*cmd;
308 	uint64_t *tmp_lba;
309 	uint32_t sector_size;
310 	uint32_t sectors_per_max_io;
311 	uint32_t sectors_per_stripe;
312 
313 	/* The bottom 16 bits must be empty */
314 	if (io_flags & 0xFFFF)
315 		return NULL;
316 
317 	sector_size = ns->sector_size;
318 	sectors_per_max_io = ns->sectors_per_max_io;
319 	sectors_per_stripe = ns->sectors_per_stripe;
320 
321 	if (ns->flags & NVME_NS_DPS_PI_SUPPORTED)
322 		/* for extended LBA only */
323 		if ((ns->flags & NVME_NS_EXTENDED_LBA_SUPPORTED) &&
324 		    !(io_flags & NVME_IO_FLAGS_PRACT))
325 			sector_size += ns->md_size;
326 
327 	req = nvme_request_allocate(qpair, payload,
328 				    lba_count * sector_size, cb_fn, cb_arg);
329 	if (req == NULL)
330 		return NULL;
331 
332 	/*
333 	 * Intel DC P3*00 NVMe controllers benefit from driver-assisted striping.
334 	 * If this controller defines a stripe boundary and this I/O spans
335 	 * a stripe boundary, split the request into multiple requests and
336 	 * submit each separately to hardware.
337 	 */
338 	if (sectors_per_stripe > 0 &&
339 	    (((lba & (sectors_per_stripe - 1)) + lba_count) > sectors_per_stripe))
340 		return _nvme_ns_split_request(ns, qpair, payload, lba,
341 					      lba_count, cb_fn, cb_arg, opc,
342 					      io_flags, req, sectors_per_stripe,
343 					      sectors_per_stripe - 1,
344 					      apptag_mask, apptag);
345 
346 	if (lba_count > sectors_per_max_io)
347 		return _nvme_ns_split_request(ns, qpair, payload, lba,
348 					      lba_count, cb_fn, cb_arg, opc,
349 					      io_flags, req, sectors_per_max_io,
350 					      0, apptag_mask, apptag);
351 
352 	cmd = &req->cmd;
353 	cmd->opc = opc;
354 	cmd->nsid = ns->id;
355 
356 	tmp_lba = (uint64_t *)&cmd->cdw10;
357 	*tmp_lba = lba;
358 
359 	if (ns->flags & NVME_NS_DPS_PI_SUPPORTED) {
360 		switch (ns->pi_type) {
361 		case NVME_FMT_NVM_PROTECTION_TYPE1:
362 		case NVME_FMT_NVM_PROTECTION_TYPE2:
363 			cmd->cdw14 = (uint32_t)lba;
364 			break;
365 		}
366 	}
367 
368 	cmd->cdw12 = lba_count - 1;
369 	cmd->cdw12 |= io_flags;
370 
371 	cmd->cdw15 = apptag_mask;
372 	cmd->cdw15 = (cmd->cdw15 << 16 | apptag);
373 
374 	return req;
375 }
376 
nvme_ns_read(struct nvme_ns * ns,struct nvme_qpair * qpair,void * buffer,uint64_t lba,uint32_t lba_count,nvme_cmd_cb cb_fn,void * cb_arg,unsigned int io_flags)377 int nvme_ns_read(struct nvme_ns *ns, struct nvme_qpair *qpair,
378 		 void *buffer,
379 		 uint64_t lba, uint32_t lba_count,
380 		 nvme_cmd_cb cb_fn, void *cb_arg,
381 		 unsigned int io_flags)
382 {
383 	struct nvme_request *req;
384 	struct nvme_payload payload;
385 
386 	payload.type = NVME_PAYLOAD_TYPE_CONTIG;
387 	payload.u.contig = buffer;
388 	payload.md = NULL;
389 
390 	req = _nvme_ns_rw(ns, qpair, &payload, lba, lba_count, cb_fn, cb_arg,
391 			  NVME_OPC_READ, io_flags, 0, 0);
392 	if (req != NULL)
393 		return nvme_qpair_submit_request(qpair, req);
394 
395 	return ENOMEM;
396 }
397 
nvme_ns_read_with_md(struct nvme_ns * ns,struct nvme_qpair * qpair,void * buffer,void * metadata,uint64_t lba,uint32_t lba_count,nvme_cmd_cb cb_fn,void * cb_arg,unsigned int io_flags,uint16_t apptag_mask,uint16_t apptag)398 int nvme_ns_read_with_md(struct nvme_ns *ns, struct nvme_qpair *qpair,
399 			 void *buffer, void *metadata,
400 			 uint64_t lba, uint32_t lba_count,
401 			 nvme_cmd_cb cb_fn, void *cb_arg,
402 			 unsigned int io_flags,
403 			 uint16_t apptag_mask, uint16_t apptag)
404 {
405 	struct nvme_request *req;
406 	struct nvme_payload payload;
407 
408 	payload.type = NVME_PAYLOAD_TYPE_CONTIG;
409 	payload.u.contig = buffer;
410 	payload.md = metadata;
411 
412 	req = _nvme_ns_rw(ns, qpair, &payload, lba, lba_count, cb_fn, cb_arg,
413 			  NVME_OPC_READ, io_flags, apptag_mask, apptag);
414 	if (req != NULL)
415 		return nvme_qpair_submit_request(qpair, req);
416 
417 	return ENOMEM;
418 }
419 
nvme_ns_readv(struct nvme_ns * ns,struct nvme_qpair * qpair,uint64_t lba,uint32_t lba_count,nvme_cmd_cb cb_fn,void * cb_arg,unsigned int io_flags,nvme_req_reset_sgl_cb reset_sgl_fn,nvme_req_next_sge_cb next_sge_fn)420 int nvme_ns_readv(struct nvme_ns *ns, struct nvme_qpair *qpair,
421 		  uint64_t lba, uint32_t lba_count,
422 		  nvme_cmd_cb cb_fn, void *cb_arg,
423 		  unsigned int io_flags,
424 		  nvme_req_reset_sgl_cb reset_sgl_fn,
425 		  nvme_req_next_sge_cb next_sge_fn)
426 {
427 	struct nvme_request *req;
428 	struct nvme_payload payload;
429 
430 	if (reset_sgl_fn == NULL || next_sge_fn == NULL)
431 		return EINVAL;
432 
433 	payload.type = NVME_PAYLOAD_TYPE_SGL;
434 	payload.md = NULL;
435 	payload.u.sgl.reset_sgl_fn = reset_sgl_fn;
436 	payload.u.sgl.next_sge_fn = next_sge_fn;
437 	payload.u.sgl.cb_arg = cb_arg;
438 
439 	req = _nvme_ns_rw(ns, qpair, &payload, lba, lba_count, cb_fn, cb_arg,
440 			  NVME_OPC_READ, io_flags, 0, 0);
441 	if (req != NULL)
442 		return nvme_qpair_submit_request(qpair, req);
443 
444 	return ENOMEM;
445 }
446 
nvme_ns_write(struct nvme_ns * ns,struct nvme_qpair * qpair,void * buffer,uint64_t lba,uint32_t lba_count,nvme_cmd_cb cb_fn,void * cb_arg,unsigned int io_flags)447 int nvme_ns_write(struct nvme_ns *ns, struct nvme_qpair *qpair,
448 		  void *buffer,
449 		  uint64_t lba, uint32_t lba_count,
450 		  nvme_cmd_cb cb_fn, void *cb_arg,
451 		  unsigned int io_flags)
452 {
453 	struct nvme_request *req;
454 	struct nvme_payload payload;
455 
456 	payload.type = NVME_PAYLOAD_TYPE_CONTIG;
457 	payload.u.contig = buffer;
458 	payload.md = NULL;
459 
460 	req = _nvme_ns_rw(ns, qpair, &payload, lba, lba_count, cb_fn, cb_arg,
461 			  NVME_OPC_WRITE, io_flags, 0, 0);
462 	if (req != NULL)
463 		return nvme_qpair_submit_request(qpair, req);
464 
465 	return ENOMEM;
466 }
467 
nvme_ns_write_with_md(struct nvme_ns * ns,struct nvme_qpair * qpair,void * buffer,void * metadata,uint64_t lba,uint32_t lba_count,nvme_cmd_cb cb_fn,void * cb_arg,unsigned int io_flags,uint16_t apptag_mask,uint16_t apptag)468 int nvme_ns_write_with_md(struct nvme_ns *ns, struct nvme_qpair *qpair,
469 			  void *buffer, void *metadata,
470 			  uint64_t lba, uint32_t lba_count,
471 			  nvme_cmd_cb cb_fn, void *cb_arg,
472 			  unsigned int io_flags,
473 			  uint16_t apptag_mask, uint16_t apptag)
474 {
475 	struct nvme_request *req;
476 	struct nvme_payload payload;
477 
478 	payload.type = NVME_PAYLOAD_TYPE_CONTIG;
479 	payload.u.contig = buffer;
480 	payload.md = metadata;
481 
482 	req = _nvme_ns_rw(ns, qpair, &payload, lba, lba_count, cb_fn, cb_arg,
483 			  NVME_OPC_WRITE, io_flags, apptag_mask, apptag);
484 	if (req != NULL)
485 		return nvme_qpair_submit_request(qpair, req);
486 
487 	return ENOMEM;
488 }
489 
nvme_ns_writev(struct nvme_ns * ns,struct nvme_qpair * qpair,uint64_t lba,uint32_t lba_count,nvme_cmd_cb cb_fn,void * cb_arg,unsigned int io_flags,nvme_req_reset_sgl_cb reset_sgl_fn,nvme_req_next_sge_cb next_sge_fn)490 int nvme_ns_writev(struct nvme_ns *ns, struct nvme_qpair *qpair,
491 		   uint64_t lba, uint32_t lba_count,
492 		   nvme_cmd_cb cb_fn, void *cb_arg,
493 		   unsigned int io_flags,
494 		   nvme_req_reset_sgl_cb reset_sgl_fn,
495 		   nvme_req_next_sge_cb next_sge_fn)
496 {
497 	struct nvme_request *req;
498 	struct nvme_payload payload;
499 
500 	if (reset_sgl_fn == NULL || next_sge_fn == NULL)
501 		return EINVAL;
502 
503 	payload.type = NVME_PAYLOAD_TYPE_SGL;
504 	payload.md = NULL;
505 	payload.u.sgl.reset_sgl_fn = reset_sgl_fn;
506 	payload.u.sgl.next_sge_fn = next_sge_fn;
507 	payload.u.sgl.cb_arg = cb_arg;
508 
509 	req = _nvme_ns_rw(ns, qpair, &payload, lba, lba_count, cb_fn, cb_arg,
510 			  NVME_OPC_WRITE, io_flags, 0, 0);
511 	if (req != NULL)
512 		return nvme_qpair_submit_request(qpair, req);
513 
514 	return ENOMEM;
515 }
516 
nvme_ns_write_zeroes(struct nvme_ns * ns,struct nvme_qpair * qpair,uint64_t lba,uint32_t lba_count,nvme_cmd_cb cb_fn,void * cb_arg,unsigned int io_flags)517 int nvme_ns_write_zeroes(struct nvme_ns *ns, struct nvme_qpair *qpair,
518 			 uint64_t lba, uint32_t lba_count,
519 			 nvme_cmd_cb cb_fn, void *cb_arg,
520 			 unsigned int io_flags)
521 {
522 	struct nvme_request *req;
523 	struct nvme_cmd	*cmd;
524 	uint64_t *tmp_lba;
525 
526 	if (lba_count == 0)
527 		return EINVAL;
528 
529 	req = nvme_request_allocate_null(qpair, cb_fn, cb_arg);
530 	if (req == NULL)
531 		return ENOMEM;
532 
533 	cmd = &req->cmd;
534 	cmd->opc = NVME_OPC_WRITE_ZEROES;
535 	cmd->nsid = ns->id;
536 
537 	tmp_lba = (uint64_t *)&cmd->cdw10;
538 	*tmp_lba = lba;
539 	cmd->cdw12 = lba_count - 1;
540 	cmd->cdw12 |= io_flags;
541 
542 	return nvme_qpair_submit_request(qpair, req);
543 }
544 
nvme_ns_deallocate(struct nvme_ns * ns,struct nvme_qpair * qpair,void * payload,uint16_t ranges,nvme_cmd_cb cb_fn,void * cb_arg)545 int nvme_ns_deallocate(struct nvme_ns *ns, struct nvme_qpair *qpair,
546 		       void *payload, uint16_t ranges,
547 		       nvme_cmd_cb cb_fn, void *cb_arg)
548 {
549 	struct nvme_request *req;
550 	struct nvme_cmd	*cmd;
551 
552 	if (ranges == 0 || ranges > NVME_DATASET_MANAGEMENT_MAX_RANGES)
553 		return EINVAL;
554 
555 	req = nvme_request_allocate_contig(qpair, payload,
556 				   ranges * sizeof(struct nvme_dsm_range),
557 				   cb_fn, cb_arg);
558 	if (req == NULL)
559 		return ENOMEM;
560 
561 	cmd = &req->cmd;
562 	cmd->opc = NVME_OPC_DATASET_MANAGEMENT;
563 	cmd->nsid = ns->id;
564 
565 	/* TODO: create a delete command data structure */
566 	cmd->cdw10 = ranges - 1;
567 	cmd->cdw11 = NVME_DSM_ATTR_DEALLOCATE;
568 
569 	return nvme_qpair_submit_request(qpair, req);
570 }
571 
nvme_ns_flush(struct nvme_ns * ns,struct nvme_qpair * qpair,nvme_cmd_cb cb_fn,void * cb_arg)572 int nvme_ns_flush(struct nvme_ns *ns, struct nvme_qpair *qpair,
573 		  nvme_cmd_cb cb_fn, void *cb_arg)
574 {
575 	struct nvme_request *req;
576 	struct nvme_cmd	*cmd;
577 
578 	req = nvme_request_allocate_null(qpair, cb_fn, cb_arg);
579 	if (req == NULL)
580 		return ENOMEM;
581 
582 	cmd = &req->cmd;
583 	cmd->opc = NVME_OPC_FLUSH;
584 	cmd->nsid = ns->id;
585 
586 	return nvme_qpair_submit_request(qpair, req);
587 }
588 
nvme_ns_reservation_register(struct nvme_ns * ns,struct nvme_qpair * qpair,struct nvme_reservation_register_data * payload,bool ignore_key,enum nvme_reservation_register_action action,enum nvme_reservation_register_cptpl cptpl,nvme_cmd_cb cb_fn,void * cb_arg)589 int nvme_ns_reservation_register(struct nvme_ns *ns, struct nvme_qpair *qpair,
590 				 struct nvme_reservation_register_data *payload,
591 				 bool ignore_key,
592 				 enum nvme_reservation_register_action action,
593 				 enum nvme_reservation_register_cptpl cptpl,
594 				 nvme_cmd_cb cb_fn, void *cb_arg)
595 {
596 	struct nvme_request *req;
597 	struct nvme_cmd	*cmd;
598 
599 	req = nvme_request_allocate_contig(qpair, payload,
600 					   sizeof(struct nvme_reservation_register_data),
601 					   cb_fn, cb_arg);
602 	if (req == NULL)
603 		return ENOMEM;
604 
605 	cmd = &req->cmd;
606 	cmd->opc = NVME_OPC_RESERVATION_REGISTER;
607 	cmd->nsid = ns->id;
608 
609 	/* Bits 0-2 */
610 	cmd->cdw10 = action;
611 	/* Bit 3 */
612 	cmd->cdw10 |= ignore_key ? 1 << 3 : 0;
613 	/* Bits 30-31 */
614 	cmd->cdw10 |= (uint32_t)cptpl << 30;
615 
616 	return nvme_qpair_submit_request(qpair, req);
617 }
618 
nvme_ns_reservation_release(struct nvme_ns * ns,struct nvme_qpair * qpair,struct nvme_reservation_key_data * payload,bool ignore_key,enum nvme_reservation_release_action action,enum nvme_reservation_type type,nvme_cmd_cb cb_fn,void * cb_arg)619 int nvme_ns_reservation_release(struct nvme_ns *ns, struct nvme_qpair *qpair,
620 				struct nvme_reservation_key_data *payload,
621 				bool ignore_key,
622 				enum nvme_reservation_release_action action,
623 				enum nvme_reservation_type type,
624 				nvme_cmd_cb cb_fn, void *cb_arg)
625 {
626 	struct nvme_request *req;
627 	struct nvme_cmd	*cmd;
628 
629 	req = nvme_request_allocate_contig(qpair, payload,
630 					   sizeof(struct nvme_reservation_key_data),
631 					   cb_fn, cb_arg);
632 	if (req == NULL)
633 		return ENOMEM;
634 
635 	cmd = &req->cmd;
636 	cmd->opc = NVME_OPC_RESERVATION_RELEASE;
637 	cmd->nsid = ns->id;
638 
639 	/* Bits 0-2 */
640 	cmd->cdw10 = action;
641 	/* Bit 3 */
642 	cmd->cdw10 |= ignore_key ? 1 << 3 : 0;
643 	/* Bits 8-15 */
644 	cmd->cdw10 |= (uint32_t)type << 8;
645 
646 	return nvme_qpair_submit_request(qpair, req);
647 }
648 
nvme_ns_reservation_acquire(struct nvme_ns * ns,struct nvme_qpair * qpair,struct nvme_reservation_acquire_data * payload,bool ignore_key,enum nvme_reservation_acquire_action action,enum nvme_reservation_type type,nvme_cmd_cb cb_fn,void * cb_arg)649 int nvme_ns_reservation_acquire(struct nvme_ns *ns, struct nvme_qpair *qpair,
650 				struct nvme_reservation_acquire_data *payload,
651 				bool ignore_key,
652 				enum nvme_reservation_acquire_action action,
653 				enum nvme_reservation_type type,
654 				nvme_cmd_cb cb_fn, void *cb_arg)
655 {
656 	struct nvme_request	*req;
657 	struct nvme_cmd	*cmd;
658 
659 	req = nvme_request_allocate_contig(qpair, payload,
660 					   sizeof(struct nvme_reservation_acquire_data),
661 					   cb_fn, cb_arg);
662 	if (req == NULL)
663 		return ENOMEM;
664 
665 	cmd = &req->cmd;
666 	cmd->opc = NVME_OPC_RESERVATION_ACQUIRE;
667 	cmd->nsid = ns->id;
668 
669 	/* Bits 0-2 */
670 	cmd->cdw10 = action;
671 	/* Bit 3 */
672 	cmd->cdw10 |= ignore_key ? 1 << 3 : 0;
673 	/* Bits 8-15 */
674 	cmd->cdw10 |= (uint32_t)type << 8;
675 
676 	return nvme_qpair_submit_request(qpair, req);
677 }
678 
nvme_ns_reservation_report(struct nvme_ns * ns,struct nvme_qpair * qpair,void * payload,size_t len,nvme_cmd_cb cb_fn,void * cb_arg)679 int nvme_ns_reservation_report(struct nvme_ns *ns, struct nvme_qpair *qpair,
680 			       void *payload, size_t len,
681 			       nvme_cmd_cb cb_fn, void *cb_arg)
682 {
683 	uint32_t num_dwords;
684 	struct nvme_request *req;
685 	struct nvme_cmd	*cmd;
686 
687 	if (len % 4)
688 		return EINVAL;
689 	num_dwords = len / 4;
690 
691 	req = nvme_request_allocate_contig(qpair, payload, len, cb_fn, cb_arg);
692 	if (req == NULL)
693 		return ENOMEM;
694 
695 	cmd = &req->cmd;
696 	cmd->opc = NVME_OPC_RESERVATION_REPORT;
697 	cmd->nsid = ns->id;
698 
699 	cmd->cdw10 = num_dwords;
700 
701 	return nvme_qpair_submit_request(qpair, req);
702 }
703