Commit e8c195b3 authored by Ben Walker's avatar Ben Walker Committed by Tomasz Zawadzki
Browse files

nvmf: Allow 4 byte property operations on 8 byte properties



The first 4 or last 4 bytes of an 8 byte property can now
be written independently.

Change-Id: I894f8349be836511c18c380262eae46951060766
Signed-off-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/421


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
parent 8175aa1f
Loading
Loading
Loading
Loading
+109 −42
Original line number Diff line number Diff line
@@ -663,11 +663,11 @@ nvmf_prop_get_cc(struct spdk_nvmf_ctrlr *ctrlr)
}

static bool
nvmf_prop_set_cc(struct spdk_nvmf_ctrlr *ctrlr, uint64_t value)
nvmf_prop_set_cc(struct spdk_nvmf_ctrlr *ctrlr, uint32_t value)
{
	union spdk_nvme_cc_register cc, diff;

	cc.raw = (uint32_t)value;
	cc.raw = value;

	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "cur CC: 0x%08x\n", ctrlr->vcprop.cc.raw);
	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "new CC: 0x%08x\n", cc.raw);
@@ -759,9 +759,18 @@ nvmf_prop_get_aqa(struct spdk_nvmf_ctrlr *ctrlr)
}

static bool
nvmf_prop_set_aqa(struct spdk_nvmf_ctrlr *ctrlr, uint64_t value)
nvmf_prop_set_aqa(struct spdk_nvmf_ctrlr *ctrlr, uint32_t value)
{
	ctrlr->vcprop.aqa.raw = (uint32_t)value;
	union spdk_nvme_aqa_register aqa;

	aqa.raw = value;

	if (aqa.bits.asqs > ctrlr->vcprop.cap.bits.mqes ||
	    aqa.bits.acqs > ctrlr->vcprop.cap.bits.mqes) {
		return false;
	}

	ctrlr->vcprop.aqa.raw = value;

	return true;
}
@@ -773,9 +782,17 @@ nvmf_prop_get_asq(struct spdk_nvmf_ctrlr *ctrlr)
}

static bool
nvmf_prop_set_asq(struct spdk_nvmf_ctrlr *ctrlr, uint64_t value)
nvmf_prop_set_asq_lower(struct spdk_nvmf_ctrlr *ctrlr, uint32_t value)
{
	ctrlr->vcprop.asq = value;
	ctrlr->vcprop.asq = (ctrlr->vcprop.asq & (0xFFFFFFFFULL << 32ULL)) | value;

	return true;
}

static bool
nvmf_prop_set_asq_upper(struct spdk_nvmf_ctrlr *ctrlr, uint32_t value)
{
	ctrlr->vcprop.asq = (ctrlr->vcprop.asq & 0xFFFFFFFFULL) | ((uint64_t)value << 32ULL);

	return true;
}
@@ -787,9 +804,17 @@ nvmf_prop_get_acq(struct spdk_nvmf_ctrlr *ctrlr)
}

static bool
nvmf_prop_set_acq(struct spdk_nvmf_ctrlr *ctrlr, uint64_t value)
nvmf_prop_set_acq_lower(struct spdk_nvmf_ctrlr *ctrlr, uint32_t value)
{
	ctrlr->vcprop.acq = (ctrlr->vcprop.acq & (0xFFFFFFFFULL << 32ULL)) | value;

	return true;
}

static bool
nvmf_prop_set_acq_upper(struct spdk_nvmf_ctrlr *ctrlr, uint32_t value)
{
	ctrlr->vcprop.acq = value;
	ctrlr->vcprop.acq = (ctrlr->vcprop.acq & 0xFFFFFFFFULL) | ((uint64_t)value << 32ULL);

	return true;
}
@@ -799,36 +824,37 @@ struct nvmf_prop {
	uint8_t size;
	char name[11];
	uint64_t (*get_cb)(struct spdk_nvmf_ctrlr *ctrlr);
	bool (*set_cb)(struct spdk_nvmf_ctrlr *ctrlr, uint64_t value);
	bool (*set_cb)(struct spdk_nvmf_ctrlr *ctrlr, uint32_t value);
	bool (*set_upper_cb)(struct spdk_nvmf_ctrlr *ctrlr, uint32_t value);
};

#define PROP(field, size, get_cb, set_cb) \
#define PROP(field, size, get_cb, set_cb, set_upper_cb) \
	{ \
		offsetof(struct spdk_nvme_registers, field), \
		SPDK_NVMF_PROP_SIZE_##size, \
		size, \
		#field, \
		get_cb, set_cb \
		get_cb, set_cb, set_upper_cb \
	}

static const struct nvmf_prop nvmf_props[] = {
	PROP(cap,  8, nvmf_prop_get_cap,  NULL),
	PROP(vs,   4, nvmf_prop_get_vs,   NULL),
	PROP(cc,   4, nvmf_prop_get_cc,   nvmf_prop_set_cc),
	PROP(csts, 4, nvmf_prop_get_csts, NULL),
	PROP(aqa,  4, nvmf_prop_get_aqa,  nvmf_prop_set_aqa),
	PROP(asq,  8, nvmf_prop_get_asq,  nvmf_prop_set_asq),
	PROP(acq,  8, nvmf_prop_get_acq,  nvmf_prop_set_acq),
	PROP(cap,  8, nvmf_prop_get_cap,  NULL,                    NULL),
	PROP(vs,   4, nvmf_prop_get_vs,   NULL,                    NULL),
	PROP(cc,   4, nvmf_prop_get_cc,   nvmf_prop_set_cc,        NULL),
	PROP(csts, 4, nvmf_prop_get_csts, NULL,                    NULL),
	PROP(aqa,  4, nvmf_prop_get_aqa,  nvmf_prop_set_aqa,       NULL),
	PROP(asq,  8, nvmf_prop_get_asq,  nvmf_prop_set_asq_lower, nvmf_prop_set_asq_upper),
	PROP(acq,  8, nvmf_prop_get_acq,  nvmf_prop_set_acq_lower, nvmf_prop_set_acq_upper),
};

static const struct nvmf_prop *
find_prop(uint32_t ofst)
find_prop(uint32_t ofst, uint8_t size)
{
	size_t i;

	for (i = 0; i < SPDK_COUNTOF(nvmf_props); i++) {
		const struct nvmf_prop *prop = &nvmf_props[i];

		if (prop->ofst == ofst) {
		if ((ofst >= prop->ofst) && (ofst + size <= prop->ofst + prop->size)) {
			return prop;
		}
	}
@@ -843,6 +869,7 @@ spdk_nvmf_property_get(struct spdk_nvmf_request *req)
	struct spdk_nvmf_fabric_prop_get_cmd *cmd = &req->cmd->prop_get_cmd;
	struct spdk_nvmf_fabric_prop_get_rsp *response = &req->rsp->prop_get_rsp;
	const struct nvmf_prop *prop;
	uint8_t size;

	response->status.sc = 0;
	response->value.u64 = 0;
@@ -850,32 +877,47 @@ spdk_nvmf_property_get(struct spdk_nvmf_request *req)
	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "size %d, offset 0x%x\n",
		      cmd->attrib.size, cmd->ofst);

	if (cmd->attrib.size != SPDK_NVMF_PROP_SIZE_4 &&
	    cmd->attrib.size != SPDK_NVMF_PROP_SIZE_8) {
	switch (cmd->attrib.size) {
	case SPDK_NVMF_PROP_SIZE_4:
		size = 4;
		break;
	case SPDK_NVMF_PROP_SIZE_8:
		size = 8;
		break;
	default:
		SPDK_ERRLOG("Invalid size value %d\n", cmd->attrib.size);
		response->status.sct = SPDK_NVME_SCT_COMMAND_SPECIFIC;
		response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
		return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
	}

	prop = find_prop(cmd->ofst);
	prop = find_prop(cmd->ofst, size);
	if (prop == NULL || prop->get_cb == NULL) {
		/* Reserved properties return 0 when read */
		return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
	}

	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "name: %s\n", prop->name);
	if (cmd->attrib.size != prop->size) {
		SPDK_ERRLOG("offset 0x%x size mismatch: cmd %u, prop %u\n",
			    cmd->ofst, cmd->attrib.size, prop->size);
		response->status.sct = SPDK_NVME_SCT_COMMAND_SPECIFIC;
		response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
		return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
	}

	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "name: %s\n", prop->name);

	response->value.u64 = prop->get_cb(ctrlr);

	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "response value: 0x%" PRIx64 "\n", response->value.u64);

	if (size != prop->size) {
		/* The size must be 4 and the prop->size is 8. Figure out which part of the property to read. */
		assert(size == 4);
		assert(prop->size == 8);

		if (cmd->ofst == prop->ofst) {
			/* Keep bottom 4 bytes only */
			response->value.u64 &= 0xFFFFFFFF;
		} else {
			/* Keep top 4 bytes only */
			response->value.u64 >>= 32;
		}
	}

	return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
}

@@ -887,33 +929,58 @@ spdk_nvmf_property_set(struct spdk_nvmf_request *req)
	struct spdk_nvme_cpl *response = &req->rsp->nvme_cpl;
	const struct nvmf_prop *prop;
	uint64_t value;
	uint8_t size;
	bool ret;

	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "size %d, offset 0x%x, value 0x%" PRIx64 "\n",
		      cmd->attrib.size, cmd->ofst, cmd->value.u64);

	prop = find_prop(cmd->ofst);
	if (prop == NULL || prop->set_cb == NULL) {
		SPDK_ERRLOG("Invalid offset 0x%x\n", cmd->ofst);
	switch (cmd->attrib.size) {
	case SPDK_NVMF_PROP_SIZE_4:
		size = 4;
		break;
	case SPDK_NVMF_PROP_SIZE_8:
		size = 8;
		break;
	default:
		SPDK_ERRLOG("Invalid size value %d\n", cmd->attrib.size);
		response->status.sct = SPDK_NVME_SCT_COMMAND_SPECIFIC;
		response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
		return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
	}

	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "name: %s\n", prop->name);
	if (cmd->attrib.size != prop->size) {
		SPDK_ERRLOG("offset 0x%x size mismatch: cmd %u, prop %u\n",
			    cmd->ofst, cmd->attrib.size, prop->size);
	prop = find_prop(cmd->ofst, size);
	if (prop == NULL || prop->set_cb == NULL) {
		SPDK_ERRLOG("Invalid offset 0x%x\n", cmd->ofst);
		response->status.sct = SPDK_NVME_SCT_COMMAND_SPECIFIC;
		response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
		return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
	}

	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "name: %s\n", prop->name);

	value = cmd->value.u64;
	if (prop->size == SPDK_NVMF_PROP_SIZE_4) {
		value = (uint32_t)value;

	if (prop->size == 4) {
		ret = prop->set_cb(ctrlr, (uint32_t)value);
	} else if (size != prop->size) {
		/* The size must be 4 and the prop->size is 8. Figure out which part of the property to write. */
		assert(size == 4);
		assert(prop->size == 8);

		if (cmd->ofst == prop->ofst) {
			ret = prop->set_cb(ctrlr, (uint32_t)value);
		} else {
			ret = prop->set_upper_cb(ctrlr, (uint32_t)value);
		}
	} else {
		ret = prop->set_cb(ctrlr, (uint32_t)value);
		if (ret) {
			ret = prop->set_upper_cb(ctrlr, (uint32_t)(value >> 32));
		}
	}

	if (!prop->set_cb(ctrlr, value)) {
	if (!ret) {
		SPDK_ERRLOG("prop set_cb failed\n");
		response->status.sct = SPDK_NVME_SCT_COMMAND_SPECIFIC;
		response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;