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