spdk: Add nvme format interface and unit tests.
Change-Id: Ie0506debf547a5fc011e116421387a5adb7abf0e Signed-off-by: Cunyin Chang <cunyin.chang@intel.com>
This commit is contained in:
parent
4fc355ba68
commit
eae688576a
@ -139,7 +139,8 @@ static void usage(void)
|
|||||||
printf("\t[3: delete namespace]\n");
|
printf("\t[3: delete namespace]\n");
|
||||||
printf("\t[4: attach namespace to controller]\n");
|
printf("\t[4: attach namespace to controller]\n");
|
||||||
printf("\t[5: detach namespace from 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
|
static void
|
||||||
@ -198,6 +199,16 @@ display_controller(struct dev *dev, int model)
|
|||||||
printf("============================\n");
|
printf("============================\n");
|
||||||
printf("Namespace Manage And Attach: %s\n",
|
printf("Namespace Manage And Attach: %s\n",
|
||||||
cdata->oacs.ns_manage ? "Supported" : "Not Supported");
|
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("\n");
|
||||||
printf("Namespace Attributes\n");
|
printf("Namespace Attributes\n");
|
||||||
printf("============================\n");
|
printf("============================\n");
|
||||||
@ -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
|
static void
|
||||||
attach_and_detach_ns(int attachment_op)
|
attach_and_detach_ns(int attachment_op)
|
||||||
{
|
{
|
||||||
@ -437,6 +466,105 @@ delete_ns(void)
|
|||||||
ns_manage_delete(ctrlr, ns_id);
|
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 main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int rc, i;
|
int rc, i;
|
||||||
@ -494,6 +622,9 @@ int main(int argc, char **argv)
|
|||||||
attach_and_detach_ns(SPDK_NVME_NS_CTRLR_DETACH);
|
attach_and_detach_ns(SPDK_NVME_NS_CTRLR_DETACH);
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
|
format_nvm();
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
exit_flag = true;
|
exit_flag = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -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);
|
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.
|
* \brief Get the identify namespace data as defined by the NVMe specification.
|
||||||
*
|
*
|
||||||
|
@ -760,7 +760,12 @@ struct __attribute__((packed)) spdk_nvme_ctrlr_data {
|
|||||||
uint16_t fuses;
|
uint16_t fuses;
|
||||||
|
|
||||||
/** format nvm attributes */
|
/** 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 */
|
/** volatile write cache */
|
||||||
struct {
|
struct {
|
||||||
@ -1231,6 +1236,39 @@ struct spdk_nvme_ctrlr_list {
|
|||||||
};
|
};
|
||||||
SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_ctrlr_list) == 4096, "Incorrect size");
|
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) \
|
#define spdk_nvme_cpl_is_error(cpl) \
|
||||||
((cpl)->status.sc != 0 || (cpl)->status.sct != 0)
|
((cpl)->status.sc != 0 || (cpl)->status.sct != 0)
|
||||||
|
|
||||||
|
@ -1203,3 +1203,28 @@ spdk_nvme_ctrlr_delete_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid)
|
|||||||
|
|
||||||
return spdk_nvme_ctrlr_reset(ctrlr);
|
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);
|
||||||
|
}
|
||||||
|
@ -330,6 +330,31 @@ nvme_ctrlr_cmd_delete_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, spdk_nvme
|
|||||||
return rc;
|
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
|
int
|
||||||
spdk_nvme_ctrlr_cmd_set_feature(struct spdk_nvme_ctrlr *ctrlr, uint8_t feature,
|
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,
|
uint32_t cdw11, uint32_t cdw12, void *payload, uint32_t payload_size,
|
||||||
|
@ -514,6 +514,8 @@ int nvme_ctrlr_cmd_create_ns(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns_
|
|||||||
spdk_nvme_cmd_cb cb_fn, void *cb_arg);
|
spdk_nvme_cmd_cb cb_fn, void *cb_arg);
|
||||||
int nvme_ctrlr_cmd_delete_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, spdk_nvme_cmd_cb cb_fn,
|
int nvme_ctrlr_cmd_delete_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, spdk_nvme_cmd_cb cb_fn,
|
||||||
void *cb_arg);
|
void *cb_arg);
|
||||||
|
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);
|
||||||
void nvme_completion_poll_cb(void *arg, const struct spdk_nvme_cpl *cpl);
|
void nvme_completion_poll_cb(void *arg, const struct spdk_nvme_cpl *cpl);
|
||||||
|
|
||||||
int nvme_ctrlr_construct(struct spdk_nvme_ctrlr *ctrlr, void *devhandle);
|
int nvme_ctrlr_construct(struct spdk_nvme_ctrlr *ctrlr, void *devhandle);
|
||||||
|
@ -246,6 +246,13 @@ nvme_ctrlr_cmd_delete_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, spdk_nvme
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nvme_ns_destruct(struct spdk_nvme_ns *ns)
|
nvme_ns_destruct(struct spdk_nvme_ns *ns)
|
||||||
{
|
{
|
||||||
|
@ -52,6 +52,7 @@ uint32_t get_feature_cdw11 = 1;
|
|||||||
uint16_t abort_cid = 1;
|
uint16_t abort_cid = 1;
|
||||||
uint16_t abort_sqid = 1;
|
uint16_t abort_sqid = 1;
|
||||||
uint32_t namespace_management_nsid = 1;
|
uint32_t namespace_management_nsid = 1;
|
||||||
|
uint32_t format_nvme_nsid = 1;
|
||||||
|
|
||||||
typedef void (*verify_request_fn_t)(struct nvme_request *req);
|
typedef void (*verify_request_fn_t)(struct nvme_request *req);
|
||||||
verify_request_fn_t verify_fn;
|
verify_request_fn_t verify_fn;
|
||||||
@ -205,6 +206,13 @@ static void verify_namespace_delete(struct nvme_request *req)
|
|||||||
CU_ASSERT(req->cmd.nsid == namespace_management_nsid);
|
CU_ASSERT(req->cmd.nsid == namespace_management_nsid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void verify_format_nvme(struct nvme_request *req)
|
||||||
|
{
|
||||||
|
CU_ASSERT(req->cmd.opc == SPDK_NVME_OPC_FORMAT_NVM);
|
||||||
|
CU_ASSERT(req->cmd.cdw10 == 0);
|
||||||
|
CU_ASSERT(req->cmd.nsid == format_nvme_nsid);
|
||||||
|
}
|
||||||
|
|
||||||
struct nvme_request *
|
struct nvme_request *
|
||||||
nvme_allocate_request(const struct nvme_payload *payload, uint32_t payload_size,
|
nvme_allocate_request(const struct nvme_payload *payload, uint32_t payload_size,
|
||||||
spdk_nvme_cmd_cb cb_fn,
|
spdk_nvme_cmd_cb cb_fn,
|
||||||
@ -468,6 +476,17 @@ test_namespace_delete(void)
|
|||||||
nvme_ctrlr_cmd_delete_ns(&ctrlr, namespace_management_nsid, NULL, NULL);
|
nvme_ctrlr_cmd_delete_ns(&ctrlr, namespace_management_nsid, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_format_nvme(void)
|
||||||
|
{
|
||||||
|
struct spdk_nvme_ctrlr ctrlr = {};
|
||||||
|
struct spdk_nvme_format format = {};
|
||||||
|
|
||||||
|
verify_fn = verify_format_nvme;
|
||||||
|
|
||||||
|
nvme_ctrlr_cmd_format(&ctrlr, format_nvme_nsid, &format, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
CU_pSuite suite = NULL;
|
CU_pSuite suite = NULL;
|
||||||
@ -493,6 +512,7 @@ int main(int argc, char **argv)
|
|||||||
|| CU_add_test(suite, "test ctrlr cmd namespace_detach", test_namespace_detach) == NULL
|
|| CU_add_test(suite, "test ctrlr cmd namespace_detach", test_namespace_detach) == NULL
|
||||||
|| CU_add_test(suite, "test ctrlr cmd namespace_create", test_namespace_create) == NULL
|
|| CU_add_test(suite, "test ctrlr cmd namespace_create", test_namespace_create) == NULL
|
||||||
|| CU_add_test(suite, "test ctrlr cmd namespace_delete", test_namespace_delete) == NULL
|
|| CU_add_test(suite, "test ctrlr cmd namespace_delete", test_namespace_delete) == NULL
|
||||||
|
|| CU_add_test(suite, "test ctrlr cmd format_nvme", test_format_nvme) == NULL
|
||||||
) {
|
) {
|
||||||
CU_cleanup_registry();
|
CU_cleanup_registry();
|
||||||
return CU_get_error();
|
return CU_get_error();
|
||||||
|
Loading…
Reference in New Issue
Block a user