xref: /spdk/module/bdev/nvme/vbdev_opal.c (revision 19d5c3ed8e87dbd240c77ae0ddb5eda25ae99b5f)
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/opal.h"
35 #include "spdk/bdev_module.h"
36 #include "vbdev_opal.h"
37 #include "spdk_internal/log.h"
38 #include "spdk/string.h"
39 
40 /* OPAL locking range only supports operations on nsid=1 for now */
41 #define NSID_SUPPORTED		1
42 
43 struct spdk_vbdev_opal_config {
44 	char *nvme_ctrlr_name;
45 	uint8_t locking_range_id;
46 	uint64_t range_start;
47 	uint64_t range_length;
48 	SPDK_BDEV_PART_TAILQ *part_tailq;
49 	struct vbdev_opal_part_base *opal_base;
50 };
51 
52 struct opal_vbdev {
53 	char *name;
54 	struct nvme_bdev_ctrlr *nvme_ctrlr;
55 	struct spdk_opal_dev *opal_dev;
56 	struct spdk_bdev_part *bdev_part;
57 	struct spdk_vbdev_opal_config cfg;
58 
59 	TAILQ_ENTRY(opal_vbdev) tailq;
60 };
61 
62 static TAILQ_HEAD(, opal_vbdev) g_opal_vbdev =
63 	TAILQ_HEAD_INITIALIZER(g_opal_vbdev);
64 
65 struct vbdev_opal_bdev_io {
66 	struct spdk_io_channel *ch;
67 	struct spdk_bdev_io *bdev_io;
68 	struct spdk_bdev_io_wait_entry bdev_io_wait;
69 };
70 
71 struct vbdev_opal_channel {
72 	struct spdk_bdev_part_channel part_ch;
73 };
74 
75 struct vbdev_opal_part_base {
76 	char *nvme_ctrlr_name;
77 	struct spdk_bdev_part_base *part_base;
78 	int num_of_part;
79 	TAILQ_ENTRY(vbdev_opal_part_base) tailq;
80 };
81 
82 static TAILQ_HEAD(, vbdev_opal_part_base) g_opal_base = TAILQ_HEAD_INITIALIZER(g_opal_base);
83 
84 static void _vbdev_opal_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io);
85 
86 static void vbdev_opal_examine(struct spdk_bdev *bdev);
87 
88 static void
89 vbdev_opal_delete(struct opal_vbdev *opal_bdev)
90 {
91 	TAILQ_REMOVE(&g_opal_vbdev, opal_bdev, tailq);
92 	free(opal_bdev->name);
93 	free(opal_bdev->cfg.nvme_ctrlr_name);
94 	free(opal_bdev);
95 	opal_bdev = NULL;
96 }
97 
98 static void
99 vbdev_opal_clear(void)
100 {
101 	struct opal_vbdev *opal_bdev, *tmp;
102 
103 	TAILQ_FOREACH_SAFE(opal_bdev, &g_opal_vbdev, tailq, tmp) {
104 		vbdev_opal_delete(opal_bdev);
105 	}
106 }
107 
108 static int
109 vbdev_opal_init(void)
110 {
111 	/* TODO */
112 	return 0;
113 }
114 
115 static void
116 vbdev_opal_fini(void)
117 {
118 	vbdev_opal_clear();
119 }
120 
121 static int
122 vbdev_opal_get_ctx_size(void)
123 {
124 	return sizeof(struct vbdev_opal_bdev_io);
125 }
126 
127 /* delete all the config of the same base bdev */
128 static void
129 vbdev_opal_delete_all_base_config(struct vbdev_opal_part_base *base)
130 {
131 	char *nvme_ctrlr_name = base->nvme_ctrlr_name;
132 	struct opal_vbdev *bdev, *tmp_bdev;
133 
134 	TAILQ_FOREACH_SAFE(bdev, &g_opal_vbdev, tailq, tmp_bdev) {
135 		if (!strcmp(nvme_ctrlr_name, bdev->nvme_ctrlr->name)) {
136 			vbdev_opal_delete(bdev);
137 		}
138 	}
139 }
140 
141 static int
142 vbdev_opal_destruct(void *ctx)
143 {
144 	struct spdk_bdev_part *part = ctx;
145 
146 	return spdk_bdev_part_free(part);
147 }
148 
149 static void
150 vbdev_opal_base_free(void *ctx)
151 {
152 	struct vbdev_opal_part_base *base = ctx;
153 	SPDK_BDEV_PART_TAILQ *part_tailq = spdk_bdev_part_base_get_tailq(base->part_base);
154 
155 	free(part_tailq);
156 	free(base->nvme_ctrlr_name);
157 	free(base);
158 }
159 
160 static void
161 vbdev_opal_resubmit_io(void *arg)
162 {
163 	struct vbdev_opal_bdev_io *io_ctx = (struct vbdev_opal_bdev_io *)arg;
164 
165 	_vbdev_opal_submit_request(io_ctx->ch, io_ctx->bdev_io);
166 }
167 
168 static void
169 vbdev_opal_queue_io(struct vbdev_opal_bdev_io *io_ctx)
170 {
171 	struct vbdev_opal_channel *ch = spdk_io_channel_get_ctx(io_ctx->ch);
172 	int rc;
173 
174 	io_ctx->bdev_io_wait.bdev = io_ctx->bdev_io->bdev;
175 	io_ctx->bdev_io_wait.cb_fn = vbdev_opal_resubmit_io;
176 	io_ctx->bdev_io_wait.cb_arg = io_ctx;
177 
178 	rc = spdk_bdev_queue_io_wait(io_ctx->bdev_io->bdev, ch->part_ch.base_ch, &io_ctx->bdev_io_wait);
179 
180 	if (rc != 0) {
181 		SPDK_ERRLOG("Queue io failed in vbdev_opal_queue_io: %d\n", rc);
182 		spdk_bdev_io_complete(io_ctx->bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
183 	}
184 }
185 
186 static void
187 _vbdev_opal_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io)
188 {
189 	struct vbdev_opal_channel *ch = spdk_io_channel_get_ctx(_ch);
190 	struct vbdev_opal_bdev_io *io_ctx = (struct vbdev_opal_bdev_io *)bdev_io->driver_ctx;
191 	int rc;
192 
193 	rc = spdk_bdev_part_submit_request(&ch->part_ch, bdev_io);
194 	if (rc) {
195 		if (rc == -ENOMEM) {
196 			SPDK_DEBUGLOG(SPDK_LOG_VBDEV_OPAL, "opal: no memory, queue io.\n");
197 			io_ctx->ch = _ch;
198 			io_ctx->bdev_io = bdev_io;
199 			vbdev_opal_queue_io(io_ctx);
200 		} else {
201 			SPDK_ERRLOG("opal: error on io submission, rc=%d.\n", rc);
202 			spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
203 		}
204 	}
205 }
206 
207 static void
208 vbdev_opal_io_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io, bool success)
209 {
210 	if (!success) {
211 		spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
212 		return;
213 	}
214 
215 	_vbdev_opal_submit_request(ch, bdev_io);
216 }
217 
218 static void
219 vbdev_opal_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
220 {
221 	switch (bdev_io->type) {
222 	case SPDK_BDEV_IO_TYPE_READ:
223 		spdk_bdev_io_get_buf(bdev_io, vbdev_opal_io_get_buf_cb,
224 				     bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
225 		break;
226 	default:
227 		_vbdev_opal_submit_request(ch, bdev_io);
228 		break;
229 	}
230 }
231 
232 struct spdk_opal_locking_range_info *
233 spdk_vbdev_opal_get_info_from_bdev(const char *opal_bdev_name, const char *password)
234 {
235 	struct opal_vbdev *vbdev;
236 	struct nvme_bdev_ctrlr *nvme_ctrlr;
237 	int locking_range_id;
238 	int rc;
239 
240 	TAILQ_FOREACH(vbdev, &g_opal_vbdev, tailq) {
241 		if (strcmp(vbdev->name, opal_bdev_name) == 0) {
242 			break;
243 		}
244 	}
245 
246 	if (vbdev == NULL) {
247 		SPDK_ERRLOG("%s not found\n", opal_bdev_name);
248 		return NULL;
249 	}
250 
251 	nvme_ctrlr = vbdev->nvme_ctrlr;
252 	if (nvme_ctrlr == NULL) {
253 		SPDK_ERRLOG("can't find nvme_ctrlr of %s\n", vbdev->name);
254 		return NULL;
255 	}
256 
257 	if (spdk_opal_get_max_locking_ranges(nvme_ctrlr->opal_dev) == 0) {
258 		rc = spdk_opal_cmd_get_max_ranges(nvme_ctrlr->opal_dev, password);
259 		if (rc) {
260 			SPDK_ERRLOG("Get locking range number failure: %d\n", rc);
261 			return NULL;
262 		}
263 	}
264 
265 	locking_range_id = vbdev->cfg.locking_range_id;
266 	rc = spdk_opal_cmd_get_locking_range_info(nvme_ctrlr->opal_dev, password,
267 			OPAL_ADMIN1, locking_range_id);
268 	if (rc) {
269 		SPDK_ERRLOG("Get locking range info error: %d\n", rc);
270 		return NULL;
271 	}
272 
273 	return spdk_opal_get_locking_range_info(nvme_ctrlr->opal_dev, locking_range_id);
274 }
275 
276 static int
277 vbdev_opal_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
278 {
279 	struct spdk_bdev_part *part = ctx;
280 	struct spdk_bdev *base_bdev = spdk_bdev_part_get_base_bdev(part);
281 	uint64_t offset = spdk_bdev_part_get_offset_blocks(part);
282 
283 	spdk_json_write_named_object_begin(w, "opal");
284 
285 	spdk_json_write_named_string(w, "base_bdev", spdk_bdev_get_name(base_bdev));
286 	spdk_json_write_named_uint64(w, "offset_blocks", offset);
287 
288 	spdk_json_write_object_end(w);
289 
290 	return 0;
291 }
292 
293 static void
294 vbdev_opal_base_bdev_hotremove_cb(void *_part_base)
295 {
296 	struct spdk_bdev_part_base *part_base = _part_base;
297 	struct vbdev_opal_part_base *base = spdk_bdev_part_base_get_ctx(part_base);
298 
299 	spdk_bdev_part_base_hotremove(part_base, spdk_bdev_part_base_get_tailq(part_base));
300 	vbdev_opal_delete_all_base_config(base);
301 }
302 
303 static bool
304 vbdev_opal_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
305 {
306 	struct spdk_bdev_part *part = ctx;
307 	struct spdk_bdev *base_bdev = spdk_bdev_part_get_base_bdev(part);
308 
309 	return spdk_bdev_io_type_supported(base_bdev, io_type);
310 }
311 
312 static struct spdk_bdev_fn_table opal_vbdev_fn_table = {
313 	.destruct           = vbdev_opal_destruct,
314 	.submit_request     = vbdev_opal_submit_request,
315 	.io_type_supported  = vbdev_opal_io_type_supported,
316 	.dump_info_json     = vbdev_opal_dump_info_json,
317 	.write_config_json  = NULL,
318 };
319 
320 static struct spdk_bdev_module opal_if = {
321 	.name           = "opal",
322 	.module_init    = vbdev_opal_init,
323 	.module_fini    = vbdev_opal_fini,
324 	.get_ctx_size   = vbdev_opal_get_ctx_size,
325 	.examine_config = vbdev_opal_examine,
326 	.config_json    = NULL,
327 };
328 
329 SPDK_BDEV_MODULE_REGISTER(opal, &opal_if)
330 
331 static void
332 vbdev_opal_free_bdev(struct opal_vbdev *opal_bdev)
333 {
334 	free(opal_bdev->cfg.nvme_ctrlr_name);
335 	free(opal_bdev);
336 }
337 
338 int
339 spdk_vbdev_opal_create(const char *nvme_ctrlr_name, uint32_t nsid, uint8_t locking_range_id,
340 		       uint64_t range_start, uint64_t range_length, const char *password)
341 {
342 	int rc;
343 	char *opal_vbdev_name;
344 	char *base_bdev_name;
345 	struct nvme_bdev_ctrlr *nvme_ctrlr;
346 	struct opal_vbdev *opal_bdev;
347 	struct vbdev_opal_part_base *opal_part_base;
348 	struct spdk_bdev_part *part_bdev;
349 	SPDK_BDEV_PART_TAILQ *part_tailq;
350 	struct spdk_vbdev_opal_config *cfg;
351 	struct nvme_bdev *nvme_bdev;
352 
353 	if (nsid != NSID_SUPPORTED) {
354 		SPDK_ERRLOG("nsid %d not supported", nsid);
355 		return -EINVAL;
356 	}
357 
358 	nvme_ctrlr = nvme_bdev_ctrlr_get_by_name(nvme_ctrlr_name);
359 	if (!nvme_ctrlr) {
360 		SPDK_ERRLOG("get nvme ctrlr failed\n");
361 		return -ENODEV;
362 	}
363 
364 	if (nvme_ctrlr->opal_dev == NULL) {
365 		SPDK_ERRLOG("Opal not supported\n");
366 		return -ENODEV;
367 	}
368 
369 	opal_bdev = calloc(1, sizeof(struct opal_vbdev));
370 	if (!opal_bdev) {
371 		SPDK_ERRLOG("allocation for opal_bdev failed\n");
372 		return -ENOMEM;
373 	}
374 
375 	cfg = &opal_bdev->cfg;
376 	cfg->nvme_ctrlr_name = strdup(nvme_ctrlr_name);
377 	if (!cfg->nvme_ctrlr_name) {
378 		SPDK_ERRLOG("allocation for nvme_ctrlr_name failed\n");
379 		free(opal_bdev);
380 		return -ENOMEM;
381 	}
382 
383 	cfg->locking_range_id = locking_range_id;
384 	cfg->range_start = range_start;
385 	cfg->range_length = range_length;
386 
387 	opal_bdev->nvme_ctrlr = nvme_ctrlr;
388 	opal_bdev->opal_dev = nvme_ctrlr->opal_dev;
389 	if (!spdk_opal_supported(opal_bdev->opal_dev)) {
390 		SPDK_ERRLOG("Opal not supported\n");
391 		vbdev_opal_free_bdev(opal_bdev);
392 		return -EINVAL;
393 	}
394 
395 	nvme_bdev = TAILQ_FIRST(&nvme_ctrlr->namespaces[nsid - 1]->bdevs);
396 	assert(nvme_bdev != NULL);
397 	base_bdev_name = nvme_bdev->disk.name;
398 
399 	/* traverse base list to see if part_base is already create for this base bdev */
400 	TAILQ_FOREACH(opal_part_base, &g_opal_base, tailq) {
401 		if (!strcmp(spdk_bdev_part_base_get_bdev_name(opal_part_base->part_base), base_bdev_name)) {
402 			cfg->opal_base = opal_part_base;
403 		}
404 	}
405 
406 	/* If there is not a corresponding opal_part_base, a new opal_part_base will be created.
407 	   For each new part_base, there will be one tailq to store all the parts of this base */
408 	if (cfg->opal_base == NULL) {
409 		part_tailq = calloc(1, sizeof(*part_tailq));
410 		if (part_tailq == NULL) {
411 			SPDK_ERRLOG("Could not allocate bdev_part_tailq\n");
412 			vbdev_opal_free_bdev(opal_bdev);
413 			return -ENOMEM;
414 		}
415 
416 		TAILQ_INIT(part_tailq);
417 		cfg->part_tailq = part_tailq;
418 		opal_part_base = calloc(1, sizeof(*opal_part_base));
419 		if (opal_part_base == NULL) {
420 			SPDK_ERRLOG("Could not allocate opal_part_base\n");
421 			vbdev_opal_free_bdev(opal_bdev);
422 			free(part_tailq);
423 			return -ENOMEM;
424 		}
425 
426 		opal_part_base->part_base = spdk_bdev_part_base_construct(spdk_bdev_get_by_name(base_bdev_name),
427 					    vbdev_opal_base_bdev_hotremove_cb, &opal_if,
428 					    &opal_vbdev_fn_table, part_tailq, vbdev_opal_base_free, opal_part_base,
429 					    sizeof(struct vbdev_opal_channel), NULL, NULL);
430 		if (opal_part_base->part_base == NULL) {
431 			SPDK_ERRLOG("Could not allocate part_base\n");
432 			vbdev_opal_free_bdev(opal_bdev);
433 			free(part_tailq);
434 			free(opal_part_base);
435 			return -ENOMEM;
436 		}
437 		opal_part_base->num_of_part = 0;
438 		opal_part_base->nvme_ctrlr_name = strdup(cfg->nvme_ctrlr_name);
439 		if (opal_part_base->nvme_ctrlr_name == NULL) {
440 			vbdev_opal_free_bdev(opal_bdev);
441 			spdk_bdev_part_base_free(opal_part_base->part_base);
442 			return -ENOMEM;
443 		}
444 
445 		cfg->opal_base = opal_part_base;
446 		TAILQ_INSERT_TAIL(&g_opal_base, opal_part_base, tailq);
447 	}
448 
449 	part_bdev = calloc(1, sizeof(struct spdk_bdev_part));
450 	if (!part_bdev) {
451 		SPDK_ERRLOG("Could not allocate part_bdev\n");
452 		vbdev_opal_free_bdev(opal_bdev);
453 		return -ENOMEM;
454 	}
455 
456 	TAILQ_INSERT_TAIL(&g_opal_vbdev, opal_bdev, tailq);
457 	opal_vbdev_name = spdk_sprintf_alloc("%sr%" PRIu8, base_bdev_name,
458 					     cfg->locking_range_id);  /* e.g.: nvme0n1r1 */
459 	if (opal_vbdev_name == NULL) {
460 		SPDK_ERRLOG("Could not allocate opal_vbdev_name\n");
461 		rc = -ENOMEM;
462 		goto err;
463 	}
464 
465 	opal_bdev->name = opal_vbdev_name;
466 	rc = spdk_opal_cmd_setup_locking_range(opal_bdev->opal_dev, OPAL_ADMIN1,
467 					       cfg->locking_range_id, cfg->range_start, cfg->range_length, password);
468 	if (rc) {
469 		SPDK_ERRLOG("Error construct %s\n", opal_vbdev_name);
470 		goto err;
471 	}
472 
473 	rc = spdk_bdev_part_construct(part_bdev, cfg->opal_base->part_base, opal_vbdev_name,
474 				      cfg->range_start, cfg->range_length, "Opal locking range");
475 	if (rc) {
476 		SPDK_ERRLOG("Could not allocate bdev part\n");
477 		goto err;
478 	}
479 
480 	/* lock this bdev initially */
481 	rc = spdk_opal_cmd_lock_unlock(opal_bdev->opal_dev, OPAL_ADMIN1, OPAL_RWLOCK, locking_range_id,
482 				       password);
483 	if (rc) {
484 		SPDK_ERRLOG("Error lock %s\n", opal_vbdev_name);
485 		goto err;
486 	}
487 
488 	opal_bdev->bdev_part = part_bdev;
489 	cfg->opal_base->num_of_part++;
490 	return 0;
491 
492 err:
493 	vbdev_opal_delete(opal_bdev);
494 	free(part_bdev);
495 	return rc;
496 }
497 
498 static void
499 vbdev_opal_destruct_bdev(struct opal_vbdev *opal_bdev)
500 {
501 	SPDK_BDEV_PART_TAILQ *opal_part_tailq;
502 	struct spdk_bdev_part *part;
503 	struct spdk_vbdev_opal_config *cfg = &opal_bdev->cfg;
504 
505 	if (cfg->opal_base != NULL) {
506 		part = opal_bdev->bdev_part;
507 		opal_part_tailq = spdk_bdev_part_base_get_tailq(cfg->opal_base->part_base);
508 		if (opal_part_tailq == NULL) {
509 			SPDK_ERRLOG("Can't get tailq for this opal_base\n");
510 			return;
511 		}
512 		if (cfg->range_start == spdk_bdev_part_get_offset_blocks(part)) {
513 			if (cfg->opal_base->num_of_part <= 1) {
514 				/* if there is only one part for this base, we can remove the base now */
515 				spdk_bdev_part_base_hotremove(cfg->opal_base->part_base, opal_part_tailq);
516 
517 				/* remove from the tailq vbdev_opal_part_base */
518 				TAILQ_REMOVE(&g_opal_base, cfg->opal_base, tailq);
519 			} else {
520 				spdk_bdev_unregister(spdk_bdev_part_get_bdev(part), NULL, NULL);
521 				cfg->opal_base->num_of_part--;
522 			}
523 		}
524 	}
525 	vbdev_opal_delete(opal_bdev);
526 }
527 
528 int
529 spdk_vbdev_opal_destruct(const char *bdev_name, const char *password)
530 {
531 	struct spdk_vbdev_opal_config *cfg;
532 	struct nvme_bdev_ctrlr *nvme_ctrlr;
533 	int locking_range_id;
534 	int rc;
535 	struct opal_vbdev *opal_bdev;
536 
537 	TAILQ_FOREACH(opal_bdev, &g_opal_vbdev, tailq) {
538 		if (strcmp(opal_bdev->name, bdev_name) == 0) {
539 			break;
540 		}
541 	}
542 
543 	if (opal_bdev == NULL) {
544 		SPDK_ERRLOG("%s not found\n", bdev_name);
545 		rc = -ENODEV;
546 		goto err;
547 	}
548 
549 	cfg = &opal_bdev->cfg;
550 	locking_range_id = cfg->locking_range_id;
551 
552 	nvme_ctrlr = opal_bdev->nvme_ctrlr;
553 	if (nvme_ctrlr == NULL) {
554 		SPDK_ERRLOG("can't find nvme_ctrlr of %s\n", bdev_name);
555 		return -ENODEV;
556 	}
557 
558 	/* secure erase locking range */
559 	rc = spdk_opal_cmd_erase_locking_range(nvme_ctrlr->opal_dev, OPAL_ADMIN1, locking_range_id,
560 					       password);
561 	if (rc) {
562 		SPDK_ERRLOG("opal erase locking range failed\n");
563 		goto err;
564 	}
565 
566 	/* reset the locking range to 0 */
567 	rc = spdk_opal_cmd_setup_locking_range(nvme_ctrlr->opal_dev, OPAL_ADMIN1, locking_range_id, 0,
568 					       0, password);
569 	if (rc) {
570 		SPDK_ERRLOG("opal reset locking range failed\n");
571 		goto err;
572 	}
573 
574 	spdk_opal_free_locking_range_info(opal_bdev->opal_dev, locking_range_id);
575 	vbdev_opal_destruct_bdev(opal_bdev);
576 	return 0;
577 
578 err:
579 	return rc;
580 }
581 
582 static void
583 vbdev_opal_examine(struct spdk_bdev *bdev)
584 {
585 	/* TODO */
586 	spdk_bdev_module_examine_done(&opal_if);
587 }
588 
589 static int
590 vbdev_opal_recv_poll(void *arg)
591 {
592 	struct nvme_bdev_ctrlr *nvme_ctrlr = arg;
593 	int rc;
594 
595 	rc = spdk_opal_revert_poll(nvme_ctrlr->opal_dev);
596 	if (rc == -EAGAIN) {
597 		return -1;
598 	}
599 
600 	/* receive end */
601 	spdk_poller_unregister(&nvme_ctrlr->opal_poller);
602 	nvme_ctrlr->opal_poller = NULL;
603 	return 1;
604 }
605 
606 int
607 spdk_vbdev_opal_revert_tper(struct nvme_bdev_ctrlr *nvme_ctrlr, const char *password,
608 			    spdk_opal_revert_cb cb_fn, void *cb_ctx)
609 {
610 	int rc;
611 
612 	rc = spdk_opal_cmd_revert_tper_async(nvme_ctrlr->opal_dev, password, cb_fn, cb_ctx);
613 	if (rc) {
614 		SPDK_ERRLOG("%s revert tper failure: %d\n", nvme_ctrlr->name, rc);
615 		return rc;
616 	}
617 	nvme_ctrlr->opal_poller = spdk_poller_register(vbdev_opal_recv_poll, nvme_ctrlr, 50);
618 	return 0;
619 }
620 
621 int
622 spdk_vbdev_opal_set_lock_state(const char *bdev_name, uint16_t user_id, const char *password,
623 			       const char *lock_state)
624 {
625 	struct nvme_bdev_ctrlr *nvme_ctrlr;
626 	int locking_range_id;
627 	int rc;
628 	enum spdk_opal_lock_state state_flag;
629 	struct opal_vbdev *opal_bdev;
630 
631 	TAILQ_FOREACH(opal_bdev, &g_opal_vbdev, tailq) {
632 		if (strcmp(opal_bdev->name, bdev_name) == 0) {
633 			break;
634 		}
635 	}
636 
637 	if (opal_bdev == NULL) {
638 		SPDK_ERRLOG("%s not found\n", bdev_name);
639 		return -ENODEV;
640 	}
641 
642 	nvme_ctrlr = opal_bdev->nvme_ctrlr;
643 	if (nvme_ctrlr == NULL) {
644 		SPDK_ERRLOG("can't find nvme_ctrlr of %s\n", opal_bdev->name);
645 		return -ENODEV;
646 	}
647 
648 	if (strcasecmp(lock_state, "READWRITE") == 0) {
649 		state_flag = OPAL_READWRITE;
650 	} else if (strcasecmp(lock_state, "READONLY") == 0) {
651 		state_flag = OPAL_READONLY;
652 	} else if (strcasecmp(lock_state, "RWLOCK") == 0) {
653 		state_flag = OPAL_RWLOCK;
654 	} else {
655 		SPDK_ERRLOG("Invalid OPAL lock state input\n");
656 		return -EINVAL;
657 	}
658 
659 	locking_range_id = opal_bdev->cfg.locking_range_id;
660 	rc = spdk_opal_cmd_lock_unlock(nvme_ctrlr->opal_dev, user_id, state_flag, locking_range_id,
661 				       password);
662 	if (rc) {
663 		SPDK_ERRLOG("%s lock/unlock failure: %d\n", bdev_name, rc);
664 	}
665 
666 	return rc;
667 }
668 
669 int
670 spdk_vbdev_opal_enable_new_user(const char *bdev_name, const char *admin_password, uint16_t user_id,
671 				const char *user_password)
672 {
673 	struct nvme_bdev_ctrlr *nvme_ctrlr;
674 	int locking_range_id;
675 	int rc;
676 	struct opal_vbdev *opal_bdev;
677 
678 	TAILQ_FOREACH(opal_bdev, &g_opal_vbdev, tailq) {
679 		if (strcmp(opal_bdev->name, bdev_name) == 0) {
680 			break;
681 		}
682 	}
683 
684 	if (opal_bdev == NULL) {
685 		SPDK_ERRLOG("%s not found\n", bdev_name);
686 		return -ENODEV;
687 	}
688 
689 	nvme_ctrlr = opal_bdev->nvme_ctrlr;
690 	if (nvme_ctrlr == NULL) {
691 		SPDK_ERRLOG("can't find nvme_ctrlr of %s\n", opal_bdev->name);
692 		return -ENODEV;
693 	}
694 
695 	rc = spdk_opal_cmd_enable_user(nvme_ctrlr->opal_dev, user_id, admin_password);
696 	if (rc) {
697 		SPDK_ERRLOG("%s enable user error: %d\n", bdev_name, rc);
698 		return rc;
699 	}
700 
701 	rc = spdk_opal_cmd_set_new_passwd(nvme_ctrlr->opal_dev, user_id, user_password, admin_password,
702 					  true);
703 	if (rc) {
704 		SPDK_ERRLOG("%s set user password error: %d\n", bdev_name, rc);
705 		return rc;
706 	}
707 
708 	locking_range_id = opal_bdev->cfg.locking_range_id;
709 	rc = spdk_opal_cmd_add_user_to_locking_range(nvme_ctrlr->opal_dev, user_id, locking_range_id,
710 			OPAL_READONLY, admin_password);
711 	if (rc) {
712 		SPDK_ERRLOG("%s add user READONLY priority error: %d\n", bdev_name, rc);
713 		return rc;
714 	}
715 
716 	rc = spdk_opal_cmd_add_user_to_locking_range(nvme_ctrlr->opal_dev, user_id, locking_range_id,
717 			OPAL_READWRITE, admin_password);
718 	if (rc) {
719 		SPDK_ERRLOG("%s add user READWRITE priority error: %d\n", bdev_name, rc);
720 		return rc;
721 	}
722 
723 	return 0;
724 }
725 
726 SPDK_LOG_REGISTER_COMPONENT("vbdev_opal", SPDK_LOG_VBDEV_OPAL)
727