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:
Cunyin Chang 2016-03-07 14:29:50 +08:00 committed by Daniel Verkamp
parent 4fc355ba68
commit eae688576a
8 changed files with 264 additions and 2 deletions

View File

@ -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
@ -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");
@ -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)
{
@ -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;
@ -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:

View File

@ -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.
*

View File

@ -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 {
@ -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)

View File

@ -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);
}

View File

@ -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,

View File

@ -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);
int nvme_ctrlr_cmd_delete_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, spdk_nvme_cmd_cb cb_fn,
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);
int nvme_ctrlr_construct(struct spdk_nvme_ctrlr *ctrlr, void *devhandle);

View File

@ -246,6 +246,13 @@ nvme_ctrlr_cmd_delete_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, spdk_nvme
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
nvme_ns_destruct(struct spdk_nvme_ns *ns)
{

View File

@ -52,6 +52,7 @@ uint32_t get_feature_cdw11 = 1;
uint16_t abort_cid = 1;
uint16_t abort_sqid = 1;
uint32_t namespace_management_nsid = 1;
uint32_t format_nvme_nsid = 1;
typedef void (*verify_request_fn_t)(struct nvme_request *req);
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);
}
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 *
nvme_allocate_request(const struct nvme_payload *payload, uint32_t payload_size,
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);
}
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)
{
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_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 format_nvme", test_format_nvme) == NULL
) {
CU_cleanup_registry();
return CU_get_error();