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: Ben Walker <benjamin.walker@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/421
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
This commit is contained in:
Ben Walker 2020-02-03 15:00:35 -07:00 committed by Tomasz Zawadzki
parent 8175aa1fea
commit e8c195b3eb

View File

@ -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 = 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 = (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,11 +929,27 @@ 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);
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, 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;
@ -900,20 +958,29 @@ spdk_nvmf_property_set(struct spdk_nvmf_request *req)
}
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;
}
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;