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