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: Chunyang Hui <chunyang.hui@intel.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/468916
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Paul Luse <paul.e.luse@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
This commit is contained in:
Chunyang Hui 2019-09-20 22:16:12 +08:00 committed by Jim Harris
parent 0a18f228c3
commit ac4949807b
3 changed files with 152 additions and 7 deletions

View File

@ -164,6 +164,8 @@ struct spdk_opal_locking_range_info {
struct spdk_opal_dev; 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); struct spdk_opal_dev *spdk_opal_init_dev(void *dev_handler);
void spdk_opal_close(struct spdk_opal_dev *dev); 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_scan(struct spdk_opal_dev *dev);
int spdk_opal_cmd_take_ownership(struct spdk_opal_dev *dev, char *new_passwd); 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_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_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, 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, 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, struct spdk_opal_locking_range_info *spdk_opal_get_locking_range_info(struct spdk_opal_dev *dev,
enum spdk_opal_locking_range id); 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); uint8_t spdk_opal_get_max_locking_ranges(struct spdk_opal_dev *dev);
#endif #endif

View File

@ -37,6 +37,10 @@
#include "nvme_opal_internal.h" #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 * static const char *
opal_error_to_human(int error) opal_error_to_human(int error)
{ {
@ -96,7 +100,7 @@ opal_recv_cmd(struct spdk_opal_dev *dev)
} }
static int 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; int ret;
@ -276,6 +280,11 @@ opal_cmd_finalize(struct spdk_opal_dev *dev, uint32_t hsn, uint32_t tsn, bool eo
return 0; return 0;
} }
/**
* synchronous function: send and then receive.
*
* Wait until response is received. And then call the callback functions.
*/
static int static int
opal_finalize_and_send(struct spdk_opal_dev *dev, bool eod, spdk_opal_cb cb, void *data) 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); pthread_mutex_destroy(&dev->mutex_lock);
if (dev->max_ranges > 0) { if (dev->max_ranges > 0) {
for (int i = 0; i < dev->max_ranges; i++) { 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); 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); opal_add_token_u8(&err, dev, SPDK_OPAL_ENDLIST);
if (err) { if (err) {
SPDK_ERRLOG("Error building REVERT TPER command.\n"); 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 static int
@ -2044,7 +2052,8 @@ spdk_opal_cmd_revert_tper(struct spdk_opal_dev *dev, const char *passwd)
} }
ret = opal_init_key(&opal_key, passwd, OPAL_LOCKING_RANGE_GLOBAL); ret = opal_init_key(&opal_key, passwd, OPAL_LOCKING_RANGE_GLOBAL);
if (ret != 0) { if (ret) {
SPDK_ERRLOG("Init key failed\n");
return ret; return ret;
} }
@ -2067,6 +2076,104 @@ spdk_opal_cmd_revert_tper(struct spdk_opal_dev *dev, const char *passwd)
goto end; 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;
}
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_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. */ /* Controller will terminate session. No "end session" here needed. */
end: 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]; 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 uint8_t
spdk_opal_get_max_locking_ranges(struct spdk_opal_dev *dev) spdk_opal_get_max_locking_ranges(struct spdk_opal_dev *dev)
{ {

View File

@ -52,8 +52,6 @@
#define SPDK_DTAERROR_NO_METHOD_STATUS 0x89 #define SPDK_DTAERROR_NO_METHOD_STATUS 0x89
typedef int (spdk_opal_cb)(struct spdk_opal_dev *dev, void *data);
enum opal_token_type { enum opal_token_type {
OPAL_DTA_TOKENID_BYTESTRING = 0xE0, OPAL_DTA_TOKENID_BYTESTRING = 0xE0,
OPAL_DTA_TOKENID_SINT = 0xE1, 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]; 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 */ 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 #endif