Commit eae68857 authored by Cunyin Chang's avatar Cunyin Chang Committed by Daniel Verkamp
Browse files

spdk: Add nvme format interface and unit tests.



Change-Id: Ie0506debf547a5fc011e116421387a5adb7abf0e
Signed-off-by: default avatarCunyin Chang <cunyin.chang@intel.com>
parent 4fc355ba
Loading
Loading
Loading
Loading
+132 −1
Original line number Diff line number Diff line
@@ -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:
+14 −0
Original line number Diff line number Diff line
@@ -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.
 *
+39 −1
Original line number Diff line number Diff line
@@ -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)

+25 −0
Original line number Diff line number Diff line
@@ -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);
}
+25 −0
Original line number Diff line number Diff line
@@ -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