diff --git a/include/spdk/opal.h b/include/spdk/opal.h index 5f16fc87b..e0e59a19b 100644 --- a/include/spdk/opal.h +++ b/include/spdk/opal.h @@ -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 diff --git a/lib/nvme/nvme_opal.c b/lib/nvme/nvme_opal.c index 7118a8e84..3d1503cf9 100644 --- a/lib/nvme/nvme_opal.c +++ b/lib/nvme/nvme_opal.c @@ -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,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); - if (ret != 0) { + if (ret) { + SPDK_ERRLOG("Init key failed\n"); return ret; } @@ -2067,6 +2076,104 @@ spdk_opal_cmd_revert_tper(struct spdk_opal_dev *dev, const char *passwd) 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. */ 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) { diff --git a/lib/nvme/nvme_opal_internal.h b/lib/nvme/nvme_opal_internal.h index b0e87580c..d03b96d67 100644 --- a/lib/nvme/nvme_opal_internal.h +++ b/lib/nvme/nvme_opal_internal.h @@ -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