xref: /spdk/lib/nvme/nvme_opal.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 #include "spdk/opal.h"
34 #include "spdk_internal/event.h"
35 #include "spdk_internal/log.h"
36 #include "spdk/util.h"
37 
38 #include "nvme_opal_internal.h"
39 
40 typedef int (spdk_opal_cb)(struct spdk_opal_dev *dev);
41 
42 static int opal_end_session_error(struct spdk_opal_dev *dev);
43 
44 static const char *
45 opal_error_to_human(int error)
46 {
47 	if (error == SPDK_OPAL_FAILED) {
48 		return "FAILED";
49 	}
50 
51 	if ((size_t)error >= SPDK_COUNTOF(spdk_opal_errors) || error < 0) {
52 		return "UNKNOWN ERROR";
53 	}
54 
55 	return spdk_opal_errors[error];
56 }
57 
58 static int
59 opal_send_cmd(struct spdk_opal_dev *dev)
60 {
61 	return spdk_nvme_ctrlr_security_send(dev->dev_handler, SPDK_SCSI_SECP_TCG, dev->comid,
62 					     0, dev->cmd, IO_BUFFER_LENGTH);
63 }
64 
65 static int
66 opal_recv_cmd(struct spdk_opal_dev *dev)
67 {
68 	void *response = dev->resp;
69 	struct spdk_opal_header *header = response;
70 	int ret = 0;
71 	uint64_t start = spdk_get_ticks();
72 	uint64_t now;
73 
74 	do {
75 		ret = spdk_nvme_ctrlr_security_receive(dev->dev_handler, SPDK_SCSI_SECP_TCG, dev->comid,
76 						       0, dev->resp, IO_BUFFER_LENGTH);
77 		if (ret) {
78 			SPDK_ERRLOG("Security Receive Error on dev = %p\n", dev);
79 			return ret;
80 		}
81 		SPDK_DEBUGLOG(SPDK_LOG_OPAL, "outstanding_data=%d, minTransfer=%d\n",
82 			      header->com_packet.outstanding_data,
83 			      header->com_packet.min_transfer);
84 
85 		if (header->com_packet.outstanding_data == 0 &&
86 		    header->com_packet.min_transfer == 0) {
87 			return 0;	/* return if all the response data are ready by tper and received by host */
88 		} else {	/* check timeout */
89 			now = spdk_get_ticks();
90 			if (now - start > dev->timeout * spdk_get_ticks_hz()) {
91 				SPDK_ERRLOG("Secutiy Receive Timeout on dev = %p\n", dev);
92 				return 0x0F; /* TPer Malfunction */
93 			}
94 		}
95 
96 		memset(response, 0, IO_BUFFER_LENGTH);
97 	} while (!ret);
98 
99 	return ret;
100 }
101 
102 static int
103 opal_send_recv(struct spdk_opal_dev *dev, spdk_opal_cb *cb)
104 {
105 	int ret;
106 
107 	ret = opal_send_cmd(dev);
108 	if (ret) {
109 		return ret;
110 	}
111 	ret = opal_recv_cmd(dev);
112 	if (ret) {
113 		return ret;
114 	}
115 	return cb(dev);
116 }
117 
118 static void
119 opal_add_token_u8(int *err, struct spdk_opal_dev *dev, uint8_t token)
120 {
121 	if (*err) {
122 		return;
123 	}
124 	if (dev->cmd_pos >= IO_BUFFER_LENGTH - 1) {
125 		SPDK_ERRLOG("Error adding u8: end of buffer.\n");
126 		*err = -ERANGE;
127 		return;
128 	}
129 	dev->cmd[dev->cmd_pos++] = token;
130 }
131 
132 static int
133 opal_cmd_finalize(struct spdk_opal_dev *dev, uint32_t hsn, uint32_t tsn, bool eod)
134 {
135 	struct spdk_opal_header *hdr;
136 	int err = 0;
137 
138 	if (eod) {
139 		opal_add_token_u8(&err, dev, SPDK_OPAL_ENDOFDATA);
140 		opal_add_token_u8(&err, dev, SPDK_OPAL_STARTLIST);
141 		opal_add_token_u8(&err, dev, 0);
142 		opal_add_token_u8(&err, dev, 0);
143 		opal_add_token_u8(&err, dev, 0);
144 		opal_add_token_u8(&err, dev, SPDK_OPAL_ENDLIST);
145 	}
146 
147 	if (err) {
148 		SPDK_ERRLOG("Error finalizing command.\n");
149 		return -EFAULT;
150 	}
151 
152 	hdr = (struct spdk_opal_header *)dev->cmd;
153 
154 	to_be32(&hdr->packet.session_tsn, tsn);
155 	to_be32(&hdr->packet.session_hsn, hsn);
156 
157 	to_be32(&hdr->sub_packet.length, dev->cmd_pos - sizeof(*hdr));
158 	while (dev->cmd_pos % 4) {
159 		if (dev->cmd_pos >= IO_BUFFER_LENGTH) {
160 			SPDK_ERRLOG("Error: Buffer overrun\n");
161 			return -ERANGE;
162 		}
163 		dev->cmd[dev->cmd_pos++] = 0;
164 	}
165 	to_be32(&hdr->packet.length, dev->cmd_pos - sizeof(hdr->com_packet) -
166 		sizeof(hdr->packet));
167 	to_be32(&hdr->com_packet.length, dev->cmd_pos - sizeof(hdr->com_packet));
168 
169 	return 0;
170 }
171 
172 static int
173 opal_finalize_and_send(struct spdk_opal_dev *dev, bool eod, spdk_opal_cb cb)
174 {
175 	int ret;
176 
177 	ret = opal_cmd_finalize(dev, dev->hsn, dev->tsn, eod);
178 	if (ret) {
179 		SPDK_ERRLOG("Error finalizing command buffer: %d\n", ret);
180 		return ret;
181 	}
182 
183 	return opal_send_recv(dev, cb);
184 }
185 
186 static size_t
187 opal_response_parse_tiny(struct spdk_opal_resp_token *token,
188 			 const uint8_t *pos)
189 {
190 	token->pos = pos;
191 	token->len = 1;
192 	token->width = OPAL_WIDTH_TINY;
193 
194 	if (pos[0] & SPDK_TINY_ATOM_SIGN_FLAG) {
195 		token->type = OPAL_DTA_TOKENID_SINT;
196 	} else {
197 		token->type = OPAL_DTA_TOKENID_UINT;
198 		token->stored.unsigned_num = pos[0] & SPDK_TINY_ATOM_DATA_MASK;
199 	}
200 
201 	return token->len;
202 }
203 
204 static int
205 opal_response_parse_short(struct spdk_opal_resp_token *token,
206 			  const uint8_t *pos)
207 {
208 	token->pos = pos;
209 	token->len = (pos[0] & SPDK_SHORT_ATOM_LEN_MASK) + 1; /* plus 1-byte header */
210 	token->width = OPAL_WIDTH_SHORT;
211 
212 	if (pos[0] & SPDK_SHORT_ATOM_BYTESTRING_FLAG) {
213 		token->type = OPAL_DTA_TOKENID_BYTESTRING;
214 	} else if (pos[0] & SPDK_SHORT_ATOM_SIGN_FLAG) {
215 		token->type = OPAL_DTA_TOKENID_SINT;
216 	} else {
217 		uint64_t u_integer = 0;
218 		size_t i, b = 0;
219 
220 		token->type = OPAL_DTA_TOKENID_UINT;
221 		if (token->len > 9) {
222 			SPDK_ERRLOG("uint64 with more than 8 bytes\n");
223 			return -EINVAL;
224 		}
225 		for (i = token->len - 1; i > 0; i--) {
226 			u_integer |= ((uint64_t)pos[i] << (8 * b));
227 			b++;
228 		}
229 		token->stored.unsigned_num = u_integer;
230 	}
231 
232 	return token->len;
233 }
234 
235 static size_t
236 opal_response_parse_medium(struct spdk_opal_resp_token *token,
237 			   const uint8_t *pos)
238 {
239 	token->pos = pos;
240 	token->len = (((pos[0] & SPDK_MEDIUM_ATOM_LEN_MASK) << 8) | pos[1]) + 2; /* plus 2-byte header */
241 	token->width = OPAL_WIDTH_MEDIUM;
242 
243 	if (pos[0] & SPDK_MEDIUM_ATOM_BYTESTRING_FLAG) {
244 		token->type = OPAL_DTA_TOKENID_BYTESTRING;
245 	} else if (pos[0] & SPDK_MEDIUM_ATOM_SIGN_FLAG) {
246 		token->type = OPAL_DTA_TOKENID_SINT;
247 	} else {
248 		token->type = OPAL_DTA_TOKENID_UINT;
249 	}
250 
251 	return token->len;
252 }
253 
254 static size_t
255 opal_response_parse_long(struct spdk_opal_resp_token *token,
256 			 const uint8_t *pos)
257 {
258 	token->pos = pos;
259 	token->len = ((pos[1] << 16) | (pos[2] << 8) | pos[3]) + 4; /* plus 4-byte header */
260 	token->width = OPAL_WIDTH_LONG;
261 
262 	if (pos[0] & SPDK_LONG_ATOM_BYTESTRING_FLAG) {
263 		token->type = OPAL_DTA_TOKENID_BYTESTRING;
264 	} else if (pos[0] & SPDK_LONG_ATOM_SIGN_FLAG) {
265 		token->type = OPAL_DTA_TOKENID_SINT;
266 	} else {
267 		token->type = OPAL_DTA_TOKENID_UINT;
268 	}
269 
270 	return token->len;
271 }
272 
273 static size_t
274 opal_response_parse_token(struct spdk_opal_resp_token *token,
275 			  const uint8_t *pos)
276 {
277 	token->pos = pos;
278 	token->len = 1;
279 	token->type = OPAL_DTA_TOKENID_TOKEN;
280 	token->width = OPAL_WIDTH_TOKEN;
281 
282 	return token->len;
283 }
284 
285 static int
286 opal_response_parse(const uint8_t *buf, size_t length,
287 		    struct spdk_opal_resp_parsed *resp)
288 {
289 	const struct spdk_opal_header *hdr;
290 	struct spdk_opal_resp_token *token_iter;
291 	int num_entries = 0;
292 	int total;
293 	size_t token_length;
294 	const uint8_t *pos;
295 	uint32_t clen, plen, slen;
296 
297 	if (!buf || !resp) {
298 		return -EINVAL;
299 	}
300 
301 	hdr = (struct spdk_opal_header *)buf;
302 	pos = buf + sizeof(*hdr);
303 
304 	clen = from_be32(&hdr->com_packet.length);
305 	plen = from_be32(&hdr->packet.length);
306 	slen = from_be32(&hdr->sub_packet.length);
307 	SPDK_DEBUGLOG(SPDK_LOG_OPAL, "Response size: cp: %u, pkt: %u, subpkt: %u\n",
308 		      clen, plen, slen);
309 
310 	if (clen == 0 || plen == 0 || slen == 0 ||
311 	    slen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
312 		SPDK_ERRLOG("Bad header length. cp: %u, pkt: %u, subpkt: %u\n",
313 			    clen, plen, slen);
314 		return -EINVAL;
315 	}
316 
317 	if (pos > buf + length) {
318 		SPDK_ERRLOG("Pointer out of range\n");
319 		return -EFAULT;
320 	}
321 
322 	token_iter = resp->resp_tokens;
323 	total = slen;
324 
325 	while (total > 0) {
326 		if (pos[0] <= SPDK_TINY_ATOM_TYPE_MAX) { /* tiny atom */
327 			token_length = opal_response_parse_tiny(token_iter, pos);
328 		} else if (pos[0] <= SPDK_SHORT_ATOM_TYPE_MAX) { /* short atom */
329 			token_length = opal_response_parse_short(token_iter, pos);
330 		} else if (pos[0] <= SPDK_MEDIUM_ATOM_TYPE_MAX) { /* medium atom */
331 			token_length = opal_response_parse_medium(token_iter, pos);
332 		} else if (pos[0] <= SPDK_LONG_ATOM_TYPE_MAX) { /* long atom */
333 			token_length = opal_response_parse_long(token_iter, pos);
334 		} else { /* TOKEN */
335 			token_length = opal_response_parse_token(token_iter, pos);
336 		}
337 
338 		if (token_length <= 0) {
339 			SPDK_ERRLOG("Parse response failure.\n");
340 			return -EINVAL;
341 		}
342 
343 		pos += token_length;
344 		total -= token_length;
345 		token_iter++;
346 		num_entries++;
347 
348 		if (total < 0) {
349 			SPDK_ERRLOG("Length not matching.\n");
350 			return -EINVAL;
351 		}
352 	}
353 
354 	if (num_entries == 0) {
355 		SPDK_ERRLOG("Couldn't parse response.\n");
356 		return -EINVAL;
357 	}
358 	resp->num = num_entries;
359 
360 	return 0;
361 }
362 
363 static inline bool
364 opal_response_token_matches(const struct spdk_opal_resp_token *token,
365 			    uint8_t match)
366 {
367 	if (!token ||
368 	    token->type != OPAL_DTA_TOKENID_TOKEN ||
369 	    token->pos[0] != match) {
370 		SPDK_ERRLOG("Token not matching\n");
371 		return false;
372 	}
373 	return true;
374 }
375 
376 static const struct spdk_opal_resp_token *
377 opal_response_get_token(const struct spdk_opal_resp_parsed *resp, int index)
378 {
379 	const struct spdk_opal_resp_token *token;
380 
381 	if (index >= resp->num) {
382 		SPDK_ERRLOG("Token number doesn't exist: %d, resp: %d\n",
383 			    index, resp->num);
384 		return NULL;
385 	}
386 
387 	token = &resp->resp_tokens[index];
388 	if (token->len == 0) {
389 		SPDK_ERRLOG("Token length must be non-zero\n");
390 		return NULL;
391 	}
392 
393 	return token;
394 }
395 
396 static uint64_t
397 opal_response_get_u64(const struct spdk_opal_resp_parsed *resp, int index)
398 {
399 	if (!resp) {
400 		SPDK_ERRLOG("Response is NULL\n");
401 		return 0;
402 	}
403 
404 	if (resp->resp_tokens[index].type != OPAL_DTA_TOKENID_UINT) {
405 		SPDK_ERRLOG("Token is not unsigned int: %d\n",
406 			    resp->resp_tokens[index].type);
407 		return 0;
408 	}
409 
410 	if (!(resp->resp_tokens[index].width == OPAL_WIDTH_TINY ||
411 	      resp->resp_tokens[index].width == OPAL_WIDTH_SHORT)) {
412 		SPDK_ERRLOG("Atom is not short or tiny: %d\n",
413 			    resp->resp_tokens[index].width);
414 		return 0;
415 	}
416 
417 	return resp->resp_tokens[index].stored.unsigned_num;
418 }
419 
420 static int
421 opal_response_status(const struct spdk_opal_resp_parsed *resp)
422 {
423 	const struct spdk_opal_resp_token *tok;
424 
425 	/* if we get an EOS token, just return 0 */
426 	tok = opal_response_get_token(resp, 0);
427 	if (opal_response_token_matches(tok, SPDK_OPAL_ENDOFSESSION)) {
428 		return 0;
429 	}
430 
431 	if (resp->num < 5) {
432 		return SPDK_DTAERROR_NO_METHOD_STATUS;
433 	}
434 
435 	tok = opal_response_get_token(resp, resp->num - 5); /* the first token should be STARTLIST */
436 	if (!opal_response_token_matches(tok, SPDK_OPAL_STARTLIST)) {
437 		return SPDK_DTAERROR_NO_METHOD_STATUS;
438 	}
439 
440 	tok = opal_response_get_token(resp, resp->num - 1); /* the last token should be ENDLIST */
441 	if (!opal_response_token_matches(tok, SPDK_OPAL_ENDLIST)) {
442 		return SPDK_DTAERROR_NO_METHOD_STATUS;
443 	}
444 
445 	/* The second and third values in the status list are reserved, and are
446 	defined in core spec to be 0x00 and 0x00 and SHOULD be ignored by the host. */
447 	return (int)opal_response_get_u64(resp,
448 					  resp->num - 4); /* We only need the first value in the status list. */
449 }
450 
451 static int
452 opal_parse_and_check_status(struct spdk_opal_dev *dev)
453 {
454 	int error;
455 
456 	error = opal_response_parse(dev->resp, IO_BUFFER_LENGTH, &dev->parsed_resp);
457 	if (error) {
458 		SPDK_ERRLOG("Couldn't parse response.\n");
459 		return error;
460 	}
461 	return opal_response_status(&dev->parsed_resp);
462 }
463 
464 static inline void
465 opal_clear_cmd(struct spdk_opal_dev *dev)
466 {
467 	dev->cmd_pos = sizeof(struct spdk_opal_header);
468 	memset(dev->cmd, 0, IO_BUFFER_LENGTH);
469 }
470 
471 static inline void
472 opal_set_comid(struct spdk_opal_dev *dev, uint16_t comid)
473 {
474 	struct spdk_opal_header *hdr = (struct spdk_opal_header *)dev->cmd;
475 
476 	hdr->com_packet.comid[0] = comid >> 8;
477 	hdr->com_packet.comid[1] = comid;
478 	hdr->com_packet.extended_comid[0] = 0;
479 	hdr->com_packet.extended_comid[1] = 0;
480 }
481 
482 static int
483 opal_next(struct spdk_opal_dev *dev)
484 {
485 	const struct spdk_opal_step *step;
486 	int state = 0, error = 0;
487 
488 	do {
489 		step = &dev->steps[state];
490 		if (!step->opal_fn) {
491 			if (state != 0) {
492 				break;
493 			} else {
494 				SPDK_ERRLOG("First step is NULL\n");
495 				return -1;
496 			}
497 		}
498 
499 		error = step->opal_fn(dev, step->data);
500 		if (error) {
501 			SPDK_ERRLOG("Error on step function: %d with error %d: %s\n",
502 				    state, error,
503 				    opal_error_to_human(error));
504 			if (state > 1) {
505 				opal_end_session_error(dev);
506 				return error;
507 			}
508 		}
509 		state++;
510 	} while (!error);
511 
512 	return error;
513 }
514 
515 static void
516 opal_check_tper(struct spdk_opal_dev *dev, const void *data)
517 {
518 	const struct spdk_d0_tper_features *tper = data;
519 	struct spdk_opal_info *opal_info = dev->opal_info;
520 
521 	opal_info->opal_ssc_dev = 1;
522 	opal_info->tper = 1;
523 	opal_info->tper_acknack = tper->acknack;
524 	opal_info->tper_async = tper->async;
525 	opal_info->tper_buffer_mgt = tper->buffer_management;
526 	opal_info->tper_comid_mgt = tper->comid_management;
527 	opal_info->tper_streaming = tper->streaming;
528 	opal_info->tper_sync = tper->sync;
529 }
530 
531 /*
532  * check single user mode
533  */
534 static bool
535 opal_check_sum(struct spdk_opal_dev *dev, const void *data)
536 {
537 	const struct spdk_d0_sum *sum = data;
538 	uint32_t num_locking_objects = from_be32(&sum->num_locking_objects);
539 	struct spdk_opal_info *opal_info = dev->opal_info;
540 
541 	if (num_locking_objects == 0) {
542 		SPDK_NOTICELOG("Need at least one locking object.\n");
543 		return false;
544 	}
545 
546 	opal_info->single_user_mode = 1;
547 	opal_info->single_user_locking_objects = num_locking_objects;
548 	opal_info->single_user_any = sum->any;
549 	opal_info->single_user_all = sum->all;
550 	opal_info->single_user_policy = sum->policy;
551 
552 	return true;
553 }
554 
555 static void
556 opal_check_lock(struct spdk_opal_dev *dev, const void *data)
557 {
558 	const struct spdk_d0_locking_features *lock = data;
559 	struct spdk_opal_info *opal_info = dev->opal_info;
560 
561 	opal_info->locking = 1;
562 	opal_info->locking_locked = lock->locked;
563 	opal_info->locking_locking_enabled = lock->locking_enabled;
564 	opal_info->locking_locking_supported = lock->locking_supported;
565 	opal_info->locking_mbr_done = lock->mbr_done;
566 	opal_info->locking_mbr_enabled = lock->mbr_enabled;
567 	opal_info->locking_media_encrypt = lock->media_encryption;
568 }
569 
570 static void
571 opal_check_geometry(struct spdk_opal_dev *dev, const void *data)
572 {
573 	const struct spdk_d0_geo_features *geo = data;
574 	struct spdk_opal_info *opal_info = dev->opal_info;
575 	uint64_t align = from_be64(&geo->alignment_granularity);
576 	uint64_t lowest_lba = from_be64(&geo->lowest_aligned_lba);
577 
578 	dev->align = align;
579 	dev->lowest_lba = lowest_lba;
580 
581 	opal_info->geometry = 1;
582 	opal_info->geometry_align = geo->align;
583 	opal_info->geometry_logical_block_size = from_be64(&geo->logical_block_size);
584 	opal_info->geometry_lowest_aligned_lba = lowest_lba;
585 	opal_info->geometry_alignment_granularity = align;
586 }
587 
588 static void
589 opal_check_datastore(struct spdk_opal_dev *dev, const void *data)
590 {
591 	const struct spdk_d0_datastore_features *datastore = data;
592 	struct spdk_opal_info *opal_info = dev->opal_info;
593 
594 	opal_info->datastore = 1;
595 	opal_info->datastore_max_tables = from_be16(&datastore->max_tables);
596 	opal_info->datastore_max_table_size = from_be32(&datastore->max_table_size);
597 	opal_info->datastore_alignment = from_be32(&datastore->alignment);
598 }
599 
600 static uint16_t
601 opal_get_comid_v100(struct spdk_opal_dev *dev, const void *data)
602 {
603 	const struct spdk_d0_opal_v100 *v100 = data;
604 	struct spdk_opal_info *opal_info = dev->opal_info;
605 	uint16_t base_comid = from_be16(&v100->base_comid);
606 
607 	opal_info->opal_v100 = 1;
608 	opal_info->opal_v100_base_comid = base_comid;
609 	opal_info->opal_v100_num_comid = from_be16(&v100->number_comids);
610 	opal_info->opal_v100_range_crossing = v100->range_crossing;
611 
612 	return base_comid;
613 }
614 
615 static uint16_t
616 opal_get_comid_v200(struct spdk_opal_dev *dev, const void *data)
617 {
618 	const struct spdk_d0_opal_v200 *v200 = data;
619 	struct spdk_opal_info *opal_info = dev->opal_info;
620 	uint16_t base_comid = from_be16(&v200->base_comid);
621 
622 	opal_info->opal_v200 = 1;
623 	opal_info->opal_v200_base_comid = base_comid;
624 	opal_info->opal_v200_num_comid = from_be16(&v200->num_comids);
625 	opal_info->opal_v200_range_crossing = v200->range_crossing;
626 	opal_info->opal_v200_num_admin = from_be16(&v200->num_locking_admin_auth);
627 	opal_info->opal_v200_num_user = from_be16(&v200->num_locking_user_auth);
628 
629 	opal_info->opal_v200_initial_pin = v200->initial_pin;
630 	opal_info->opal_v200_reverted_pin = v200->reverted_pin;
631 
632 	return base_comid;
633 }
634 
635 static int
636 opal_discovery0_end(struct spdk_opal_dev *dev)
637 {
638 	bool found_com_id = false, supported = false, single_user = false;
639 	const struct spdk_d0_header *hdr = (struct spdk_d0_header *)dev->resp;
640 	const uint8_t *epos = dev->resp, *cpos = dev->resp;
641 	uint16_t comid = 0;
642 	uint32_t hlen = from_be32(&(hdr->length));
643 
644 	if (hlen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
645 		SPDK_ERRLOG("Discovery length overflows buffer (%zu+%u)/%u\n",
646 			    sizeof(*hdr), hlen, IO_BUFFER_LENGTH);
647 		return -EFAULT;
648 	}
649 
650 	epos += hlen; /* end of buffer */
651 	cpos += sizeof(*hdr); /* current position on buffer */
652 
653 	while (cpos < epos) {
654 		const union spdk_discovery0_features *body =
655 				(const union spdk_discovery0_features *)cpos;
656 		uint16_t feature_code = from_be16(&(body->tper.feature_code));
657 
658 		switch (feature_code) {
659 		case FEATURECODE_TPER:
660 			opal_check_tper(dev, body);
661 			break;
662 		case FEATURECODE_SINGLEUSER:
663 			single_user = opal_check_sum(dev, body);
664 			break;
665 		case FEATURECODE_GEOMETRY:
666 			opal_check_geometry(dev, body);
667 			break;
668 		case FEATURECODE_LOCKING:
669 			opal_check_lock(dev, body);
670 			break;
671 		case FEATURECODE_DATASTORE:
672 			opal_check_datastore(dev, body);
673 			break;
674 		case FEATURECODE_OPALV100:
675 			comid = opal_get_comid_v100(dev, body);
676 			found_com_id = true;
677 			supported = true;
678 			break;
679 		case FEATURECODE_OPALV200:
680 			comid = opal_get_comid_v200(dev, body);
681 			found_com_id = true;
682 			supported = true;
683 			break;
684 		default:
685 			SPDK_NOTICELOG("Unknow feature code: %d\n", feature_code);
686 		}
687 		cpos += body->tper.length + 4;
688 	}
689 
690 	if (supported == false) {
691 		SPDK_ERRLOG("Opal Not Supported.\n");
692 		return SPDK_OPAL_NOT_SUPPORTED;
693 	}
694 
695 	if (single_user == false) {
696 		SPDK_NOTICELOG("Single User Mode Not Supported\n");
697 	}
698 
699 	if (found_com_id == false) {
700 		SPDK_ERRLOG("Could not find OPAL comid for device. Returning early\n");
701 		return -EINVAL;
702 	}
703 
704 	dev->comid = comid;
705 	return 0;
706 }
707 
708 static int
709 opal_discovery0(struct spdk_opal_dev *dev, void *data)
710 {
711 	int ret;
712 
713 	memset(dev->resp, 0, IO_BUFFER_LENGTH);
714 	dev->comid = LV0_DISCOVERY_COMID;
715 	ret = opal_recv_cmd(dev);
716 	if (ret) {
717 		return ret;
718 	}
719 
720 	return opal_discovery0_end(dev);
721 }
722 
723 static inline void
724 opal_setup_dev(struct spdk_opal_dev *dev,
725 	       const struct spdk_opal_step *steps)
726 {
727 	dev->steps = steps;
728 	dev->tsn = 0;
729 	dev->hsn = 0;
730 	dev->prev_data = NULL;
731 	dev->timeout = SPDK_OPAL_TPER_TIMEOUT;
732 }
733 
734 static int
735 opal_end_session_cb(struct spdk_opal_dev *dev)
736 {
737 	dev->hsn = 0;
738 	dev->tsn = 0;
739 	return opal_parse_and_check_status(dev);
740 }
741 
742 static int
743 opal_end_session(struct spdk_opal_dev *dev, void *data)
744 {
745 	int err = 0;
746 	bool eod = 0;
747 
748 	opal_clear_cmd(dev);
749 	opal_set_comid(dev, dev->comid);
750 	opal_add_token_u8(&err, dev, SPDK_OPAL_ENDOFSESSION);
751 
752 	if (err < 0) {
753 		return err;
754 	}
755 	return opal_finalize_and_send(dev, eod, opal_end_session_cb);
756 }
757 
758 static int
759 opal_end_session_error(struct spdk_opal_dev *dev)
760 {
761 	const struct spdk_opal_step error_end_session[] = {
762 		{ opal_end_session, },
763 		{ NULL, }
764 	};
765 	dev->steps = error_end_session;
766 	return opal_next(dev);
767 }
768 
769 static int
770 opal_check_support(struct spdk_opal_dev *dev)
771 {
772 	const struct spdk_opal_step steps[] = {
773 		{ opal_discovery0, },
774 		{ NULL, }
775 	};
776 	int ret;
777 
778 	opal_setup_dev(dev, steps);
779 	ret = opal_next(dev);
780 	if (ret == 0) {
781 		dev->supported = true;
782 	} else {
783 		dev->supported = false;
784 	}
785 
786 	return ret;
787 }
788 
789 void
790 spdk_opal_close(struct spdk_opal_dev *dev)
791 {
792 	free(dev->opal_info);
793 	free(dev);
794 }
795 
796 struct spdk_opal_dev *
797 spdk_opal_init_dev(void *dev_handler)
798 {
799 	struct spdk_opal_dev *dev;
800 	struct spdk_opal_info *info;
801 
802 	dev = calloc(1, sizeof(*dev));
803 	if (!dev) {
804 		SPDK_ERRLOG("Memory allocation failed\n");
805 		return NULL;
806 	}
807 
808 	dev->dev_handler = dev_handler;
809 
810 	info = calloc(1, sizeof(struct spdk_opal_info));
811 	if (info == NULL) {
812 		free(dev);
813 		SPDK_ERRLOG("Memory allocation failed\n");
814 		return NULL;
815 	}
816 
817 	dev->opal_info = info;
818 	if (opal_check_support(dev) != 0) {
819 		SPDK_INFOLOG(SPDK_LOG_OPAL, "Opal is not supported on this device\n");
820 		dev->supported = false;
821 	}
822 	return dev;
823 }
824 
825 void
826 spdk_opal_scan(struct spdk_opal_dev *dev)
827 {
828 	int ret;
829 
830 	ret = opal_check_support(dev);
831 	if (ret) {
832 		SPDK_ERRLOG("check opal support failed: %d\n", ret);
833 		spdk_opal_close(dev);
834 		return;
835 	}
836 }
837 
838 struct spdk_opal_info *
839 spdk_opal_get_info(struct spdk_opal_dev *dev)
840 {
841 	return dev->opal_info;
842 }
843 
844 bool
845 spdk_opal_supported(struct spdk_opal_dev *dev)
846 {
847 	return dev->supported;
848 }
849 
850 /* Log component for opal submodule */
851 SPDK_LOG_REGISTER_COMPONENT("opal", SPDK_LOG_OPAL)
852