Loading examples/nvme/nvme_manage/nvme_manage.c +132 −1 Original line number Diff line number Diff line Loading @@ -139,7 +139,8 @@ static void usage(void) printf("\t[3: delete namespace]\n"); printf("\t[4: attach namespace to controller]\n"); printf("\t[5: detach namespace from controller]\n"); printf("\t[6: quit]\n"); printf("\t[6: format namespace or controller]\n"); printf("\t[7: quit]\n"); } static void Loading Loading @@ -198,6 +199,16 @@ display_controller(struct dev *dev, int model) printf("============================\n"); printf("Namespace Manage And Attach: %s\n", cdata->oacs.ns_manage ? "Supported" : "Not Supported"); printf("Namespace Format: %s\n", cdata->oacs.format ? "Supported" : "Not Supported"); printf("\n"); printf("NVM Command Set Attributes\n"); printf("============================\n"); if (cdata->fna.format_all_ns) { printf("Namespace format operation applies to all namespaces\n"); } else { printf("Namespace format operation applies to per namespace\n"); } printf("\n"); printf("Namespace Attributes\n"); printf("============================\n"); Loading Loading @@ -340,6 +351,24 @@ ns_manage_delete(struct dev *device, int ns_id) } } static void nvme_manage_format(struct dev *device, int ns_id, int ses, int pi, int pil, int ms, int lbaf) { int ret = 0; struct spdk_nvme_format format = {}; format.lbaf = lbaf; format.ms = ms; format.pi = pi; format.pil = pil; format.ses = ses; ret = spdk_nvme_ctrlr_format(device->ctrlr, ns_id, &format); if (ret) { fprintf(stdout, "nvme format: Failed\n"); return; } } static void attach_and_detach_ns(int attachment_op) { Loading Loading @@ -437,6 +466,105 @@ delete_ns(void) ns_manage_delete(ctrlr, ns_id); } static void format_nvm(void) { int ns_id; int ses; int pil; int pi; int ms; int lbaf; char option; struct dev *ctrlr; ctrlr = get_controller(); if (ctrlr == NULL) { printf("Invalid controller PCI BDF.\n"); return; } if (!ctrlr->cdata->oacs.format) { printf("Controller does not support Format NVM command\n"); return; } if (ctrlr->cdata->fna.format_all_ns) { ns_id = 0xffffffff; } else { printf("Please Input Namespace ID (1 - %d): \n", ctrlr->cdata->nn); if (!scanf("%d", &ns_id)) { printf("Invalid Namespace ID\n"); while (getchar() != '\n'); return; } } printf("Please Input Secure Erase Setting: \n"); printf(" 0: No secure erase operation requested\n"); printf(" 1: User data erase\n"); printf(" 2: Cryptographic erase\n"); if (!scanf("%d", &ses)) { printf("Invalid Secure Erase Setting\n"); while (getchar() != '\n'); return; } printf("Please Input Protection Information: \n"); printf(" 0: Protection information is not enabled\n"); printf(" 1: Protection information is enabled, Type 1\n"); printf(" 2: Protection information is enabled, Type 2\n"); printf(" 3: Protection information is enabled, Type 3\n"); if (!scanf("%d", &pi)) { printf("Invalid protection information\n"); while (getchar() != '\n'); return; } printf("Please Input Protection Information Location: \n"); printf(" 0: Protection information transferred as the last eight bytes of metadata\n"); printf(" 1: Protection information transferred as the first eight bytes of metadata\n"); if (!scanf("%d", &pil)) { printf("Invalid protection information location\n"); while (getchar() != '\n'); return; } printf("Please Input Metadata Setting: \n"); printf(" 0: Metadata is transferred as part of a separate buffer\n"); printf(" 1: Metadata is transferred as part of an extended data LBA\n"); if (!scanf("%d", &ms)) { printf("Invalid metadata setting\n"); while (getchar() != '\n'); return; } printf("Please Input LBA Format Number (0 - 15): \n"); if (!scanf("%d", &lbaf)) { printf("Invalid LBA format size\n"); while (getchar() != '\n'); return; } printf("Warning: use this utility at your own risk.\n" "This command will format your namespace and all data will be lost.\n" "This command may take several minutes to complete,\n" "so do not interrupt the utility until it completes.\n" "Press 'Y' to continue with the format operation.\n"); while (getchar() != '\n'); if (!scanf("%c", &option)) { printf("Invalid option\n"); while (getchar() != '\n'); return; } if (option == 'y' || option == 'Y') { nvme_manage_format(ctrlr, ns_id, ses, pi, pil, ms, lbaf); } else { printf("NVMe format abort\n"); } } int main(int argc, char **argv) { int rc, i; Loading Loading @@ -494,6 +622,9 @@ int main(int argc, char **argv) attach_and_detach_ns(SPDK_NVME_NS_CTRLR_DETACH); break; case 6: format_nvm(); break; case 7: exit_flag = true; break; default: Loading include/spdk/nvme.h +14 −0 Original line number Diff line number Diff line Loading @@ -447,6 +447,20 @@ int spdk_nvme_ctrlr_create_ns(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns */ int spdk_nvme_ctrlr_delete_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid); /** * \brief format NVMe. * * \param nsid the name space identifier. * \param format the format information for the command. * * \return 0 if successfully submitted, ENOMEM if resources could not be allocated for this request * * This function is thread safe and can be called at any point after spdk_nvme_attach(). * */ int spdk_nvme_ctrlr_format(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, struct spdk_nvme_format *format); /** * \brief Get the identify namespace data as defined by the NVMe specification. * Loading include/spdk/nvme_spec.h +39 −1 Original line number Diff line number Diff line Loading @@ -760,7 +760,12 @@ struct __attribute__((packed)) spdk_nvme_ctrlr_data { uint16_t fuses; /** format nvm attributes */ uint8_t fna; struct { uint8_t format_all_ns: 1; uint8_t erase_all_ns: 1; uint8_t crypto_erase_supported: 1; uint8_t reserved: 5; } fna; /** volatile write cache */ struct { Loading Loading @@ -1231,6 +1236,39 @@ struct spdk_nvme_ctrlr_list { }; SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_ctrlr_list) == 4096, "Incorrect size"); enum spdk_nvme_secure_erase_setting { SPDK_NVME_FMT_NVM_SES_NO_SECURE_ERASE = 0x0, SPDK_NVME_FMT_NVM_SES_USER_DATA_ERASE = 0x1, SPDK_NVME_FMT_NVM_SES_CRYPTO_ERASE = 0x2, }; enum spdk_nvme_protection_information_location { SPDK_NVME_FMT_NVM_PROTECTION_AT_TAIL = 0x0, SPDK_NVME_FMT_NVM_PROTECTION_AT_HEAD = 0x1, }; enum spdk_nvme_protection_information { SPDK_NVME_FMT_NVM_PROTECTION_DISABLE = 0x0, SPDK_NVME_FMT_NVM_PROTECTION_TYPE1 = 0x1, SPDK_NVME_FMT_NVM_PROTECTION_TYPE2 = 0x2, SPDK_NVME_FMT_NVM_PROTECTION_TYPE3 = 0x3, }; enum spdk_nvme_metadata_setting { SPDK_NVME_FMT_NVM_METADATA_TRANSFER_AS_BUFFER = 0x0, SPDK_NVME_FMT_NVM_METADATA_TRANSFER_AS_LBA = 0x1, }; struct spdk_nvme_format { uint32_t lbaf : 4; uint32_t ms : 1; uint32_t pi : 3; uint32_t pil : 1; uint32_t ses : 3; uint32_t reserved : 20; }; SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_format) == 4, "Incorrect size"); #define spdk_nvme_cpl_is_error(cpl) \ ((cpl)->status.sc != 0 || (cpl)->status.sct != 0) Loading lib/nvme/nvme_ctrlr.c +25 −0 Original line number Diff line number Diff line Loading @@ -1203,3 +1203,28 @@ spdk_nvme_ctrlr_delete_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid) return spdk_nvme_ctrlr_reset(ctrlr); } int spdk_nvme_ctrlr_format(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, struct spdk_nvme_format *format) { struct nvme_completion_poll_status status; int res; status.done = false; res = nvme_ctrlr_cmd_format(ctrlr, nsid, format, nvme_completion_poll_cb, &status); if (res) return res; while (status.done == false) { nvme_mutex_lock(&ctrlr->ctrlr_lock); spdk_nvme_qpair_process_completions(&ctrlr->adminq, 0); nvme_mutex_unlock(&ctrlr->ctrlr_lock); } if (spdk_nvme_cpl_is_error(&status.cpl)) { nvme_printf(ctrlr, "spdk_nvme_ctrlr_format failed!\n"); return ENXIO; } return spdk_nvme_ctrlr_reset(ctrlr); } lib/nvme/nvme_ctrlr_cmd.c +25 −0 Original line number Diff line number Diff line Loading @@ -330,6 +330,31 @@ nvme_ctrlr_cmd_delete_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, spdk_nvme return rc; } int nvme_ctrlr_cmd_format(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, struct spdk_nvme_format *format, spdk_nvme_cmd_cb cb_fn, void *cb_arg) { struct nvme_request *req; struct spdk_nvme_cmd *cmd; nvme_mutex_lock(&ctrlr->ctrlr_lock); req = nvme_allocate_request_null(cb_fn, cb_arg); if (req == NULL) { nvme_mutex_unlock(&ctrlr->ctrlr_lock); return ENOMEM; } cmd = &req->cmd; cmd->opc = SPDK_NVME_OPC_FORMAT_NVM; cmd->nsid = nsid; memcpy(&cmd->cdw10, format, sizeof(uint32_t)); nvme_ctrlr_submit_admin_request(ctrlr, req); nvme_mutex_unlock(&ctrlr->ctrlr_lock); return 0; } int spdk_nvme_ctrlr_cmd_set_feature(struct spdk_nvme_ctrlr *ctrlr, uint8_t feature, uint32_t cdw11, uint32_t cdw12, void *payload, uint32_t payload_size, Loading Loading
examples/nvme/nvme_manage/nvme_manage.c +132 −1 Original line number Diff line number Diff line Loading @@ -139,7 +139,8 @@ static void usage(void) printf("\t[3: delete namespace]\n"); printf("\t[4: attach namespace to controller]\n"); printf("\t[5: detach namespace from controller]\n"); printf("\t[6: quit]\n"); printf("\t[6: format namespace or controller]\n"); printf("\t[7: quit]\n"); } static void Loading Loading @@ -198,6 +199,16 @@ display_controller(struct dev *dev, int model) printf("============================\n"); printf("Namespace Manage And Attach: %s\n", cdata->oacs.ns_manage ? "Supported" : "Not Supported"); printf("Namespace Format: %s\n", cdata->oacs.format ? "Supported" : "Not Supported"); printf("\n"); printf("NVM Command Set Attributes\n"); printf("============================\n"); if (cdata->fna.format_all_ns) { printf("Namespace format operation applies to all namespaces\n"); } else { printf("Namespace format operation applies to per namespace\n"); } printf("\n"); printf("Namespace Attributes\n"); printf("============================\n"); Loading Loading @@ -340,6 +351,24 @@ ns_manage_delete(struct dev *device, int ns_id) } } static void nvme_manage_format(struct dev *device, int ns_id, int ses, int pi, int pil, int ms, int lbaf) { int ret = 0; struct spdk_nvme_format format = {}; format.lbaf = lbaf; format.ms = ms; format.pi = pi; format.pil = pil; format.ses = ses; ret = spdk_nvme_ctrlr_format(device->ctrlr, ns_id, &format); if (ret) { fprintf(stdout, "nvme format: Failed\n"); return; } } static void attach_and_detach_ns(int attachment_op) { Loading Loading @@ -437,6 +466,105 @@ delete_ns(void) ns_manage_delete(ctrlr, ns_id); } static void format_nvm(void) { int ns_id; int ses; int pil; int pi; int ms; int lbaf; char option; struct dev *ctrlr; ctrlr = get_controller(); if (ctrlr == NULL) { printf("Invalid controller PCI BDF.\n"); return; } if (!ctrlr->cdata->oacs.format) { printf("Controller does not support Format NVM command\n"); return; } if (ctrlr->cdata->fna.format_all_ns) { ns_id = 0xffffffff; } else { printf("Please Input Namespace ID (1 - %d): \n", ctrlr->cdata->nn); if (!scanf("%d", &ns_id)) { printf("Invalid Namespace ID\n"); while (getchar() != '\n'); return; } } printf("Please Input Secure Erase Setting: \n"); printf(" 0: No secure erase operation requested\n"); printf(" 1: User data erase\n"); printf(" 2: Cryptographic erase\n"); if (!scanf("%d", &ses)) { printf("Invalid Secure Erase Setting\n"); while (getchar() != '\n'); return; } printf("Please Input Protection Information: \n"); printf(" 0: Protection information is not enabled\n"); printf(" 1: Protection information is enabled, Type 1\n"); printf(" 2: Protection information is enabled, Type 2\n"); printf(" 3: Protection information is enabled, Type 3\n"); if (!scanf("%d", &pi)) { printf("Invalid protection information\n"); while (getchar() != '\n'); return; } printf("Please Input Protection Information Location: \n"); printf(" 0: Protection information transferred as the last eight bytes of metadata\n"); printf(" 1: Protection information transferred as the first eight bytes of metadata\n"); if (!scanf("%d", &pil)) { printf("Invalid protection information location\n"); while (getchar() != '\n'); return; } printf("Please Input Metadata Setting: \n"); printf(" 0: Metadata is transferred as part of a separate buffer\n"); printf(" 1: Metadata is transferred as part of an extended data LBA\n"); if (!scanf("%d", &ms)) { printf("Invalid metadata setting\n"); while (getchar() != '\n'); return; } printf("Please Input LBA Format Number (0 - 15): \n"); if (!scanf("%d", &lbaf)) { printf("Invalid LBA format size\n"); while (getchar() != '\n'); return; } printf("Warning: use this utility at your own risk.\n" "This command will format your namespace and all data will be lost.\n" "This command may take several minutes to complete,\n" "so do not interrupt the utility until it completes.\n" "Press 'Y' to continue with the format operation.\n"); while (getchar() != '\n'); if (!scanf("%c", &option)) { printf("Invalid option\n"); while (getchar() != '\n'); return; } if (option == 'y' || option == 'Y') { nvme_manage_format(ctrlr, ns_id, ses, pi, pil, ms, lbaf); } else { printf("NVMe format abort\n"); } } int main(int argc, char **argv) { int rc, i; Loading Loading @@ -494,6 +622,9 @@ int main(int argc, char **argv) attach_and_detach_ns(SPDK_NVME_NS_CTRLR_DETACH); break; case 6: format_nvm(); break; case 7: exit_flag = true; break; default: Loading
include/spdk/nvme.h +14 −0 Original line number Diff line number Diff line Loading @@ -447,6 +447,20 @@ int spdk_nvme_ctrlr_create_ns(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns */ int spdk_nvme_ctrlr_delete_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid); /** * \brief format NVMe. * * \param nsid the name space identifier. * \param format the format information for the command. * * \return 0 if successfully submitted, ENOMEM if resources could not be allocated for this request * * This function is thread safe and can be called at any point after spdk_nvme_attach(). * */ int spdk_nvme_ctrlr_format(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, struct spdk_nvme_format *format); /** * \brief Get the identify namespace data as defined by the NVMe specification. * Loading
include/spdk/nvme_spec.h +39 −1 Original line number Diff line number Diff line Loading @@ -760,7 +760,12 @@ struct __attribute__((packed)) spdk_nvme_ctrlr_data { uint16_t fuses; /** format nvm attributes */ uint8_t fna; struct { uint8_t format_all_ns: 1; uint8_t erase_all_ns: 1; uint8_t crypto_erase_supported: 1; uint8_t reserved: 5; } fna; /** volatile write cache */ struct { Loading Loading @@ -1231,6 +1236,39 @@ struct spdk_nvme_ctrlr_list { }; SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_ctrlr_list) == 4096, "Incorrect size"); enum spdk_nvme_secure_erase_setting { SPDK_NVME_FMT_NVM_SES_NO_SECURE_ERASE = 0x0, SPDK_NVME_FMT_NVM_SES_USER_DATA_ERASE = 0x1, SPDK_NVME_FMT_NVM_SES_CRYPTO_ERASE = 0x2, }; enum spdk_nvme_protection_information_location { SPDK_NVME_FMT_NVM_PROTECTION_AT_TAIL = 0x0, SPDK_NVME_FMT_NVM_PROTECTION_AT_HEAD = 0x1, }; enum spdk_nvme_protection_information { SPDK_NVME_FMT_NVM_PROTECTION_DISABLE = 0x0, SPDK_NVME_FMT_NVM_PROTECTION_TYPE1 = 0x1, SPDK_NVME_FMT_NVM_PROTECTION_TYPE2 = 0x2, SPDK_NVME_FMT_NVM_PROTECTION_TYPE3 = 0x3, }; enum spdk_nvme_metadata_setting { SPDK_NVME_FMT_NVM_METADATA_TRANSFER_AS_BUFFER = 0x0, SPDK_NVME_FMT_NVM_METADATA_TRANSFER_AS_LBA = 0x1, }; struct spdk_nvme_format { uint32_t lbaf : 4; uint32_t ms : 1; uint32_t pi : 3; uint32_t pil : 1; uint32_t ses : 3; uint32_t reserved : 20; }; SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_format) == 4, "Incorrect size"); #define spdk_nvme_cpl_is_error(cpl) \ ((cpl)->status.sc != 0 || (cpl)->status.sct != 0) Loading
lib/nvme/nvme_ctrlr.c +25 −0 Original line number Diff line number Diff line Loading @@ -1203,3 +1203,28 @@ spdk_nvme_ctrlr_delete_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid) return spdk_nvme_ctrlr_reset(ctrlr); } int spdk_nvme_ctrlr_format(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, struct spdk_nvme_format *format) { struct nvme_completion_poll_status status; int res; status.done = false; res = nvme_ctrlr_cmd_format(ctrlr, nsid, format, nvme_completion_poll_cb, &status); if (res) return res; while (status.done == false) { nvme_mutex_lock(&ctrlr->ctrlr_lock); spdk_nvme_qpair_process_completions(&ctrlr->adminq, 0); nvme_mutex_unlock(&ctrlr->ctrlr_lock); } if (spdk_nvme_cpl_is_error(&status.cpl)) { nvme_printf(ctrlr, "spdk_nvme_ctrlr_format failed!\n"); return ENXIO; } return spdk_nvme_ctrlr_reset(ctrlr); }
lib/nvme/nvme_ctrlr_cmd.c +25 −0 Original line number Diff line number Diff line Loading @@ -330,6 +330,31 @@ nvme_ctrlr_cmd_delete_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, spdk_nvme return rc; } int nvme_ctrlr_cmd_format(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, struct spdk_nvme_format *format, spdk_nvme_cmd_cb cb_fn, void *cb_arg) { struct nvme_request *req; struct spdk_nvme_cmd *cmd; nvme_mutex_lock(&ctrlr->ctrlr_lock); req = nvme_allocate_request_null(cb_fn, cb_arg); if (req == NULL) { nvme_mutex_unlock(&ctrlr->ctrlr_lock); return ENOMEM; } cmd = &req->cmd; cmd->opc = SPDK_NVME_OPC_FORMAT_NVM; cmd->nsid = nsid; memcpy(&cmd->cdw10, format, sizeof(uint32_t)); nvme_ctrlr_submit_admin_request(ctrlr, req); nvme_mutex_unlock(&ctrlr->ctrlr_lock); return 0; } int spdk_nvme_ctrlr_cmd_set_feature(struct spdk_nvme_ctrlr *ctrlr, uint8_t feature, uint32_t cdw11, uint32_t cdw12, void *payload, uint32_t payload_size, Loading