#include <sys/sysmacros.h>
#include <sys/nvme.h>
#include "nvme_reg.h"
#include "nvme_var.h"
typedef struct nvme_validate_info {
const nvme_field_info_t *err_fields;
size_t err_index;
uint32_t err_unuse_bit;
nvme_ioctl_errno_t err_field_range;
nvme_ioctl_errno_t err_field_unsup;
nvme_ioctl_errno_t err_field_unuse;
} nvme_validate_info_t;
static boolean_t
nvme_validate_one_field(nvme_ioctl_common_t *com, uint64_t val,
const nvme_validate_info_t *info, const nvme_valid_ctrl_data_t *data,
uint32_t valid)
{
const nvme_field_info_t *field = &info->err_fields[info->err_index];
nvme_field_error_t err;
if (val == 0) {
return (B_TRUE);
}
if (valid != 0 && info->err_unuse_bit != 0 &&
(valid & info->err_unuse_bit) == 0) {
VERIFY3U(info->err_field_unuse, !=, 0);
return (nvme_ioctl_error(com, info->err_field_unuse, 0, 0));
}
err = nvme_field_validate(field, data, val, NULL, 0);
switch (err) {
case NVME_FIELD_ERR_UNSUP_VERSION:
case NVME_FIELD_ERR_UNSUP_FIELD:
VERIFY3U(info->err_field_unsup, !=, 0);
return (nvme_ioctl_error(com, info->err_field_unsup, 0, 0));
case NVME_FIELD_ERR_BAD_VALUE:
VERIFY3U(info->err_field_range, !=, 0);
return (nvme_ioctl_error(com, info->err_field_range, 0, 0));
case NVME_FIELD_ERR_OK:
return (B_TRUE);
default:
panic("unsupported nvme_field_validate() value: 0x%x", err);
}
}
uint32_t nvme_log_page_max_size = 1 * 1024 * 1024;
static boolean_t
nvme_logpage_is_vendor(nvme_ioctl_get_logpage_t *log)
{
return (log->nigl_lid >= NVME_LOGPAGE_VEND_MIN &&
log->nigl_lid <= NVME_LOGPAGE_VEND_MAX);
}
static const nvme_validate_info_t nvme_valid_log_csi = {
nvme_log_fields, NVME_LOG_REQ_FIELD_CSI, 0,
NVME_IOCTL_E_LOG_CSI_RANGE, 0, NVME_IOCTL_E_LOG_CSI_UNSUP
};
static const nvme_validate_info_t nvme_valid_log_lid = {
nvme_log_fields, NVME_LOG_REQ_FIELD_LID, 0,
NVME_IOCTL_E_LOG_LID_RANGE, 0, 0
};
static const nvme_validate_info_t nvme_valid_log_lsp = {
nvme_log_fields, NVME_LOG_REQ_FIELD_LSP,
NVME_LOG_DISC_F_NEED_LSP, NVME_IOCTL_E_LOG_LSP_RANGE,
NVME_IOCTL_E_LOG_LSP_UNSUP, NVME_IOCTL_E_LOG_LSP_UNUSE
};
static const nvme_validate_info_t nvme_valid_log_lsi = {
nvme_log_fields, NVME_LOG_REQ_FIELD_LSI,
NVME_LOG_DISC_F_NEED_LSI, NVME_IOCTL_E_LOG_LSI_RANGE,
NVME_IOCTL_E_LOG_LSI_UNSUP, NVME_IOCTL_E_LOG_LSI_UNUSE
};
static const nvme_validate_info_t nvme_valid_log_rae = {
nvme_log_fields, NVME_LOG_REQ_FIELD_RAE,
NVME_LOG_DISC_F_NEED_RAE, NVME_IOCTL_E_LOG_RAE_RANGE,
NVME_IOCTL_E_LOG_RAE_UNSUP, NVME_IOCTL_E_LOG_RAE_UNUSE
};
static const nvme_validate_info_t nvme_valid_log_size = {
nvme_log_fields, NVME_LOG_REQ_FIELD_SIZE, 0,
NVME_IOCTL_E_LOG_SIZE_RANGE, 0, 0
};
static const nvme_validate_info_t nvme_valid_log_offset = {
nvme_log_fields, NVME_LOG_REQ_FIELD_OFFSET, 0,
NVME_IOCTL_E_LOG_OFFSET_RANGE, 0, NVME_IOCTL_E_LOG_OFFSET_UNSUP
};
static boolean_t
nvme_validate_logpage_fields(nvme_ioctl_get_logpage_t *log,
const nvme_valid_ctrl_data_t *ctrl_data, const nvme_log_page_info_t *info)
{
uint32_t disc = 0;
if (info != NULL) {
disc = info->nlpi_disc;
}
if (!nvme_validate_one_field(&log->nigl_common, log->nigl_csi,
&nvme_valid_log_csi, ctrl_data, disc)) {
return (B_FALSE);
}
if (!nvme_validate_one_field(&log->nigl_common, log->nigl_lid,
&nvme_valid_log_lid, ctrl_data, disc)) {
return (B_FALSE);
}
if (!nvme_validate_one_field(&log->nigl_common, log->nigl_lsp,
&nvme_valid_log_lsp, ctrl_data, disc)) {
return (B_FALSE);
}
if (!nvme_validate_one_field(&log->nigl_common, log->nigl_lsi,
&nvme_valid_log_lsi, ctrl_data, disc)) {
return (B_FALSE);
}
if (!nvme_validate_one_field(&log->nigl_common, log->nigl_len,
&nvme_valid_log_size, ctrl_data, disc)) {
return (B_FALSE);
}
if (log->nigl_len > nvme_log_page_max_size) {
return (nvme_ioctl_error(&log->nigl_common,
NVME_IOCTL_E_LOG_SIZE_RANGE, 0, 0));
}
if (!nvme_validate_one_field(&log->nigl_common, log->nigl_rae,
&nvme_valid_log_rae, ctrl_data, disc)) {
return (B_FALSE);
}
if (!nvme_validate_one_field(&log->nigl_common, log->nigl_offset,
&nvme_valid_log_offset, ctrl_data, disc)) {
return (B_FALSE);
}
if (info != NULL) {
bool var;
size_t targ = nvme_log_page_info_size(info, ctrl_data, &var);
if (!var) {
if (targ != 0 && targ != log->nigl_len) {
return (nvme_ioctl_error(&log->nigl_common,
NVME_IOCTL_E_LOG_SIZE_RANGE, 0, 0));
}
if (log->nigl_offset != 0) {
return (nvme_ioctl_error(&log->nigl_common,
NVME_IOCTL_E_LOG_OFFSET_RANGE, 0, 0));
}
}
}
return (B_TRUE);
}
boolean_t
nvme_validate_logpage(nvme_t *nvme, nvme_ioctl_get_logpage_t *log)
{
const nvme_log_page_info_t *info = NULL;
nvme_valid_ctrl_data_t ctrl_data;
nvme_log_disc_scope_t scope, req_scope;
ctrl_data.vcd_vers = &nvme->n_version;
ctrl_data.vcd_id = nvme->n_idctl;
if (nvme_logpage_is_vendor(log)) {
return (nvme_validate_logpage_fields(log, &ctrl_data, NULL));
}
for (size_t i = 0; i < nvme_std_log_npages; i++) {
if (nvme_std_log_pages[i].nlpi_csi == log->nigl_csi &&
nvme_std_log_pages[i].nlpi_lid == log->nigl_lid) {
info = &nvme_std_log_pages[i];
break;
}
}
if (info == NULL) {
return (nvme_ioctl_error(&log->nigl_common,
NVME_IOCTL_E_UNKNOWN_LOG_PAGE, 0, 0));
}
if (!nvme_log_page_info_supported(info, &ctrl_data)) {
return (nvme_ioctl_error(&log->nigl_common,
NVME_IOCTL_E_UNSUP_LOG_PAGE, 0, 0));
}
scope = nvme_log_page_info_scope(info, &ctrl_data);
if (log->nigl_common.nioc_nsid == NVME_NSID_BCAST) {
req_scope = NVME_LOG_SCOPE_CTRL | NVME_LOG_SCOPE_NVM;
} else {
req_scope = NVME_LOG_SCOPE_NS;
}
if ((scope & req_scope) == 0) {
return (nvme_ioctl_error(&log->nigl_common,
NVME_IOCTL_E_BAD_LOG_SCOPE, 0, 0));
}
return (nvme_validate_logpage_fields(log, &ctrl_data, info));
}
static const nvme_validate_info_t nvme_valid_get_feat_sel = {
nvme_get_feat_fields, NVME_GET_FEAT_REQ_FIELD_SEL, 0,
NVME_IOCTL_E_GET_FEAT_SEL_RANGE, NVME_IOCTL_E_GET_FEAT_SEL_UNSUP, 0
};
static const nvme_validate_info_t nvme_valid_get_feat_cdw11 = {
nvme_get_feat_fields, NVME_GET_FEAT_REQ_FIELD_CDW11,
NVME_GET_FEAT_F_CDW11, NVME_IOCTL_E_GET_FEAT_CDW11_RANGE,
0, NVME_IOCTL_E_GET_FEAT_CDW11_UNUSE
};
boolean_t
nvme_validate_get_feature(nvme_t *nvme, nvme_ioctl_get_feature_t *get)
{
const nvme_feat_info_t *feat = NULL;
const uint32_t nsid = get->nigf_common.nioc_nsid;
nvme_valid_ctrl_data_t ctrl_data;
nvme_feat_impl_t impl;
ctrl_data.vcd_vers = &nvme->n_version;
ctrl_data.vcd_id = nvme->n_idctl;
for (size_t i = 0; i < nvme_std_nfeats; i++) {
if (nvme_std_feats[i].nfeat_fid == get->nigf_fid) {
feat = &nvme_std_feats[i];
break;
}
}
if (feat == NULL) {
return (nvme_ioctl_error(&get->nigf_common,
NVME_IOCTL_E_UNKNOWN_FEATURE, 0, 0));
}
impl = nvme_feat_supported(feat, &ctrl_data);
if (impl == NVME_FEAT_IMPL_UNSUPPORTED) {
return (nvme_ioctl_error(&get->nigf_common,
NVME_IOCTL_E_UNSUP_FEATURE, 0, 0));
}
if ((feat->nfeat_in_get & NVME_GET_FEAT_F_NSID) != 0) {
if (nsid == 0 || (nsid == NVME_NSID_BCAST &&
(feat->nfeat_flags & NVME_FEAT_F_GET_BCAST_NSID) == 0)) {
return (nvme_ioctl_error(&get->nigf_common,
NVME_IOCTL_E_NS_RANGE, 0, 0));
}
} else {
if (nsid != 0) {
return (nvme_ioctl_error(&get->nigf_common,
NVME_IOCTL_E_NS_UNUSE, 0, 0));
}
}
if (!nvme_validate_one_field(&get->nigf_common, get->nigf_sel,
&nvme_valid_get_feat_sel, &ctrl_data, feat->nfeat_in_get)) {
return (B_FALSE);
}
if (get->nigf_sel == NVME_FEATURE_SEL_SUPPORTED) {
if (get->nigf_cdw11 != 0) {
return (nvme_ioctl_error(&get->nigf_common,
NVME_IOCTL_E_GET_FEAT_CDW11_UNUSE, 0, 0));
}
if (get->nigf_data != 0 || get->nigf_len != 0) {
return (nvme_ioctl_error(&get->nigf_common,
NVME_IOCTL_E_GET_FEAT_DATA_UNUSE, 0, 0));
}
return (B_TRUE);
}
if (!nvme_validate_one_field(&get->nigf_common, get->nigf_cdw11,
&nvme_valid_get_feat_cdw11, &ctrl_data, feat->nfeat_in_get)) {
return (B_FALSE);
}
if ((feat->nfeat_in_get & NVME_GET_FEAT_F_DATA) == 0) {
if (get->nigf_data != 0 || get->nigf_len != 0) {
return (nvme_ioctl_error(&get->nigf_common,
NVME_IOCTL_E_GET_FEAT_DATA_UNUSE, 0, 0));
}
} else {
if (get->nigf_data == 0 || get->nigf_len != feat->nfeat_len) {
return (nvme_ioctl_error(&get->nigf_common,
NVME_IOCTL_E_GET_FEAT_DATA_RANGE, 0, 0));
}
}
return (B_TRUE);
}
static const nvme_validate_info_t nvme_valid_identify_nsid = {
nvme_identify_fields, NVME_ID_REQ_F_NSID,
1 << NVME_ID_REQ_F_NSID, NVME_IOCTL_E_NS_RANGE, 0,
NVME_IOCTL_E_NS_UNUSE
};
static const nvme_validate_info_t nvme_valid_identify_ctrlid = {
nvme_identify_fields, NVME_ID_REQ_F_CTRLID,
1 << NVME_ID_REQ_F_CTRLID, NVME_IOCTL_E_IDENTIFY_CTRLID_RANGE,
NVME_IOCTL_E_IDENTIFY_CTRLID_UNSUP, NVME_IOCTL_E_IDENTIFY_CTRLID_UNUSE
};
boolean_t
nvme_validate_identify(nvme_t *nvme, nvme_ioctl_identify_t *id,
boolean_t ns_minor)
{
const nvme_identify_info_t *info = NULL;
nvme_valid_ctrl_data_t ctrl_data;
ctrl_data.vcd_vers = &nvme->n_version;
ctrl_data.vcd_id = nvme->n_idctl;
for (size_t i = 0; i < nvme_identify_ncmds; i++) {
if (nvme_identify_cmds[i].nii_csi == NVME_CSI_NVM &&
nvme_identify_cmds[i].nii_cns == id->nid_cns) {
info = &nvme_identify_cmds[i];
break;
}
}
if (info == NULL) {
return (nvme_ioctl_error(&id->nid_common,
NVME_IOCTL_E_UNKNOWN_IDENTIFY, 0, 0));
}
if (!nvme_identify_info_supported(info, &ctrl_data)) {
return (nvme_ioctl_error(&id->nid_common,
NVME_IOCTL_E_UNSUP_IDENTIFY, 0, 0));
}
if ((info->nii_flags & NVME_IDENTIFY_INFO_F_NS_OK) == 0 && ns_minor) {
return (nvme_ioctl_error(&id->nid_common, NVME_IOCTL_E_NOT_CTRL,
0, 0));
}
if ((info->nii_flags & NVME_IDENTIFY_INFO_F_BCAST) != 0 &&
id->nid_common.nioc_nsid == 0) {
if (nvme_ctrl_atleast(nvme, &nvme_vers_1v2) &&
nvme->n_idctl->id_oacs.oa_nsmgmt != 0) {
id->nid_common.nioc_nsid = NVME_NSID_BCAST;
} else {
id->nid_common.nioc_nsid = 1;
}
}
if ((info->nii_flags & NVME_IDENTIFY_INFO_F_NSID_LIST) == 0 &&
!nvme_validate_one_field(&id->nid_common, id->nid_common.nioc_nsid,
&nvme_valid_identify_nsid, &ctrl_data, info->nii_fields)) {
return (B_FALSE);
}
if ((info->nii_fields & (1 << NVME_ID_REQ_F_NSID)) != 0 &&
(info->nii_flags & NVME_IDENTIFY_INFO_F_NSID_LIST) == 0) {
const uint32_t ns = id->nid_common.nioc_nsid;
boolean_t allow_bcast = (info->nii_flags &
NVME_IDENTIFY_INFO_F_BCAST) != 0;
if (ns == 0 || ns > nvme->n_namespace_count) {
if (ns != NVME_NSID_BCAST) {
return (nvme_ioctl_error(&id->nid_common,
NVME_IOCTL_E_NS_RANGE, 0, 0));
} else if (!allow_bcast) {
return (nvme_ioctl_error(&id->nid_common,
NVME_IOCTL_E_NO_BCAST_NS, 0, 0));
}
}
}
if (!nvme_validate_one_field(&id->nid_common, id->nid_ctrlid,
&nvme_valid_identify_ctrlid, &ctrl_data, info->nii_fields)) {
return (B_FALSE);
}
return (B_TRUE);
}
static const nvme_validate_info_t nvme_valid_vuc_opcode = {
nvme_vuc_fields, NVME_VUC_REQ_FIELD_OPC, 0,
NVME_IOCTL_E_VUC_OPCODE_RANGE, 0, 0
};
static const nvme_validate_info_t nvme_valid_vuc_nsid = {
nvme_vuc_fields, NVME_VUC_REQ_FIELD_NSID, 0,
NVME_IOCTL_E_NS_RANGE, 0, 0
};
static const nvme_validate_info_t nvme_valid_vuc_ndt = {
nvme_vuc_fields, NVME_VUC_REQ_FIELD_NDT, 0,
NVME_IOCTL_E_VUC_NDT_RANGE, 0, 0
};
boolean_t
nvme_validate_vuc(nvme_t *nvme, nvme_ioctl_passthru_t *pass)
{
nvme_valid_ctrl_data_t ctrl_data;
const uint32_t all_flags = NVME_PASSTHRU_READ | NVME_PASSTHRU_WRITE;
const uint32_t all_impact = NVME_IMPACT_NS;
ctrl_data.vcd_vers = &nvme->n_version;
ctrl_data.vcd_id = nvme->n_idctl;
if (nvme->n_idctl->id_nvscc.nv_spec == 0) {
return (nvme_ioctl_error(&pass->npc_common,
NVME_IOCTL_E_CTRL_VUC_UNSUP, 0, 0));
}
if (pass->npc_timeout == 0 ||
pass->npc_timeout > nvme_vendor_specific_admin_cmd_max_timeout) {
return (nvme_ioctl_error(&pass->npc_common,
NVME_IOCTL_E_VUC_TIMEOUT_RANGE, 0, 0));
}
if (!nvme_validate_one_field(&pass->npc_common, pass->npc_opcode,
&nvme_valid_vuc_opcode, &ctrl_data, 0)) {
return (B_FALSE);
}
if (!nvme_validate_one_field(&pass->npc_common,
pass->npc_common.nioc_nsid, &nvme_valid_vuc_nsid, &ctrl_data, 0)) {
return (B_FALSE);
}
if ((pass->npc_flags & ~all_flags) != 0) {
return (nvme_ioctl_error(&pass->npc_common,
NVME_IOCTL_E_VUC_FLAGS_RANGE, 0, 0));
}
if ((pass->npc_impact & ~all_impact) != 0) {
return (nvme_ioctl_error(&pass->npc_common,
NVME_IOCTL_E_VUC_IMPACT_RANGE, 0, 0));
}
if (!nvme_validate_one_field(&pass->npc_common, pass->npc_buflen,
&nvme_valid_vuc_ndt, &ctrl_data, 0)) {
return (B_FALSE);
}
if (pass->npc_buflen > nvme_vendor_specific_admin_cmd_size) {
return (nvme_ioctl_error(&pass->npc_common,
NVME_IOCTL_E_VUC_NDT_RANGE, 0, 0));
}
if ((pass->npc_buflen != 0 && pass->npc_buf == 0) ||
(pass->npc_buflen == 0 && pass->npc_buf != 0)) {
return (nvme_ioctl_error(&pass->npc_common,
NVME_IOCTL_E_INCONSIST_VUC_BUF_NDT, 0, 0));
}
if ((pass->npc_buflen != 0 && pass->npc_flags == 0) ||
((pass->npc_buflen == 0 && pass->npc_flags != 0))) {
return (nvme_ioctl_error(&pass->npc_common,
NVME_IOCTL_E_INCONSIST_VUC_FLAGS_NDT, 0, 0));
}
if ((pass->npc_flags & NVME_PASSTHRU_READ) != 0 &&
(pass->npc_flags & NVME_PASSTHRU_WRITE) != 0) {
return (nvme_ioctl_error(&pass->npc_common,
NVME_IOCTL_E_VUC_FLAGS_RANGE, 0, 0));
}
return (B_TRUE);
}
static const nvme_validate_info_t nvme_valid_format_lbaf = {
nvme_format_fields, NVME_FORMAT_REQ_FIELD_LBAF, 0,
NVME_IOCTL_E_FORMAT_LBAF_RANGE, 0, 0
};
static const nvme_validate_info_t nvme_valid_format_ses = {
nvme_format_fields, NVME_FORMAT_REQ_FIELD_SES, 0,
NVME_IOCTL_E_FORMAT_SES_RANGE, 0, 0
};
boolean_t
nvme_validate_format(nvme_t *nvme, nvme_ioctl_format_t *ioc)
{
nvme_valid_ctrl_data_t ctrl_data;
const nvme_identify_nsid_t *idns;
ctrl_data.vcd_vers = &nvme->n_version;
ctrl_data.vcd_id = nvme->n_idctl;
if (!nvme_format_cmds_supported(&ctrl_data)) {
return (nvme_ioctl_error(&ioc->nif_common,
NVME_IOCTL_E_CTRL_FORMAT_UNSUP, 0, 0));
}
if (!nvme_validate_one_field(&ioc->nif_common, ioc->nif_lbaf,
&nvme_valid_format_lbaf, &ctrl_data, 0)) {
return (B_FALSE);
}
if (!nvme_validate_one_field(&ioc->nif_common, ioc->nif_ses,
&nvme_valid_format_ses, &ctrl_data, 0)) {
return (B_FALSE);
}
idns = nvme->n_idcomns;
if (ioc->nif_lbaf > idns->id_nlbaf) {
return (nvme_ioctl_error(&ioc->nif_common,
NVME_IOCTL_E_FORMAT_LBAF_RANGE, 0, 0));
}
if (idns->id_lbaf[ioc->nif_lbaf].lbaf_ms != 0) {
return (nvme_ioctl_error(&ioc->nif_common,
NVME_IOCTL_E_UNSUP_LBAF_META, 0, 0));
}
if (ioc->nif_ses == NVME_FRMT_SES_CRYPTO &&
nvme->n_idctl->id_fna.fn_crypt_erase == 0) {
return (nvme_ioctl_error(&ioc->nif_common,
NVME_IOCTL_E_CTRL_CRYPTO_SE_UNSUP, 0, 0));
}
if (ioc->nif_common.nioc_nsid == NVME_NSID_BCAST) {
return (B_TRUE);
}
if (nvme->n_idctl->id_fna.fn_format != 0) {
return (nvme_ioctl_error(&ioc->nif_common,
NVME_IOCTL_E_CTRL_NS_FORMAT_UNSUP, 0, 0));
}
if (ioc->nif_ses != NVME_FRMT_SES_NONE &&
nvme->n_idctl->id_fna.fn_sec_erase != 0) {
return (nvme_ioctl_error(&ioc->nif_common,
NVME_IOCTL_E_CTRL_NS_SE_UNSUP, 0, 0));
}
return (B_TRUE);
}
static const nvme_validate_info_t nvme_valid_fw_load_numd = {
nvme_fw_load_fields, NVME_FW_LOAD_REQ_FIELD_NUMD, 0,
NVME_IOCTL_E_FW_LOAD_LEN_RANGE, 0, 0
};
static const nvme_validate_info_t nvme_valid_fw_load_offset = {
nvme_fw_load_fields, NVME_FW_LOAD_REQ_FIELD_OFFSET, 0,
NVME_IOCTL_E_FW_LOAD_OFFSET_RANGE, 0, 0
};
boolean_t
nvme_validate_fw_load(nvme_t *nvme, nvme_ioctl_fw_load_t *fw)
{
nvme_valid_ctrl_data_t ctrl_data;
ctrl_data.vcd_vers = &nvme->n_version;
ctrl_data.vcd_id = nvme->n_idctl;
if (!nvme_fw_cmds_supported(&ctrl_data)) {
return (nvme_ioctl_error(&fw->fwl_common,
NVME_IOCTL_E_CTRL_FW_UNSUP, 0, 0));
}
if (!nvme_validate_one_field(&fw->fwl_common, fw->fwl_len,
&nvme_valid_fw_load_numd, &ctrl_data, 0)) {
return (B_FALSE);
}
if (!nvme_validate_one_field(&fw->fwl_common, fw->fwl_off,
&nvme_valid_fw_load_offset, &ctrl_data, 0)) {
return (B_FALSE);
}
return (B_TRUE);
}
static const nvme_validate_info_t nvme_valid_fw_commit_slot = {
nvme_fw_commit_fields, NVME_FW_COMMIT_REQ_FIELD_SLOT, 0,
NVME_IOCTL_E_FW_COMMIT_SLOT_RANGE, 0, 0
};
static const nvme_validate_info_t nvme_valid_fw_commit_act = {
nvme_fw_commit_fields, NVME_FW_COMMIT_REQ_FIELD_ACT, 0,
NVME_IOCTL_E_FW_COMMIT_ACTION_RANGE, 0, 0
};
boolean_t
nvme_validate_fw_commit(nvme_t *nvme, nvme_ioctl_fw_commit_t *fw)
{
nvme_valid_ctrl_data_t ctrl_data;
ctrl_data.vcd_vers = &nvme->n_version;
ctrl_data.vcd_id = nvme->n_idctl;
if (!nvme_fw_cmds_supported(&ctrl_data)) {
return (nvme_ioctl_error(&fw->fwc_common,
NVME_IOCTL_E_CTRL_FW_UNSUP, 0, 0));
}
if (!nvme_validate_one_field(&fw->fwc_common, fw->fwc_slot,
&nvme_valid_fw_commit_slot, &ctrl_data, 0)) {
return (B_FALSE);
}
if (!nvme_validate_one_field(&fw->fwc_common, fw->fwc_action,
&nvme_valid_fw_commit_act, &ctrl_data, 0)) {
return (B_FALSE);
}
if (fw->fwc_slot == 1 && nvme->n_idctl->id_frmw.fw_readonly &&
(fw->fwc_action == NVME_FWC_SAVE ||
fw->fwc_action == NVME_FWC_SAVE_ACTIVATE)) {
return (nvme_ioctl_error(&fw->fwc_common,
NVME_IOCTL_E_RO_FW_SLOT, 0, 0));
}
return (B_TRUE);
}
boolean_t
nvme_validate_ctrl_attach_detach_ns(nvme_t *nvme, nvme_ioctl_common_t *com)
{
nvme_valid_ctrl_data_t ctrl_data;
ctrl_data.vcd_vers = &nvme->n_version;
ctrl_data.vcd_id = nvme->n_idctl;
if (!nvme_fw_cmds_supported(&ctrl_data)) {
return (nvme_ioctl_error(com, NVME_IOCTL_E_CTRL_NS_MGMT_UNSUP,
0, 0));
}
return (B_TRUE);
}
boolean_t
nvme_validate_ns_delete(nvme_t *nvme, nvme_ioctl_common_t *com)
{
nvme_valid_ctrl_data_t ctrl_data;
ctrl_data.vcd_vers = &nvme->n_version;
ctrl_data.vcd_id = nvme->n_idctl;
if (!nvme_fw_cmds_supported(&ctrl_data)) {
return (nvme_ioctl_error(com, NVME_IOCTL_E_CTRL_NS_MGMT_UNSUP,
0, 0));
}
return (B_TRUE);
}
static const nvme_validate_info_t nvme_valid_ns_create_nsze = {
nvme_ns_create_fields, NVME_NS_CREATE_REQ_FIELD_NSZE, 0,
NVME_IOCTL_E_NS_CREATE_NSZE_RANGE, 0, 0
};
static const nvme_validate_info_t nvme_valid_ns_create_ncap = {
nvme_ns_create_fields, NVME_NS_CREATE_REQ_FIELD_NCAP, 0,
NVME_IOCTL_E_NS_CREATE_NCAP_RANGE, 0, 0
};
static const nvme_validate_info_t nvme_valid_ns_create_csi = {
nvme_ns_create_fields, NVME_NS_CREATE_REQ_FIELD_CSI, 0,
NVME_IOCTL_E_NS_CREATE_CSI_RANGE, NVME_IOCTL_E_NS_CREATE_CSI_UNSUP, 0
};
static const nvme_validate_info_t nvme_valid_ns_create_nmic = {
nvme_ns_create_fields, NVME_NS_CREATE_REQ_FIELD_NMIC, 0,
NVME_IOCTL_E_NS_CREATE_NMIC_RANGE, 0, 0
};
boolean_t
nvme_validate_ns_create(nvme_t *nvme, nvme_ioctl_ns_create_t *ioc)
{
const nvme_identify_nsid_t *idns = nvme->n_idcomns;
nvme_valid_ctrl_data_t ctrl_data;
ctrl_data.vcd_vers = &nvme->n_version;
ctrl_data.vcd_id = nvme->n_idctl;
if (!nvme_nsmgmt_cmds_supported(&ctrl_data)) {
return (nvme_ioctl_error(&ioc->nnc_common,
NVME_IOCTL_E_CTRL_NS_MGMT_UNSUP, 0, 0));
}
if (!nvme_validate_one_field(&ioc->nnc_common, ioc->nnc_nsze,
&nvme_valid_ns_create_nsze, &ctrl_data, 0)) {
return (B_FALSE);
}
if (!nvme_validate_one_field(&ioc->nnc_common, ioc->nnc_ncap,
&nvme_valid_ns_create_ncap, &ctrl_data, 0)) {
return (B_FALSE);
}
if (ioc->nnc_nsze > ioc->nnc_ncap && idns->id_nsfeat.f_thin == 0) {
return (nvme_ioctl_error(&ioc->nnc_common,
NVME_IOCTL_E_CTRL_THIN_PROV_UNSUP, 0, 0));
}
if (!nvme_validate_one_field(&ioc->nnc_common, ioc->nnc_csi,
&nvme_valid_ns_create_csi, &ctrl_data, 0)) {
return (B_FALSE);
}
if (ioc->nnc_csi != NVME_CSI_NVM) {
return (nvme_ioctl_error(&ioc->nnc_common,
NVME_IOCTL_E_DRV_CSI_UNSUP, 0, 0));
}
if (ioc->nnc_flbas > idns->id_nlbaf) {
return (nvme_ioctl_error(&ioc->nnc_common,
NVME_IOCTL_E_NS_CREATE_FLBAS_RANGE, 0, 0));
}
if (!nvme_validate_one_field(&ioc->nnc_common, ioc->nnc_nmic,
&nvme_valid_ns_create_nmic, &ctrl_data, 0)) {
return (B_FALSE);
}
return (B_TRUE);
}