#include "nvme_common.h"
#include <sys/sysmacros.h>
#ifdef _KERNEL
#include <sys/sunddi.h>
#include <sys/stdint.h>
#else
#include <stdio.h>
#include <inttypes.h>
#endif
static bool
nvme_get_feat_supported_sel(const nvme_field_info_t *field,
const nvme_valid_ctrl_data_t *data, char *msg, size_t msglen)
{
if (data->vcd_id->id_oncs.on_save != 0) {
return (true);
}
(void) snprintf(msg, msglen, "controller does not support field %s "
"(%s): missing extended data support in Log Page Attributes (LPA)",
field->nlfi_human, field->nlfi_spec);
return (false);
}
const nvme_field_info_t nvme_get_feat_fields[] = {
[NVME_GET_FEAT_REQ_FIELD_FID] = {
.nlfi_vers = &nvme_vers_1v0,
.nlfi_max_size = NVME_FEAT_MAX_FID,
.nlfi_spec = "fid",
.nlfi_human = "feature identifier",
.nlfi_def_req = true,
.nlfi_def_allow = true
},
[NVME_GET_FEAT_REQ_FIELD_SEL] = {
.nlfi_vers = &nvme_vers_1v1,
.nlfi_sup = nvme_get_feat_supported_sel,
.nlfi_max_size = NVME_FEAT_MAX_SEL,
.nlfi_spec = "sel",
.nlfi_human = "select",
.nlfi_def_req = false,
.nlfi_def_allow = true
},
[NVME_GET_FEAT_REQ_FIELD_CDW11] = {
.nlfi_vers = &nvme_vers_1v0,
.nlfi_max_size = UINT32_MAX,
.nlfi_spec = "cdw11",
.nlfi_human = "control dword 11",
.nlfi_def_req = false,
.nlfi_def_allow = true
},
[NVME_GET_FEAT_REQ_FIELD_NSID] = {
.nlfi_vers = &nvme_vers_1v0,
.nlfi_valid = nvme_field_valid_nsid,
.nlfi_spec = "nsid",
.nlfi_human = "namespace ID",
.nlfi_def_req = false,
.nlfi_def_allow = true
}
};
const size_t nvme_get_feat_nfields = ARRAY_SIZE(nvme_get_feat_fields);
static bool
nvme_feat_write_cache_sup(const nvme_valid_ctrl_data_t *data,
const nvme_feat_info_t *feat)
{
return (data->vcd_id->id_vwc.vwc_present != 0);
}
static bool
nvme_feat_apst_sup(const nvme_valid_ctrl_data_t *data,
const nvme_feat_info_t *feat)
{
return (data->vcd_id->id_apsta.ap_sup != 0);
}
const nvme_feat_info_t nvme_std_feats[] = { {
.nfeat_short = "arb",
.nfeat_spec = "Arbitration",
.nfeat_fid = NVME_FEAT_ARBITRATION,
.nfeat_vers = &nvme_vers_1v0,
.nfeat_kind = NVME_FEAT_MANDATORY,
.nfeat_scope = NVME_FEAT_SCOPE_CTRL,
.nfeat_in_set = NVME_SET_FEAT_F_CDW11,
.nfeat_out_get = NVME_FEAT_OUTPUT_CDW0
}, {
.nfeat_short = "pm",
.nfeat_spec = "Power Management",
.nfeat_fid = NVME_FEAT_POWER_MGMT,
.nfeat_vers = &nvme_vers_1v0,
.nfeat_kind = NVME_FEAT_MANDATORY,
.nfeat_scope = NVME_FEAT_SCOPE_CTRL,
.nfeat_in_set = NVME_SET_FEAT_F_CDW11,
.nfeat_out_get = NVME_FEAT_OUTPUT_CDW0
}, {
.nfeat_short = "range",
.nfeat_spec = "LBA Range Type",
.nfeat_fid = NVME_FEAT_LBA_RANGE,
.nfeat_vers = &nvme_vers_1v0,
.nfeat_kind = NVME_FEAT_OPTIONAL,
.nfeat_scope = NVME_FEAT_SCOPE_NS,
.nfeat_csi = NVME_FEAT_CSI_NVM,
.nfeat_in_get = NVME_GET_FEAT_F_NSID | NVME_GET_FEAT_F_DATA,
.nfeat_in_set = NVME_SET_FEAT_F_NSID | NVME_SET_FEAT_F_CDW11 |
NVME_SET_FEAT_F_DATA,
.nfeat_out_get = NVME_FEAT_OUTPUT_CDW0 | NVME_FEAT_OUTPUT_DATA,
.nfeat_len = NVME_LBA_RANGE_BUFSIZE
}, {
.nfeat_short = "temp",
.nfeat_spec = "Temperature Threshold",
.nfeat_fid = NVME_FEAT_TEMPERATURE,
.nfeat_vers = &nvme_vers_1v0,
.nfeat_kind = NVME_FEAT_MANDATORY,
.nfeat_scope = NVME_FEAT_SCOPE_CTRL,
.nfeat_in_get = NVME_GET_FEAT_F_CDW11,
.nfeat_in_set = NVME_SET_FEAT_F_CDW11,
.nfeat_out_get = NVME_FEAT_OUTPUT_CDW0
}, {
.nfeat_short = "errrec",
.nfeat_spec = "Error Recovery",
.nfeat_fid = NVME_FEAT_ERROR,
.nfeat_vers = &nvme_vers_1v0,
.nfeat_csi = NVME_FEAT_CSI_NVM,
.nfeat_kind = NVME_FEAT_MANDATORY,
.nfeat_scope = NVME_FEAT_SCOPE_NS,
.nfeat_in_get = NVME_GET_FEAT_F_NSID,
.nfeat_in_set = NVME_SET_FEAT_F_NSID | NVME_SET_FEAT_F_CDW11,
.nfeat_out_get = NVME_FEAT_OUTPUT_CDW0
}, {
.nfeat_short = "cache",
.nfeat_spec = "Volatile Write Cache",
.nfeat_fid = NVME_FEAT_WRITE_CACHE,
.nfeat_sup_func = nvme_feat_write_cache_sup,
.nfeat_vers = &nvme_vers_1v0,
.nfeat_kind = NVME_FEAT_OPTIONAL,
.nfeat_scope = NVME_FEAT_SCOPE_CTRL,
.nfeat_in_set = NVME_SET_FEAT_F_CDW11,
.nfeat_out_get = NVME_FEAT_OUTPUT_CDW0
}, {
.nfeat_short = "queues",
.nfeat_spec = "Number of Queues",
.nfeat_fid = NVME_FEAT_NQUEUES,
.nfeat_vers = &nvme_vers_1v0,
.nfeat_kind = NVME_FEAT_MANDATORY,
.nfeat_scope = NVME_FEAT_SCOPE_CTRL,
.nfeat_in_set = NVME_SET_FEAT_F_CDW11,
.nfeat_out_get = NVME_FEAT_OUTPUT_CDW0
}, {
.nfeat_short = "coalescing",
.nfeat_spec = "Interrupt Coalescing",
.nfeat_fid = NVME_FEAT_INTR_COAL,
.nfeat_vers = &nvme_vers_1v0,
.nfeat_kind = NVME_FEAT_MANDATORY,
.nfeat_scope = NVME_FEAT_SCOPE_CTRL,
.nfeat_in_set = NVME_SET_FEAT_F_CDW11,
.nfeat_out_get = NVME_FEAT_OUTPUT_CDW0
}, {
.nfeat_short = "vector",
.nfeat_spec = "Interrupt Vector Configuration",
.nfeat_fid = NVME_FEAT_INTR_VECT,
.nfeat_vers = &nvme_vers_1v0,
.nfeat_kind = NVME_FEAT_MANDATORY,
.nfeat_scope = NVME_FEAT_SCOPE_CTRL,
.nfeat_in_get = NVME_GET_FEAT_F_CDW11,
.nfeat_in_set = NVME_SET_FEAT_F_CDW11,
.nfeat_out_get = NVME_FEAT_OUTPUT_CDW0
}, {
.nfeat_short = "atomicity",
.nfeat_spec = "Write Atomicity",
.nfeat_fid = NVME_FEAT_WRITE_ATOM,
.nfeat_vers = &nvme_vers_1v0,
.nfeat_kind = NVME_FEAT_MANDATORY,
.nfeat_scope = NVME_FEAT_SCOPE_CTRL,
.nfeat_in_set = NVME_SET_FEAT_F_CDW11,
.nfeat_out_get = NVME_FEAT_OUTPUT_CDW0
}, {
.nfeat_short = "event",
.nfeat_spec = "Asynchronous Event Configuration",
.nfeat_fid = NVME_FEAT_ASYNC_EVENT,
.nfeat_vers = &nvme_vers_1v0,
.nfeat_kind = NVME_FEAT_MANDATORY,
.nfeat_scope = NVME_FEAT_SCOPE_CTRL,
.nfeat_in_set = NVME_SET_FEAT_F_CDW11,
.nfeat_out_get = NVME_FEAT_OUTPUT_CDW0
}, {
.nfeat_short = "apst",
.nfeat_spec = "Autonomous Power State Transition",
.nfeat_fid = NVME_FEAT_AUTO_PST,
.nfeat_vers = &nvme_vers_1v1,
.nfeat_sup_func = nvme_feat_apst_sup,
.nfeat_kind = NVME_FEAT_OPTIONAL,
.nfeat_scope = NVME_FEAT_SCOPE_CTRL,
.nfeat_in_get = NVME_GET_FEAT_F_DATA,
.nfeat_in_set = NVME_SET_FEAT_F_CDW11 | NVME_SET_FEAT_F_DATA,
.nfeat_out_get = NVME_FEAT_OUTPUT_CDW0 | NVME_FEAT_OUTPUT_DATA,
.nfeat_len = NVME_AUTO_PST_BUFSIZE
}, {
.nfeat_short = "progress",
.nfeat_spec = "Software Progress Marker",
.nfeat_fid = NVME_FEAT_PROGRESS,
.nfeat_vers = &nvme_vers_1v0,
.nfeat_kind = NVME_FEAT_OPTIONAL,
.nfeat_scope = NVME_FEAT_SCOPE_CTRL,
.nfeat_in_set = NVME_SET_FEAT_F_CDW11,
.nfeat_out_get = NVME_FEAT_OUTPUT_CDW0
}, {
.nfeat_short = "hostsup",
.nfeat_spec = "Host Behavior Support",
.nfeat_fid = NVME_FEAT_HOST_BEHAVE,
.nfeat_vers = &nvme_vers_1v4,
.nfeat_kind = NVME_FEAT_OPTIONAL,
.nfeat_scope = NVME_FEAT_SCOPE_CTRL,
.nfeat_in_get = NVME_GET_FEAT_F_DATA,
.nfeat_in_set = NVME_SET_FEAT_F_DATA,
.nfeat_out_get = NVME_FEAT_OUTPUT_DATA,
.nfeat_len = sizeof (nvme_host_behavior_t)
} };
const size_t nvme_std_nfeats = ARRAY_SIZE(nvme_std_feats);
nvme_feat_impl_t
nvme_feat_supported(const nvme_feat_info_t *info,
const nvme_valid_ctrl_data_t *data)
{
if (info->nfeat_kind == NVME_FEAT_VENDOR_SPECIFIC) {
return (NVME_FEAT_IMPL_SUPPORTED);
}
if (info->nfeat_vers != NULL &&
!nvme_vers_atleast(data->vcd_vers, info->nfeat_vers)) {
return (NVME_FEAT_IMPL_UNSUPPORTED);
}
if (info->nfeat_kind == NVME_FEAT_MANDATORY) {
ASSERT3P(info->nfeat_sup_func, ==, NULL);
return (NVME_FEAT_IMPL_SUPPORTED);
}
if (info->nfeat_sup_func != NULL) {
if (info->nfeat_sup_func(data, info)) {
return (NVME_FEAT_IMPL_SUPPORTED);
}
return (NVME_FEAT_IMPL_UNSUPPORTED);
}
return (NVME_FEAT_IMPL_UNKNOWN);
}