diff --git a/CHANGELOG.md b/CHANGELOG.md index edb988ec3..e04060070 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,8 +50,7 @@ Nvme Opal library spdk_opal_cmd deprecated. Adding seperate command APIs. NVMe Opal library add support for activating locking SP which will make the transaction from "Manufactured-Inactive" state to "Manufactured" state. Upon successfully invoking of this method, lock and unlock features will be enabled. -NVMe Opal library add support for locking/unlocking range. - +NVMe Opal library add support for locking/unlocking range and list locking range info. Added spdk_nvme_ctrlr_io_cmd_raw_no_payload_build() allowing a caller to pass a completely formed command to an NVMe submission queue (buffer addresses and all). diff --git a/examples/nvme/nvme_manage/nvme_manage.c b/examples/nvme/nvme_manage/nvme_manage.c index 6c535bfd3..4c7201a63 100644 --- a/examples/nvme/nvme_manage/nvme_manage.c +++ b/examples/nvme/nvme_manage/nvme_manage.c @@ -939,7 +939,8 @@ opal_usage(void) printf("\n"); printf("\t[1: scan device]\n"); printf("\t[2: init - take ownership and activate locking]\n"); - printf("\t[3: lock/unlock the range]\n"); + printf("\t[3: setup locking range and enable locking]\n"); + printf("\t[4: list locking ranges]\n"); printf("\t[9: revert tper]\n"); printf("\t[0: quit]\n"); } @@ -1021,12 +1022,16 @@ opal_locking_usage(void) } static void -opal_lock_range(struct dev *iter) +opal_setup_lockingrange(struct dev *iter) { char passwd[MAX_PASSWORD_SIZE] = {0}; char *passwd_p; int ret; int ch; + uint64_t range_start; + uint64_t range_length; + int locking_range_flag; + struct spdk_opal_locking_range_info *info; int state; enum spdk_opal_lock_state state_flag; @@ -1036,7 +1041,7 @@ opal_lock_range(struct dev *iter) return; } if (spdk_opal_supported(iter->opal_dev)) { - printf("Please input the password for locking the range:\n"); + printf("Please input the password for setting up locking range:\n"); while ((ch = getchar()) != '\n' && ch != EOF); passwd_p = getpass(passwd); if (passwd_p) { @@ -1047,20 +1052,25 @@ opal_lock_range(struct dev *iter) return; } - ret = spdk_opal_cmd_setup_locking_range(iter->opal_dev, - OPAL_ADMIN1, OPAL_LOCKING_RANGE_GLOBAL, 0, 0, passwd_p); /* just put here for testing */ - if (ret) { - printf("Setup locking range failure: %d\n", ret); - return; + printf("Specify locking range id:\n"); + if (!scanf("%d", &locking_range_flag)) { + printf("Invalid locking range id\n"); + } + + printf("range length:\n"); + if (!scanf("%ld", &range_length)) { + printf("Invalid range length\n"); + } + + printf("range start:\n"); + if (!scanf("%ld", &range_start)) { + printf("Invalid range start address\n"); } opal_locking_usage(); - ret = scanf("%d", &state); - if (ret != 1) { - printf("Invalid input\n"); - return; + if (!scanf("%d", &state)) { + printf("Invalid option\n"); } - switch (state) { case 1: state_flag = OPAL_RWLOCK; @@ -1076,13 +1086,36 @@ opal_lock_range(struct dev *iter) return; } - ret = spdk_opal_cmd_lock_unlock(iter->opal_dev, OPAL_ADMIN1, state_flag, - OPAL_LOCKING_RANGE_GLOBAL, passwd_p); + ret = spdk_opal_cmd_setup_locking_range(iter->opal_dev, + OPAL_ADMIN1, locking_range_flag, range_start, range_length, passwd_p); if (ret) { - printf("lock range failure: %d\n", ret); + printf("Setup locking range failure: %d\n", ret); return; } + ret = spdk_opal_cmd_lock_unlock(iter->opal_dev, OPAL_ADMIN1, state_flag, + locking_range_flag, passwd_p); + if (ret) { + printf("Unlock range failure: %d\n", ret); + return; + } + + ret = spdk_opal_cmd_get_locking_range_info(iter->opal_dev, + passwd_p, locking_range_flag); + if (ret) { + printf("Get locking range info failure: %d\n", ret); + return; + } + info = spdk_opal_get_locking_range_info(iter->opal_dev, locking_range_flag); + + printf("locking range ID: %d\n", info->locking_range_id); + printf("range start: %ld\n", info->range_start); + printf("range length: %ld\n", info->range_length); + printf("read lock enabled: %d\n", info->read_lock_enabled); + printf("write lock enabled: %d\n", info->write_lock_enabled); + printf("read locked: %d\n", info->read_locked); + printf("write locked: %d\n", info->write_locked); + printf("...\n...\nOpal setup locking range success\n"); } else { printf("Input password invalid. Opal setup locking range failure\n"); @@ -1095,6 +1128,69 @@ opal_lock_range(struct dev *iter) } } +static void +opal_list_locking_ranges(struct dev *iter) +{ + char passwd[MAX_PASSWORD_SIZE] = {0}; + char *passwd_p; + int ret; + int ch; + int max_ranges; + int i; + struct spdk_opal_locking_range_info *info; + + if (spdk_nvme_ctrlr_get_flags(iter->ctrlr) & SPDK_NVME_CTRLR_SECURITY_SEND_RECV_SUPPORTED) { + iter->opal_dev = spdk_opal_init_dev(iter->ctrlr); + if (iter->opal_dev == NULL) { + return; + } + if (spdk_opal_supported(iter->opal_dev)) { + printf("Please input password:\n"); + while ((ch = getchar()) != '\n' && ch != EOF); + passwd_p = getpass(passwd); + if (passwd_p) { + ret = spdk_opal_cmd_get_max_ranges(iter->opal_dev, passwd_p); + if (ret) { + printf("get max ranges failure: %d\n", ret); + return; + } + + max_ranges = spdk_opal_get_max_locking_ranges(iter->opal_dev); + for (i = 0; i < max_ranges; i++) { + ret = spdk_opal_cmd_get_locking_range_info(iter->opal_dev, + passwd_p, i); + if (ret) { + printf("Get locking range info failure: %d\n", ret); + return; + } + info = spdk_opal_get_locking_range_info(iter->opal_dev, i); + if (info == NULL) { + continue; + } + + printf("===============================================\n"); + printf("locking range ID: %d\t", info->locking_range_id); + if (i == 0) { printf("(Global Range)"); } + printf("\n===============================================\n"); + printf("range start: %ld\t", info->range_start); + printf("range length: %ld\n", info->range_length); + printf("read lock enabled: %d\t", info->read_lock_enabled); + printf("write lock enabled: %d\t", info->write_lock_enabled); + printf("read locked: %d\t", info->read_locked); + printf("write locked: %d\n", info->write_locked); + printf("\n"); + } + } else { + printf("Input password invalid. List locking ranges failure\n"); + } + } + spdk_opal_close(iter->opal_dev); + } else { + printf("%04x:%02x:%02x.%02x: NVMe Security Support/Receive Not supported.\nOpal Not Supported\n\n\n", + iter->pci_addr.domain, iter->pci_addr.bus, iter->pci_addr.dev, iter->pci_addr.func); + } +} + static void opal_revert_tper(struct dev *iter) { @@ -1165,7 +1261,10 @@ test_opal(void) opal_init(ctrlr); /* Take ownership, Activate Locking SP */ break; case 3: - opal_lock_range(ctrlr); + opal_setup_lockingrange(ctrlr); + break; + case 4: + opal_list_locking_ranges(ctrlr); break; case 9: opal_revert_tper(ctrlr); diff --git a/include/spdk/opal.h b/include/spdk/opal.h index 849ed6409..b3fb4d0ae 100644 --- a/include/spdk/opal.h +++ b/include/spdk/opal.h @@ -151,6 +151,17 @@ enum spdk_opal_locking_range { OPAL_LOCKING_RANGE_10, }; +struct spdk_opal_locking_range_info { + uint8_t locking_range_id; + uint8_t _padding[7]; + uint64_t range_start; + uint64_t range_length; + bool read_lock_enabled; + bool write_lock_enabled; + bool read_locked; + bool write_locked; +}; + struct spdk_opal_dev; struct spdk_opal_dev *spdk_opal_init_dev(void *dev_handler); @@ -171,4 +182,11 @@ int spdk_opal_cmd_setup_locking_range(struct spdk_opal_dev *dev, enum spdk_opal_ enum spdk_opal_locking_range locking_range_id, uint64_t range_start, uint64_t range_length, const char *passwd); +int spdk_opal_cmd_get_max_ranges(struct spdk_opal_dev *dev, const char *passwd); +int spdk_opal_cmd_get_locking_range_info(struct spdk_opal_dev *dev, const char *passwd, + enum spdk_opal_locking_range locking_range_id); +struct spdk_opal_locking_range_info *spdk_opal_get_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 01c3a8ad5..cfd54db7c 100644 --- a/lib/nvme/nvme_opal.c +++ b/lib/nvme/nvme_opal.c @@ -287,7 +287,7 @@ opal_finalize_and_send(struct spdk_opal_dev *dev, bool eod, spdk_opal_cb cb, voi return ret; } - return opal_send_recv(dev, cb, NULL); + return opal_send_recv(dev, cb, data); } static size_t @@ -523,6 +523,28 @@ opal_response_get_u64(const struct spdk_opal_resp_parsed *resp, int index) return resp->resp_tokens[index].stored.unsigned_num; } +static uint16_t +opal_response_get_u16(const struct spdk_opal_resp_parsed *resp, int index) +{ + uint64_t i = opal_response_get_u64(resp, index); + if (i > 0xffffull) { + SPDK_ERRLOG("parse reponse u16 failed. Overflow\n"); + return 0; + } + return (uint16_t) i; +} + +static uint8_t +opal_response_get_u8(const struct spdk_opal_resp_parsed *resp, int index) +{ + uint64_t i = opal_response_get_u64(resp, index); + if (i > 0xffull) { + SPDK_ERRLOG("parse reponse u8 failed. Overflow\n"); + return 0; + } + return (uint8_t) i; +} + static size_t opal_response_get_string(const struct spdk_opal_resp_parsed *resp, int n, const char **store) @@ -1457,6 +1479,133 @@ opal_setup_locking_range(struct spdk_opal_dev *dev, return opal_finalize_and_send(dev, 1, opal_parse_and_check_status, NULL); } +static int +opal_get_max_ranges_cb(struct spdk_opal_dev *dev, void *data) +{ + uint8_t max_ranges; + int error = 0; + + error = opal_parse_and_check_status(dev, NULL); + if (error) { + return error; + } + + max_ranges = opal_response_get_u16(&dev->parsed_resp, 4); /* "MaxRanges" is token 4 of response */ + dev->max_ranges = max_ranges; + return 0; +} + +static int +opal_get_max_ranges(struct spdk_opal_dev *dev) +{ + int err = 0; + + opal_clear_cmd(dev); + opal_set_comid(dev, dev->comid); + + opal_add_token_u8(&err, dev, SPDK_OPAL_CALL); + opal_add_token_bytestring(&err, dev, spdk_opal_uid[UID_LOCKING_INFO_TABLE], + OPAL_UID_LENGTH); + opal_add_token_bytestring(&err, dev, spdk_opal_method[GET_METHOD], OPAL_UID_LENGTH); + + opal_add_tokens(&err, dev, 12, SPDK_OPAL_STARTLIST, + SPDK_OPAL_STARTLIST, + SPDK_OPAL_STARTNAME, + SPDK_OPAL_STARTCOLUMN, + SPDK_OPAL_MAXRANGES, + SPDK_OPAL_ENDNAME, + SPDK_OPAL_STARTNAME, + SPDK_OPAL_ENDCOLUMN, + SPDK_OPAL_MAXRANGES, + SPDK_OPAL_ENDNAME, + SPDK_OPAL_ENDLIST, + SPDK_OPAL_ENDLIST); + + if (err) { + SPDK_ERRLOG("Error Building GET Lifecycle Status command\n"); + return err; + } + + return opal_finalize_and_send(dev, 1, opal_get_max_ranges_cb, NULL); +} + +static int +opal_get_locking_range_info_cb(struct spdk_opal_dev *dev, void *data) +{ + int error = 0; + uint8_t id = *(uint8_t *)data; + + error = opal_parse_and_check_status(dev, NULL); + if (error) { + return error; + } + + if (id > dev->max_ranges) { + SPDK_ERRLOG("Locking range ID not valid\n"); + return -EINVAL; + } + + dev->locking_range_info[id]->range_start = opal_response_get_u64(&dev->parsed_resp, 4); + dev->locking_range_info[id]->range_length = opal_response_get_u64(&dev->parsed_resp, 8); + dev->locking_range_info[id]->read_lock_enabled = opal_response_get_u8(&dev->parsed_resp, 12); + dev->locking_range_info[id]->write_lock_enabled = opal_response_get_u8(&dev->parsed_resp, 16); + dev->locking_range_info[id]->read_locked = opal_response_get_u8(&dev->parsed_resp, 20); + dev->locking_range_info[id]->write_locked = opal_response_get_u8(&dev->parsed_resp, 24); + + return 0; +} + +static int +opal_get_locking_range_info(struct spdk_opal_dev *dev, + enum spdk_opal_locking_range locking_range_id) +{ + int err = 0; + uint8_t uid_locking_range[OPAL_UID_LENGTH]; + struct spdk_opal_locking_range_info *info; + + err = opal_build_locking_range(uid_locking_range, OPAL_UID_LENGTH, locking_range_id); + if (err) { + return err; + } + + info = calloc(1, sizeof(struct spdk_opal_locking_range_info)); + if (info == NULL) { + SPDK_ERRLOG("Memory allocation failed for spdk_opal_locking_range_info\n"); + return -ENOMEM; + } + + info->locking_range_id = locking_range_id; + dev->locking_range_info[locking_range_id] = info; + + opal_clear_cmd(dev); + opal_set_comid(dev, dev->comid); + + opal_add_token_u8(&err, dev, SPDK_OPAL_CALL); + opal_add_token_bytestring(&err, dev, uid_locking_range, OPAL_UID_LENGTH); + opal_add_token_bytestring(&err, dev, spdk_opal_method[GET_METHOD], OPAL_UID_LENGTH); + + + opal_add_tokens(&err, dev, 12, SPDK_OPAL_STARTLIST, + SPDK_OPAL_STARTLIST, + SPDK_OPAL_STARTNAME, + SPDK_OPAL_STARTCOLUMN, + SPDK_OPAL_RANGESTART, + SPDK_OPAL_ENDNAME, + SPDK_OPAL_STARTNAME, + SPDK_OPAL_ENDCOLUMN, + SPDK_OPAL_WRITELOCKED, + SPDK_OPAL_ENDNAME, + SPDK_OPAL_ENDLIST, + SPDK_OPAL_ENDLIST); + + if (err) { + SPDK_ERRLOG("Error Building get locking range info command\n"); + return err; + } + + return opal_finalize_and_send(dev, 1, opal_get_locking_range_info_cb, &locking_range_id); +} + static int opal_set_sid_cpin_pin(struct spdk_opal_dev *dev, void *data) { @@ -1799,6 +1948,95 @@ end: return ret; } +int +spdk_opal_cmd_get_max_ranges(struct spdk_opal_dev *dev, const char *passwd) +{ + struct spdk_opal_key opal_key; + struct opal_common_session session; + int ret; + + if (!dev || dev->supported == false) { + return -ENODEV; + } + + ret = opal_init_key(&opal_key, passwd, OPAL_LOCKING_RANGE_GLOBAL); + if (ret != 0) { + return ret; + } + + memset(&session, 0, sizeof(struct opal_common_session)); + session.opal_key = &opal_key; + session.who = OPAL_ADMIN1; + + pthread_mutex_lock(&dev->mutex_lock); + ret = opal_start_auth_session(dev, &session); + if (ret) { + SPDK_ERRLOG("start authenticate session error %d: %s\n", ret, opal_error_to_human(ret)); + pthread_mutex_unlock(&dev->mutex_lock); + return ret; + } + + ret = opal_get_max_ranges(dev); + if (ret) { + SPDK_ERRLOG("get max ranges error %d: %s\n", ret, opal_error_to_human(ret)); + goto end; + } + +end: + ret += opal_end_session(dev); + if (ret) { + SPDK_ERRLOG("end session error %d: %s\n", ret, opal_error_to_human(ret)); + } + + pthread_mutex_unlock(&dev->mutex_lock); + return ret; +} + +int +spdk_opal_cmd_get_locking_range_info(struct spdk_opal_dev *dev, const char *passwd, + enum spdk_opal_locking_range locking_range_id) +{ + struct spdk_opal_key opal_key; + struct opal_common_session session; + int ret; + + if (!dev || dev->supported == false) { + return -ENODEV; + } + + ret = opal_init_key(&opal_key, passwd, OPAL_LOCKING_RANGE_GLOBAL); + if (ret != 0) { + return ret; + } + + memset(&session, 0, sizeof(struct opal_common_session)); + session.opal_key = &opal_key; + session.who = OPAL_ADMIN1; + + pthread_mutex_lock(&dev->mutex_lock); + ret = opal_start_auth_session(dev, &session); + if (ret) { + SPDK_ERRLOG("start authenticate session error %d: %s\n", ret, opal_error_to_human(ret)); + pthread_mutex_unlock(&dev->mutex_lock); + return ret; + } + + ret = opal_get_locking_range_info(dev, locking_range_id); + if (ret) { + SPDK_ERRLOG("get locking range info error %d: %s\n", ret, opal_error_to_human(ret)); + goto end; + } + +end: + ret += opal_end_session(dev); + if (ret) { + SPDK_ERRLOG("end session error %d: %s\n", ret, opal_error_to_human(ret)); + } + + pthread_mutex_unlock(&dev->mutex_lock); + return ret; +} + struct spdk_opal_info * spdk_opal_get_info(struct spdk_opal_dev *dev) { @@ -1811,5 +2049,17 @@ spdk_opal_supported(struct spdk_opal_dev *dev) return dev->supported; } +struct spdk_opal_locking_range_info * +spdk_opal_get_locking_range_info(struct spdk_opal_dev *dev, enum spdk_opal_locking_range id) +{ + return dev->locking_range_info[id]; +} + +uint8_t +spdk_opal_get_max_locking_ranges(struct spdk_opal_dev *dev) +{ + return dev->max_ranges; +} + /* Log component for opal submodule */ SPDK_LOG_REGISTER_COMPONENT("opal", SPDK_LOG_OPAL) diff --git a/lib/nvme/nvme_opal_internal.h b/lib/nvme/nvme_opal_internal.h index 8e1dfa5f3..66720bc0c 100644 --- a/lib/nvme/nvme_opal_internal.h +++ b/lib/nvme/nvme_opal_internal.h @@ -299,6 +299,8 @@ struct spdk_opal_dev { struct spdk_opal_info *opal_info; uint64_t timeout; /* seconds */ + uint8_t max_ranges; /* max locking range number */ + 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 */ };