Commit ac494980 authored by Chunyang Hui's avatar Chunyang Hui Committed by Jim Harris
Browse files

Opal: Add async function for revert TPer



Some nvme drives might take 6-7mins for
this operation. Thus, introduce async function
to avoid waiting.

Change-Id: Id48478aec653d3fb75a3c5ce75d4997284ed016c
Signed-off-by: default avatarChunyang Hui <chunyang.hui@intel.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/468916


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarPaul Luse <paul.e.luse@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
parent 0a18f228
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
@@ -164,6 +164,8 @@ struct spdk_opal_locking_range_info {

struct spdk_opal_dev;

typedef void (*spdk_opal_revert_cb)(struct spdk_opal_dev *dev, void *ctx, int rc);

struct spdk_opal_dev *spdk_opal_init_dev(void *dev_handler);

void spdk_opal_close(struct spdk_opal_dev *dev);
@@ -173,7 +175,32 @@ bool spdk_opal_supported(struct spdk_opal_dev *dev);

int spdk_opal_cmd_scan(struct spdk_opal_dev *dev);
int spdk_opal_cmd_take_ownership(struct spdk_opal_dev *dev, char *new_passwd);

/**
 * Users should periodically call spdk_opal_revert_poll to check if the response is received.
 * Once a final result is received, no matter success or failure, dev->revert_cb_fn will be called.
 * Error code is put to dev->revert_cb_fn.
 *
 * Return: -EAGAIN for no result yet. 0 for final result received.
 */
int spdk_opal_revert_poll(struct spdk_opal_dev *dev);

/**
 * asynchronous function: Just send cmd and return.
 *
 * Users should periodically call spdk_opal_revert_poll to check if the response is received.
 * Because usually revert TPer operation will take a while.
 */
int spdk_opal_cmd_revert_tper_async(struct spdk_opal_dev *dev, const char *passwd,
				    spdk_opal_revert_cb cb_fn, void *cb_ctx);

/**
 * synchronous function: send and then receive.
 *
 * Wait until response is received.
 */
int spdk_opal_cmd_revert_tper(struct spdk_opal_dev *dev, const char *passwd);

int spdk_opal_cmd_activate_locking_sp(struct spdk_opal_dev *dev, const char *passwd);
int spdk_opal_cmd_lock_unlock(struct spdk_opal_dev *dev, enum spdk_opal_user user,
			      enum spdk_opal_lock_state flag, enum spdk_opal_locking_range locking_range,
@@ -198,6 +225,8 @@ int spdk_opal_cmd_erase_locking_range(struct spdk_opal_dev *dev, enum spdk_opal_

struct spdk_opal_locking_range_info *spdk_opal_get_locking_range_info(struct spdk_opal_dev *dev,
		enum spdk_opal_locking_range id);
void spdk_opal_free_locking_range_info(struct spdk_opal_dev *dev, enum spdk_opal_locking_range id);

uint8_t spdk_opal_get_max_locking_ranges(struct spdk_opal_dev *dev);

#endif
+121 −5
Original line number Diff line number Diff line
@@ -37,6 +37,10 @@

#include "nvme_opal_internal.h"

typedef int (*spdk_opal_cb)(struct spdk_opal_dev *dev, void *ctx);

static int opal_parse_and_check_status(struct spdk_opal_dev *dev, void *data);

static const char *
opal_error_to_human(int error)
{
@@ -96,7 +100,7 @@ opal_recv_cmd(struct spdk_opal_dev *dev)
}

static int
opal_send_recv(struct spdk_opal_dev *dev, spdk_opal_cb *cb, void *data)
opal_send_recv(struct spdk_opal_dev *dev, spdk_opal_cb cb, void *data)
{
	int ret;

@@ -276,6 +280,11 @@ opal_cmd_finalize(struct spdk_opal_dev *dev, uint32_t hsn, uint32_t tsn, bool eo
	return 0;
}

/**
 * synchronous function: send and then receive.
 *
 * Wait until response is received. And then call the callback functions.
 */
static int
opal_finalize_and_send(struct spdk_opal_dev *dev, bool eod, spdk_opal_cb cb, void *data)
{
@@ -972,7 +981,7 @@ spdk_opal_close(struct spdk_opal_dev *dev)
	pthread_mutex_destroy(&dev->mutex_lock);
	if (dev->max_ranges > 0) {
		for (int i = 0; i < dev->max_ranges; i++) {
			free(dev->locking_range_info[i]);
			spdk_opal_free_locking_range_info(dev, i);
		}
	}
	free(dev->opal_info);
@@ -1920,10 +1929,9 @@ opal_revert_tper(struct spdk_opal_dev *dev)
	opal_add_token_u8(&err, dev, SPDK_OPAL_ENDLIST);
	if (err) {
		SPDK_ERRLOG("Error building REVERT TPER command.\n");
		return err;
	}

	return opal_finalize_and_send(dev, 1, opal_parse_and_check_status, NULL);
	return err;
}

static int
@@ -2044,7 +2052,95 @@ spdk_opal_cmd_revert_tper(struct spdk_opal_dev *dev, const char *passwd)
	}

	ret = opal_init_key(&opal_key, passwd, OPAL_LOCKING_RANGE_GLOBAL);
	if (ret != 0) {
	if (ret) {
		SPDK_ERRLOG("Init key failed\n");
		return ret;
	}

	pthread_mutex_lock(&dev->mutex_lock);
	opal_setup_dev(dev);

	ret = opal_start_adminsp_session(dev, &opal_key);
	if (ret) {
		opal_end_session(dev);
		SPDK_ERRLOG("Error on starting admin SP session with error %d: %s\n", ret,
			    opal_error_to_human(ret));
		goto end;
	}

	ret = opal_revert_tper(dev);
	if (ret) {
		opal_end_session(dev);
		SPDK_ERRLOG("Error on reverting TPer with error %d: %s\n", ret,
			    opal_error_to_human(ret));
		goto end;
	}

	ret = opal_finalize_and_send(dev, 1, opal_parse_and_check_status, NULL);
	if (ret) {
		opal_end_session(dev);
		SPDK_ERRLOG("Error on reverting TPer with error %d: %s\n", ret,
			    opal_error_to_human(ret));
	}

	/* Controller will terminate session. No "end session" here needed. */

end:
	pthread_mutex_unlock(&dev->mutex_lock);
	return ret;
}

int
spdk_opal_revert_poll(struct spdk_opal_dev *dev)
{
	void *response = dev->resp;
	struct spdk_opal_header *header = response;
	int ret;

	assert(dev->revert_cb_fn);

	ret = spdk_nvme_ctrlr_security_receive(dev->dev_handler, SPDK_SCSI_SECP_TCG, dev->comid,
					       0, dev->resp, IO_BUFFER_LENGTH);
	if (ret) {
		SPDK_ERRLOG("Security Receive Error on dev = %p\n", dev);
		dev->revert_cb_fn(dev, dev->ctx, ret);
		return 0;
	}

	if (header->com_packet.outstanding_data == 0 &&
	    header->com_packet.min_transfer == 0) {
		ret = opal_parse_and_check_status(dev, NULL);
		dev->revert_cb_fn(dev, dev->ctx, ret);
		return 0;
	} else {
		memset(response, 0, IO_BUFFER_LENGTH);
	}

	return -EAGAIN;
}

int
spdk_opal_cmd_revert_tper_async(struct spdk_opal_dev *dev, const char *passwd,
				spdk_opal_revert_cb cb_fn, void *cb_ctx)
{
	int ret;
	struct spdk_opal_key opal_key;

	if (!dev || dev->supported == false) {
		return -ENODEV;
	}

	if (cb_fn == NULL) {
		SPDK_ERRLOG("No revert callback function specified.\n");
		return -EFAULT;
	}

	dev->revert_cb_fn = cb_fn;
	dev->ctx = cb_ctx;

	ret = opal_init_key(&opal_key, passwd, OPAL_LOCKING_RANGE_GLOBAL);
	if (ret) {
		SPDK_ERRLOG("Init key failed\n");
		return ret;
	}

@@ -2067,6 +2163,17 @@ spdk_opal_cmd_revert_tper(struct spdk_opal_dev *dev, const char *passwd)
		goto end;
	}

	ret = opal_cmd_finalize(dev, dev->hsn, dev->tsn, true);    /* true: end of data */
	if (ret) {
		SPDK_ERRLOG("Error finalizing command buffer: %d\n", ret);
		goto end;
	}

	ret = opal_send_cmd(dev);
	if (ret) {
		SPDK_ERRLOG("Error sending opal command: %d\n", ret);
	}

	/* Controller will terminate session. No "end session" here needed. */

end:
@@ -2521,6 +2628,15 @@ spdk_opal_get_locking_range_info(struct spdk_opal_dev *dev, enum spdk_opal_locki
	return dev->locking_range_info[id];
}

void
spdk_opal_free_locking_range_info(struct spdk_opal_dev *dev, enum spdk_opal_locking_range id)
{
	struct spdk_opal_locking_range_info *info = dev->locking_range_info[id];

	free(info);
	dev->locking_range_info[id] = NULL;
}

uint8_t
spdk_opal_get_max_locking_ranges(struct spdk_opal_dev *dev)
{
+2 −2
Original line number Diff line number Diff line
@@ -52,8 +52,6 @@

#define SPDK_DTAERROR_NO_METHOD_STATUS	0x89

typedef int (spdk_opal_cb)(struct spdk_opal_dev *dev, void *data);

enum opal_token_type {
	OPAL_DTA_TOKENID_BYTESTRING	= 0xE0,
	OPAL_DTA_TOKENID_SINT		= 0xE1,
@@ -303,6 +301,8 @@ struct spdk_opal_dev {
	struct spdk_opal_locking_range_info *locking_range_info[OPAL_MAX_LRS];

	pthread_mutex_t mutex_lock; /* some structs are accessed by current thread only */
	spdk_opal_revert_cb revert_cb_fn;
	void *ctx;  /* user context data */
};

#endif