nvmf: simplify property handling

Create a list of valid properties with get and set callbacks (set is
optional to allow read-only fields).

Remove handling for fields declared as "reserved" in the NVMe over
Fabrics 1.0 specification.

Also simplify the vcprop structure to only contain the required fields.

Change-Id: I14d3ddfd008c62b75fce8e64d193c87fb6f7b5ad
Signed-off-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
Daniel Verkamp 2016-07-07 15:32:04 -07:00
parent e2256173a8
commit 554701492c
3 changed files with 154 additions and 285 deletions

View File

@ -253,137 +253,8 @@ struct spdk_nvmf_fabric_connect_rsp {
};
SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_fabric_connect_rsp) == 16, "Incorrect size");
#define SPDK_NVMF_PROP_CAP_OFST 0x0
#define SPDK_NVMF_PROP_VS_OFST 0x8
#define SPDK_NVMF_PROP_INTMS_OFST 0xC
#define SPDK_NVMF_PROP_INTMC_OFST 0x10
#define SPDK_NVMF_PROP_CC_OFST 0x14
#define SPDK_NVMF_PROP_CSTS_OFST 0x1C
#define SPDK_NVMF_PROP_NSSR_OFST 0x20
#define SPDK_NVMF_PROP_AQA_OFST 0x24
#define SPDK_NVMF_PROP_ASQ_OFST 0x28
#define SPDK_NVMF_PROP_ACQ_OFST 0x30
#define SPDK_NVMF_PROP_CMBLOC_OFST 0x38
#define SPDK_NVMF_PROP_CMBSZ_OFST 0x3C
#define SPDK_NVMF_PROP_CAP_LEN 0x8
#define SPDK_NVMF_PROP_VS_LEN 0x4
#define SPDK_NVMF_PROP_INTMS_LEN 0x4
#define SPDK_NVMF_PROP_INTMC_LEN 0x4
#define SPDK_NVMF_PROP_CC_LEN 0x4
#define SPDK_NVMF_PROP_CSTS_LEN 0x4
#define SPDK_NVMF_PROP_NSSR_LEN 0x4
#define SPDK_NVMF_PROP_AQA_LEN 0x4
#define SPDK_NVMF_PROP_ASQ_LEN 0x8
#define SPDK_NVMF_PROP_ACQ_LEN 0x8
#define SPDK_NVMF_PROP_CMBLOC_LEN 0x4
#define SPDK_NVMF_PROP_CMBSZ_LEN 0x4
union spdk_nvmf_property_size {
uint32_t raw;
struct {
uint32_t reserved : 16;
/** property address space size */
uint32_t size : 16;
} bits;
};
SPDK_STATIC_ASSERT(sizeof(union spdk_nvmf_property_size) == 4, "Incorrect size");
union spdk_nvmf_capsule_attr_lo {
uint32_t raw;
struct {
/** maximum response capsule size */
uint32_t rspsz : 16;
/** maximum command capsule size */
uint32_t cmdsz : 16;
} bits;
};
SPDK_STATIC_ASSERT(sizeof(union spdk_nvmf_capsule_attr_lo) == 4, "Incorrect size");
union spdk_nvmf_capsule_attr_hi {
uint32_t raw;
struct {
/** support capsule alignment in response capsules */
uint32_t reserved : 26;
/** support capsule alignment in response capsules */
uint32_t cairsp : 1;
/** support capsule alignment in command capsules */
uint32_t caicmd : 1;
/** support capsule metadata in response capsules */
uint32_t cmirsp : 1;
/** support capsule metadata in command capsules */
uint32_t cmicmd : 1;
/** support capsule data in response capsules */
uint32_t cdirsp : 1;
/** support capsule data in command capsules */
uint32_t cdicmd : 1;
} bits;
};
SPDK_STATIC_ASSERT(sizeof(union spdk_nvmf_capsule_attr_hi) == 4, "Incorrect size");
struct spdk_nvmf_ctrlr_properties {
union spdk_nvme_cap_register cap;
uint32_t vs;
uint32_t intms;
uint32_t intmc;
union spdk_nvme_cc_register cc;
uint32_t reserved1;
union spdk_nvme_csts_register csts;
uint32_t nssr;
union spdk_nvme_aqa_register aqa;
uint64_t asq;
uint64_t acq;
uint32_t cmbloc;
uint32_t cmbsz;
uint8_t reserved2[0xEC0];
uint8_t reserved3[0x100];
union spdk_nvmf_property_size propsz;
uint32_t reserved4;
union spdk_nvmf_capsule_attr_lo capattr_lo;
union spdk_nvmf_capsule_attr_hi capattr_hi;
uint8_t reserved5[0x2F0];
};
SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_ctrlr_properties) == 4864, "Incorrect size");
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_CAP_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, cap),
"Incorrect register offset");
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_VS_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, vs),
"Incorrect register offset");
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_INTMS_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, intms),
"Incorrect register offset");
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_INTMC_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, intmc),
"Incorrect register offset");
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_CC_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, cc),
"Incorrect register offset");
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_CSTS_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, csts),
"Incorrect register offset");
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_NSSR_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, nssr),
"Incorrect register offset");
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_AQA_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, aqa),
"Incorrect register offset");
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_ASQ_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, asq),
"Incorrect register offset");
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_ACQ_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, acq),
"Incorrect register offset");
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_CMBLOC_OFST == offsetof(struct spdk_nvmf_ctrlr_properties,
cmbloc),
"Incorrect property offset");
SPDK_STATIC_ASSERT(SPDK_NVMF_PROP_CMBSZ_OFST == offsetof(struct spdk_nvmf_ctrlr_properties, cmbsz),
"Incorrect property offset");
#define SPDK_NVMF_PROP_SIZE_4 0
#define SPDK_NVMF_PROP_SIZE_8 1
struct spdk_nvmf_fabric_prop_get_cmd {
uint8_t opcode;
@ -391,7 +262,10 @@ struct spdk_nvmf_fabric_prop_get_cmd {
uint16_t cid;
uint8_t fctype;
uint8_t reserved2[35];
uint8_t attrib;
struct {
uint8_t size : 2;
uint8_t reserved : 6;
} attrib;
uint8_t reserved3[3];
uint32_t ofst;
uint8_t reserved4[16];
@ -420,7 +294,10 @@ struct spdk_nvmf_fabric_prop_set_cmd {
uint16_t cid;
uint8_t fctype;
uint8_t reserved1[35];
uint8_t attrib;
struct {
uint8_t size : 2;
uint8_t reserved : 6;
} attrib;
uint8_t reserved2[3];
uint32_t ofst;

View File

@ -111,7 +111,10 @@ nvmf_init_discovery_session_properties(struct nvmf_session *session)
session->vcprop.cap.bits.mpsmin = 0; /* 2 ^ 12 + mpsmin == 4k */
session->vcprop.cap.bits.mpsmax = 0; /* 2 ^ 12 + mpsmax == 4k */
session->vcprop.vs = 0x10000; /* Version Supported: Major 1, Minor 0 */
/* Version Supported: 1.0 */
session->vcprop.vs.bits.mjr = 1;
session->vcprop.vs.bits.mnr = 0;
session->vcprop.vs.bits.ter = 0;
session->vcprop.cc.raw = 0;
@ -181,7 +184,10 @@ nvmf_init_nvme_session_properties(struct nvmf_session *session, int aq_depth)
session->vcprop.cap.bits.mpsmin = 0; /* 2 ^ 12 + mpsmin == 4k */
session->vcprop.cap.bits.mpsmax = 0; /* 2 ^ 12 + mpsmax == 4k */
session->vcprop.vs = 0x10000; /* Version Supported: Major 1, Minor 0 */
/* Version Supported: 1.0 */
session->vcprop.vs.bits.mjr = 1;
session->vcprop.vs.bits.mnr = 0;
session->vcprop.vs.bits.ter = 0;
session->vcprop.cc.raw = 0;
session->vcprop.cc.bits.en = 0; /* Init controller disabled */
@ -189,33 +195,14 @@ nvmf_init_nvme_session_properties(struct nvmf_session *session, int aq_depth)
session->vcprop.csts.raw = 0;
session->vcprop.csts.bits.rdy = 0; /* Init controller as not ready */
/* nssr not defined for v1.0 */
/* Set AQA details to reflect the virtual connection SQ/CQ depth */
session->vcprop.aqa.bits.asqs = (aq_depth & 0xFFF);
session->vcprop.aqa.bits.acqs = (aq_depth & 0xFFF);
session->vcprop.propsz.bits.size = sizeof(struct spdk_nvmf_ctrlr_properties) / 64;
session->vcprop.capattr_hi.raw = 0;
session->vcprop.capattr_lo.bits.rspsz = sizeof(union nvmf_c2h_msg) / 16;
session->vcprop.capattr_lo.bits.cmdsz = sizeof(union nvmf_h2c_msg) / 16;
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: max io queues %x\n",
session->max_io_queues);
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: cap %" PRIx64 "\n",
session->vcprop.cap.raw);
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: vs %x\n", session->vcprop.vs);
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: vs %x\n", session->vcprop.vs.raw);
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: cc %x\n", session->vcprop.cc.raw);
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: csts %x\n",
session->vcprop.csts.raw);
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: nssr %x\n", session->vcprop.nssr);
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: aqa %x\n", session->vcprop.aqa.raw);
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: propsz %x\n",
session->vcprop.propsz.raw);
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: capattr_lo %x\n",
session->vcprop.capattr_lo.raw);
SPDK_TRACELOG(SPDK_TRACE_NVMF, " nvmf_init_session_properties: capattr_hi %x\n",
session->vcprop.capattr_hi.raw);
}
void
@ -376,92 +363,126 @@ nvmf_complete_cmd(void *ctx, const struct spdk_nvme_cpl *cmp)
spdk_nvmf_request_complete(req);
}
static uint64_t
nvmf_prop_get_cap(struct nvmf_session *session)
{
return session->vcprop.cap.raw;
}
static uint64_t
nvmf_prop_get_vs(struct nvmf_session *session)
{
return session->vcprop.vs.raw;
}
static uint64_t
nvmf_prop_get_cc(struct nvmf_session *session)
{
return session->vcprop.cc.raw;
}
static bool
nvmf_prop_set_cc(struct nvmf_session *session, uint64_t value)
{
union spdk_nvme_cc_register cc;
cc.raw = (uint32_t)value;
if (cc.bits.en && !session->vcprop.cc.bits.en) {
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Property Set CC Enable!\n");
session->vcprop.csts.bits.rdy = 1;
}
if (cc.bits.shn && !session->vcprop.cc.bits.shn) {
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Property Set CC Shutdown!\n");
session->vcprop.cc.bits.en = 0;
}
session->vcprop.cc.raw = cc.raw;
return true;
}
static uint64_t
nvmf_prop_get_csts(struct nvmf_session *session)
{
return session->vcprop.csts.raw;
}
struct nvmf_prop {
uint32_t ofst;
uint8_t size;
char name[11];
uint64_t (*get_cb)(struct nvmf_session *session);
bool (*set_cb)(struct nvmf_session *session, uint64_t value);
};
#define PROP(field, size, get_cb, set_cb) \
{ \
offsetof(struct spdk_nvme_registers, field), \
SPDK_NVMF_PROP_SIZE_##size, \
#field, \
get_cb, set_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),
};
static const struct nvmf_prop *
find_prop(uint32_t ofst)
{
size_t i;
for (i = 0; i < sizeof(nvmf_props) / sizeof(*nvmf_props); i++) {
const struct nvmf_prop *prop = &nvmf_props[i];
if (prop->ofst == ofst) {
return prop;
}
}
return NULL;
}
void
nvmf_property_get(struct nvmf_session *session,
struct spdk_nvmf_fabric_prop_get_cmd *cmd,
struct spdk_nvmf_fabric_prop_get_rsp *response)
{
const struct nvmf_prop *prop;
response->status.sc = 0;
response->value.u64 = 0;
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_property_get: attrib %d, offset %x\n",
cmd->attrib, cmd->ofst);
SPDK_TRACELOG(SPDK_TRACE_NVMF, "size %d, offset 0x%x\n",
cmd->attrib.size, cmd->ofst);
if (cmd->ofst > offsetof(struct spdk_nvmf_ctrlr_properties, capattr_hi)) {
if (cmd->attrib.size != SPDK_NVMF_PROP_SIZE_4 &&
cmd->attrib.size != SPDK_NVMF_PROP_SIZE_8) {
SPDK_ERRLOG("Invalid size value %d\n", cmd->attrib.size);
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
return;
}
switch (cmd->ofst) {
case (offsetof(struct spdk_nvmf_ctrlr_properties, cap)):
response->value.u32.low = session->vcprop.cap.raw;
if (cmd->attrib == 1)
response->value.u64 = session->vcprop.cap.raw;
break;
case (offsetof(struct spdk_nvmf_ctrlr_properties, cap) + 4):
if (cmd->attrib == 1)
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
else
response->value.u32.low = session->vcprop.cap.raw >> 32;
break;
case (offsetof(struct spdk_nvmf_ctrlr_properties, vs)):
if (cmd->attrib == 1)
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
else
response->value.u32.low = session->vcprop.vs;
break;
case (offsetof(struct spdk_nvmf_ctrlr_properties, intms)):
case (offsetof(struct spdk_nvmf_ctrlr_properties, intmc)):
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
break;
case (offsetof(struct spdk_nvmf_ctrlr_properties, cc)):
if (cmd->attrib == 1)
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
else
response->value.u32.low = session->vcprop.cc.raw;
break;
case (offsetof(struct spdk_nvmf_ctrlr_properties, csts)):
if (cmd->attrib == 1)
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
else
response->value.u32.low = session->vcprop.csts.raw;
break;
case (offsetof(struct spdk_nvmf_ctrlr_properties, nssr)):
if (cmd->attrib == 1)
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
else
response->value.u32.low = session->vcprop.nssr;
break;
case (offsetof(struct spdk_nvmf_ctrlr_properties, aqa)):
if (cmd->attrib == 1)
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
else
response->value.u32.low = session->vcprop.aqa.raw;
break;
case (offsetof(struct spdk_nvmf_ctrlr_properties, asq)):
case (offsetof(struct spdk_nvmf_ctrlr_properties, acq)):
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
break;
case (offsetof(struct spdk_nvmf_ctrlr_properties, propsz)):
if (cmd->attrib == 1)
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
else
response->value.u32.low = session->vcprop.propsz.raw;
break;
case (offsetof(struct spdk_nvmf_ctrlr_properties, capattr_lo)):
response->value.u32.low = session->vcprop.capattr_lo.raw;
if (cmd->attrib == 1)
response->value.u32.high = session->vcprop.capattr_hi.raw;
break;
case (offsetof(struct spdk_nvmf_ctrlr_properties, capattr_hi)):
if (cmd->attrib == 1)
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
else
response->value.u32.low = session->vcprop.capattr_hi.raw;
break;
default:
break;
prop = find_prop(cmd->ofst);
if (prop == NULL || prop->get_cb == NULL) {
/* Reserved properties return 0 when read */
return;
}
SPDK_TRACELOG(SPDK_TRACE_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.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
return;
}
response->value.u64 = prop->get_cb(session);
SPDK_TRACELOG(SPDK_TRACE_NVMF, "response value: 0x%" PRIx64 "\n", response->value.u64);
}
void
@ -470,70 +491,36 @@ nvmf_property_set(struct nvmf_session *session,
struct spdk_nvmf_fabric_prop_set_rsp *response,
bool *shutdown)
{
response->status.sc = 0;
const struct nvmf_prop *prop;
uint64_t value;
SPDK_TRACELOG(SPDK_TRACE_NVMF,
"nvmf_property_set: attrib %d, offset %x, value %lx, value low %x, value high %x\n",
cmd->attrib, cmd->ofst, cmd->value.u64, cmd->value.u32.low, cmd->value.u32.high);
SPDK_TRACELOG(SPDK_TRACE_NVMF, "size %d, offset 0x%x, value 0x%" PRIx64 "\n",
cmd->attrib.size, cmd->ofst, cmd->value.u64);
if (cmd->ofst > offsetof(struct spdk_nvmf_ctrlr_properties, capattr_hi)) {
prop = find_prop(cmd->ofst);
if (prop == NULL || prop->set_cb == NULL) {
SPDK_ERRLOG("Invalid offset 0x%x\n", cmd->ofst);
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
return;
}
/* TBD: determine which values we allow to be changed, deal with spec version
difference. Fields within 32bit value, ex. for reset in csts */
switch (cmd->ofst) {
case (offsetof(struct spdk_nvmf_ctrlr_properties, cc)): {
union spdk_nvme_cc_register cc;
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Property Set CC\n");
if (cmd->attrib == 1)
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
else {
cc.raw = cmd->value.u32.low;
if (cc.bits.en == 1 && session->vcprop.cc.bits.en == 0) {
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Property Set CC Enable!\n");
session->vcprop.csts.bits.rdy = 1;
}
if (cc.bits.shn && session->vcprop.cc.bits.shn == 0) {
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Property Set CC Shutdown!\n");
session->vcprop.cc.bits.en = 0;
*shutdown = true;
}
session->vcprop.cc.raw = cc.raw;
}
}
break;
case (offsetof(struct spdk_nvmf_ctrlr_properties, csts)):
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Property Set CSTS\n");
if (cmd->attrib == 1)
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
else
session->vcprop.csts.raw = cmd->value.u32.low;
break;
case (offsetof(struct spdk_nvmf_ctrlr_properties, nssr)):
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Property Set NSSR\n");
if (cmd->attrib == 1)
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
else
session->vcprop.nssr = cmd->value.u32.low;
break;
case (offsetof(struct spdk_nvmf_ctrlr_properties, aqa)):
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Property Set AQA\n");
if (cmd->attrib == 1)
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
else
session->vcprop.aqa.raw = cmd->value.u32.low;
break;
default:
SPDK_TRACELOG(SPDK_TRACE_NVMF, "Property Set Invalid Offset %x\n", cmd->ofst);
SPDK_TRACELOG(SPDK_TRACE_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.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
break;
return;
}
value = cmd->value.u64;
if (prop->size == SPDK_NVMF_PROP_SIZE_4) {
value = (uint32_t)value;
}
if (!prop->set_cb(session, value)) {
SPDK_ERRLOG("prop set_cb failed\n");
response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
return;
}
}

View File

@ -68,7 +68,12 @@ struct nvmf_session {
uint32_t max_io_queues; /* maximum supported by backend NVMe library */
int active_queues;
int is_valid;
struct spdk_nvmf_ctrlr_properties vcprop; /* virtual controller properties */
struct {
union spdk_nvme_cap_register cap;
union spdk_nvme_vs_register vs;
union spdk_nvme_cc_register cc;
union spdk_nvme_csts_register csts;
} vcprop; /* virtual controller properties */
struct spdk_nvme_ctrlr_data vcdata; /* virtual controller data */
TAILQ_HEAD(connection_q, nvmf_connection_entry) connections;