#include <string.h>
#include <upanic.h>
#include <sys/sysmacros.h>
#include <sys/debug.h>
#include <unistd.h>
#include "libnvme_impl.h"
void
nvme_log_disc_free(nvme_log_disc_t *disc)
{
free(disc);
}
const char *
nvme_log_disc_name(const nvme_log_disc_t *disc)
{
return (disc->nld_short);
}
const char *
nvme_log_disc_desc(const nvme_log_disc_t *disc)
{
return (disc->nld_desc);
}
const char *const *
nvme_log_disc_aliases(const nvme_log_disc_t *disc)
{
return (disc->nld_aliases);
}
size_t
nvme_log_disc_naliases(const nvme_log_disc_t *disc)
{
return (disc->nld_naliases);
}
nvme_csi_t
nvme_log_disc_csi(const nvme_log_disc_t *disc)
{
return (disc->nld_csi);
}
uint32_t
nvme_log_disc_lid(const nvme_log_disc_t *disc)
{
return (disc->nld_lid);
}
nvme_log_disc_kind_t
nvme_log_disc_kind(const nvme_log_disc_t *disc)
{
return (disc->nld_kind);
}
nvme_log_disc_source_t
nvme_log_disc_sources(const nvme_log_disc_t *disc)
{
return (disc->nld_srcs);
}
nvme_log_disc_fields_t
nvme_log_disc_fields(const nvme_log_disc_t *disc)
{
return (disc->nld_fields);
}
nvme_log_disc_scope_t
nvme_log_disc_scopes(const nvme_log_disc_t *disc)
{
return (disc->nld_scope);
}
bool
nvme_log_disc_impl(const nvme_log_disc_t *disc)
{
return ((disc->nld_flags & NVME_LOG_DISC_F_IMPL) != 0);
}
nvme_log_size_kind_t
nvme_log_disc_size(const nvme_log_disc_t *disc, uint64_t *sizep)
{
*sizep = disc->nld_alloc_len;
return (disc->nld_size_kind);
}
bool
nvme_log_disc_calc_size(const nvme_log_disc_t *disc, uint64_t *act,
const void *buf, size_t buflen)
{
if (disc->nld_var_func == NULL) {
*act = disc->nld_alloc_len;
} else if (!disc->nld_var_func(act, buf, buflen)) {
return (false);
}
uint64_t orig = *act;
*act = P2ROUNDUP(orig, NVME_DWORD_SIZE);
VERIFY3U(*act, >=, orig);
return (true);
}
bool
nvme_log_disc_dup(nvme_ctrl_t *ctrl, const nvme_log_disc_t *src,
nvme_log_disc_t **discp)
{
nvme_log_disc_t *disc;
if (src == NULL) {
return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
"encountered invalid nvme_log_disc_t pointer to duplicate: "
"%p", src));
}
if (discp == NULL) {
return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
"encountered invalid nvme_log_disc_t output pointer: %p",
discp));
}
disc = calloc(1, sizeof (nvme_log_disc_t));
if (disc == NULL) {
int e = errno;
return (nvme_ctrl_error(ctrl, NVME_ERR_NO_MEM, e, "failed to "
"allocate memory for a new nvme_log_disc_t: %s",
strerror(e)));
}
(void) memcpy(disc, src, sizeof (nvme_log_disc_t));
*discp = disc;
return (nvme_ctrl_success(ctrl));
}
static bool
nvme_log_discover_validate(nvme_ctrl_t *ctrl, nvme_log_disc_scope_t scopes,
uint32_t flags)
{
const nvme_log_disc_scope_t valid_scopes = NVME_LOG_SCOPE_CTRL |
NVME_LOG_SCOPE_NVM | NVME_LOG_SCOPE_NS;
if (scopes == 0) {
return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_FLAG, 0, "no log "
"scope specified (given 0), a scope must be requested"));
}
if ((scopes & ~valid_scopes) != 0) {
return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_FLAG, 0,
"encountered invalid scope for the nvme_log_disc_scope_t: "
"0x%x", scopes & ~valid_scopes));
}
if (flags != 0) {
return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_FLAG, 0,
"encountered invalid log discovery flags: 0x%x", flags));
}
return (true);
}
static void
nvme_log_discover_fetch_sup_logs(nvme_ctrl_t *ctrl)
{
const nvme_log_page_info_t *sup_info = &nvme_std_log_pages[0];
nvme_suplog_log_t *sup = NULL;
nvme_log_req_t *req = NULL;
nvme_valid_ctrl_data_t data;
VERIFY3U(sup_info->nlpi_lid, ==, NVME_LOGPAGE_SUP);
ctrl->nc_sup_logs = NULL;
ctrl->nc_flags |= NVME_CTRL_F_SUP_LOGS_VALID;
data.vcd_vers = &ctrl->nc_vers;
data.vcd_id = &ctrl->nc_info;
if (!nvme_log_page_info_supported(sup_info, &data)) {
return;
}
sup = calloc(1, sizeof (nvme_suplog_log_t));
if (sup == NULL) {
int e = errno;
(void) nvme_ctrl_error(ctrl, NVME_ERR_NO_MEM, e, "failed to "
"allocate memory for internal log page info: %s",
strerror(e));
goto err;
}
if (!nvme_log_req_init(ctrl, &req)) {
goto err;
}
if (!nvme_log_req_set_lid(req, sup_info->nlpi_lid) ||
!nvme_log_req_set_csi(req, sup_info->nlpi_csi) ||
!nvme_log_req_set_output(req, sup, sizeof (nvme_suplog_log_t)) ||
!nvme_log_req_exec(req)) {
goto err;
}
ctrl->nc_sup_logs = sup;
nvme_log_req_fini(req);
return;
err:
ctrl->nc_flags |= NVME_CTRL_F_SUP_LOGS_FAILED;
if ((ctrl->nc_sup_logs_err = calloc(1, sizeof (nvme_err_data_t))) !=
NULL) {
nvme_ctrl_err_save(ctrl, ctrl->nc_sup_logs_err);
}
(void) nvme_ctrl_success(ctrl);
nvme_log_req_fini(req);
free(sup);
}
void
nvme_log_discover_fini(nvme_log_iter_t *iter)
{
free(iter);
}
static bool
nvme_log_discover_one(nvme_log_iter_t *iter, const nvme_log_page_info_t *info)
{
bool var;
nvme_log_disc_t *disc = &iter->nli_nld;
nvme_ctrl_t *ctrl = iter->nli_ctrl;
nvme_log_disc_scope_t scope;
nvme_valid_ctrl_data_t data;
data.vcd_vers = &iter->nli_ctrl->nc_vers;
data.vcd_id = &iter->nli_ctrl->nc_info;
scope = nvme_log_page_info_scope(info, &data);
if ((iter->nli_scope & scope) == 0) {
return (false);
}
(void) memset(disc, 0, sizeof (nvme_log_disc_t));
disc->nld_short = info->nlpi_short;
disc->nld_desc = info->nlpi_human;
disc->nld_aliases = info->nlpi_aliases;
disc->nld_naliases = info->nlpi_naliases;
disc->nld_lid = info->nlpi_lid;
disc->nld_csi = info->nlpi_csi;
disc->nld_kind = info->nlpi_kind;
disc->nld_srcs = info->nlpi_source;
disc->nld_scope = scope;
disc->nld_fields = info->nlpi_disc;
disc->nld_alloc_len = nvme_log_page_info_size(info, &data, &var);
if (disc->nld_alloc_len != 0) {
if (var) {
disc->nld_var_func = info->nlpi_var_func;
disc->nld_size_kind = NVME_LOG_SIZE_K_VAR;
} else {
disc->nld_size_kind = NVME_LOG_SIZE_K_FIXED;
}
} else {
disc->nld_size_kind = NVME_LOG_SIZE_K_UNKNOWN;
disc->nld_alloc_len = NVME_LOG_MAX_SIZE;
}
if (nvme_log_page_info_supported(info, &data) &&
(ctrl->nc_sup_logs == NULL ||
ctrl->nc_sup_logs->nl_logs[info->nlpi_lid].ns_lsupp) != 0) {
disc->nld_flags |= NVME_LOG_DISC_F_IMPL;
}
return (true);
}
nvme_iter_t
nvme_log_discover_step(nvme_log_iter_t *iter, const nvme_log_disc_t **outp)
{
*outp = NULL;
nvme_ctrl_t *ctrl = iter->nli_ctrl;
if (iter->nli_std_done && iter->nli_vs_done) {
return (NVME_ITER_DONE);
}
if (!iter->nli_std_done) {
while (iter->nli_cur_idx < nvme_std_log_npages) {
const nvme_log_page_info_t *info =
&nvme_std_log_pages[iter->nli_cur_idx];
iter->nli_cur_idx++;
if (nvme_log_discover_one(iter, info)) {
*outp = &iter->nli_nld;
return (NVME_ITER_VALID);
}
}
iter->nli_std_done = true;
iter->nli_cur_idx = 0;
}
if (ctrl->nc_vsd == NULL) {
iter->nli_vs_done = true;
return (NVME_ITER_DONE);
}
while (iter->nli_cur_idx < ctrl->nc_vsd->nvd_nlogs) {
const nvme_log_page_info_t *info =
ctrl->nc_vsd->nvd_logs[iter->nli_cur_idx];
iter->nli_cur_idx++;
if (nvme_log_discover_one(iter, info)) {
*outp = &iter->nli_nld;
return (NVME_ITER_VALID);
}
}
iter->nli_vs_done = true;
iter->nli_cur_idx = 0;
return (NVME_ITER_DONE);
}
bool
nvme_log_discover_init(nvme_ctrl_t *ctrl, nvme_log_disc_scope_t scopes,
uint32_t flags, nvme_log_iter_t **iterp)
{
nvme_log_iter_t *iter;
if (!nvme_log_discover_validate(ctrl, scopes, flags)) {
return (false);
}
if (iterp == NULL) {
return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
"encountered invalid nvme_log_iter_t output pointer: %p",
iterp));
}
iter = calloc(1, sizeof (nvme_log_iter_t));
if (iter == NULL) {
int e = errno;
return (nvme_ctrl_error(ctrl, NVME_ERR_NO_MEM, e, "failed to "
"allocate memory for a new nvme_log_iter_t: %s",
strerror(e)));
}
if ((ctrl->nc_flags & NVME_CTRL_F_SUP_LOGS_VALID) == 0) {
nvme_log_discover_fetch_sup_logs(ctrl);
}
iter->nli_ctrl = ctrl;
iter->nli_scope = scopes;
*iterp = iter;
return (nvme_ctrl_success(ctrl));
}
bool
nvme_log_discover(nvme_ctrl_t *ctrl, nvme_log_disc_scope_t scopes,
uint32_t flags, nvme_log_disc_f func, void *arg)
{
nvme_log_iter_t *iter;
nvme_iter_t ret;
const nvme_log_disc_t *disc;
if (func == NULL) {
return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
"encountered invalid nvme_log_disc_f function pointer: %p",
func));
}
if (!nvme_log_discover_init(ctrl, scopes, flags, &iter)) {
return (false);
}
while ((ret = nvme_log_discover_step(iter, &disc)) == NVME_ITER_VALID) {
if (!func(ctrl, disc, arg))
break;
}
nvme_log_discover_fini(iter);
if (ret == NVME_ITER_ERROR) {
return (false);
}
return (nvme_ctrl_success(ctrl));
}
void
nvme_log_req_fini(nvme_log_req_t *req)
{
free(req);
}
bool
nvme_log_req_init(nvme_ctrl_t *ctrl, nvme_log_req_t **reqp)
{
nvme_log_req_t *req;
if (reqp == NULL) {
return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
"encountered invalid nvme_log_req_t output pointer: %p",
reqp));
}
req = calloc(1, sizeof (nvme_log_req_t));
if (req == NULL) {
int e = errno;
return (nvme_ctrl_error(ctrl, NVME_ERR_NO_MEM, e, "failed to "
"allocate memory for a new nvme_log_req_t: %s",
strerror(e)));
}
req->nlr_ctrl = ctrl;
for (size_t i = 0; i < nvme_log_nfields; i++) {
if (nvme_log_fields[i].nlfi_def_req) {
req->nlr_need |= 1 << i;
}
if (nvme_log_fields[i].nlfi_def_allow) {
req->nlr_allow |= 1 << i;
}
}
req->nlr_flags |= NVME_LOG_REQ_F_BCAST_NS_OK;
*reqp = req;
return (nvme_ctrl_success(ctrl));
}
bool
nvme_log_req_init_by_disc(nvme_ctrl_t *ctrl, const nvme_log_disc_t *disc,
nvme_log_req_t **reqp)
{
nvme_log_req_t *req;
if (disc == NULL) {
return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
"encountered invalid nvme_log_disc_t pointer: %p", disc));
}
if (reqp == NULL) {
return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
"encountered invalid nvme_log_req_t output pointer: %p",
reqp));
}
if ((disc->nld_flags & NVME_LOG_DISC_F_IMPL) == 0) {
return (nvme_ctrl_error(ctrl, NVME_ERR_LOG_UNSUP_BY_DEV, 0,
"cannot create log request for log %s (CSI/LID 0x%x/0x%x) "
"because it is not supported by the device",
disc->nld_short, disc->nld_csi, disc->nld_lid));
}
req = calloc(1, sizeof (nvme_log_req_t));
if (req == NULL) {
int e = errno;
return (nvme_ctrl_error(ctrl, NVME_ERR_NO_MEM, e, "failed to "
"allocate memory for a new nvme_log_req_t: %s",
strerror(e)));
}
req->nlr_ctrl = ctrl;
req->nlr_lid = disc->nld_lid;
req->nlr_csi = disc->nld_csi;
req->nlr_need = req->nlr_allow = 1 << NVME_LOG_REQ_FIELD_SIZE;
req->nlr_allow |= 1 << NVME_LOG_REQ_FIELD_OFFSET;
if ((disc->nld_fields & NVME_LOG_DISC_F_NEED_LSP) != 0) {
req->nlr_need |= 1 << NVME_LOG_REQ_FIELD_LSP;
req->nlr_allow |= 1 << NVME_LOG_REQ_FIELD_LSP;
}
if ((disc->nld_fields & NVME_LOG_DISC_F_NEED_LSI) != 0) {
req->nlr_need |= 1 << NVME_LOG_REQ_FIELD_LSI;
req->nlr_allow |= 1 << NVME_LOG_REQ_FIELD_LSI;
}
if ((disc->nld_fields & NVME_LOG_DISC_F_NEED_RAE) != 0 &&
nvme_vers_ctrl_atleast(ctrl,
nvme_log_fields[NVME_LOG_REQ_FIELD_RAE].nlfi_vers)) {
req->nlr_flags |= NVME_LOG_REQ_F_RAE;
req->nlr_allow |= 1 << NVME_LOG_REQ_FIELD_RAE;
}
if ((disc->nld_scope & NVME_LOG_SCOPE_NS) != 0) {
req->nlr_allow |= 1 << NVME_LOG_REQ_FIELD_NSID;
if ((disc->nld_scope & ~NVME_LOG_SCOPE_NS) != 0) {
req->nlr_flags |= NVME_LOG_REQ_F_BCAST_NS_OK;
req->nlr_nsid = NVME_NSID_BCAST;
} else {
req->nlr_need |= 1 << NVME_LOG_REQ_FIELD_NSID;
}
}
*reqp = req;
return (nvme_ctrl_success(ctrl));
}
typedef struct {
bool nlia_found;
const char *nlia_name;
nvme_log_req_t *nlia_req;
nvme_log_disc_t **nlia_discp;
nvme_err_data_t nlia_err;
} nvme_log_init_arg_t;
static bool
nvme_log_req_match_disc(const char *name, const nvme_log_disc_t *disc)
{
if (strcmp(name, disc->nld_short) == 0) {
return (true);
}
for (size_t i = 0; i < disc->nld_naliases; i++) {
if (strcmp(name, disc->nld_aliases[i]) == 0) {
return (true);
}
}
return (false);
}
static bool
nvme_log_req_init_by_name_cb(nvme_ctrl_t *ctrl, const nvme_log_disc_t *disc,
void *arg)
{
nvme_log_init_arg_t *init = arg;
if (!nvme_log_req_match_disc(init->nlia_name, disc)) {
return (true);
}
init->nlia_found = true;
if (!nvme_log_req_init_by_disc(ctrl, disc, &init->nlia_req)) {
nvme_ctrl_err_save(ctrl, &init->nlia_err);
init->nlia_req = NULL;
} else if (init->nlia_discp != NULL) {
if (!nvme_log_disc_dup(ctrl, disc, init->nlia_discp)) {
nvme_ctrl_err_save(ctrl, &init->nlia_err);
nvme_log_req_fini(init->nlia_req);
init->nlia_req = NULL;
}
}
return (false);
}
bool
nvme_log_req_init_by_name(nvme_ctrl_t *ctrl, const char *name, uint32_t flags,
nvme_log_disc_t **discp, nvme_log_req_t **reqp)
{
nvme_log_init_arg_t init;
if (reqp == NULL) {
return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
"encountered invalid nvme_log_req_t output pointer: %p",
reqp));
}
if (name == NULL) {
return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
"encountered invalid pointer for log page name: %p", name));
}
(void) memset(&init, 0, sizeof (init));
init.nlia_name = name;
init.nlia_discp = discp;
if (!nvme_log_discover(ctrl, NVME_LOG_SCOPE_CTRL |
NVME_LOG_SCOPE_NVM | NVME_LOG_SCOPE_NS, flags,
nvme_log_req_init_by_name_cb, &init)) {
return (false);
}
if (!init.nlia_found) {
return (nvme_ctrl_error(ctrl, NVME_ERR_LOG_NAME_UNKNOWN, 0,
"failed to find log page with name %s", name));
}
if (init.nlia_req == NULL) {
nvme_ctrl_err_set(ctrl, &init.nlia_err);
return (false);
}
*reqp = init.nlia_req;
return (nvme_ctrl_success(ctrl));
}
static void
nvme_log_req_set_need(nvme_log_req_t *req, nvme_log_req_field_t field)
{
req->nlr_need |= 1 << field;
}
static void
nvme_log_req_clear_need(nvme_log_req_t *req, nvme_log_req_field_t field)
{
req->nlr_need &= ~(1 << field);
}
static const nvme_field_check_t nvme_log_check_lid = {
nvme_log_fields, NVME_LOG_REQ_FIELD_LID,
NVME_ERR_LOG_LID_RANGE, 0, 0
};
bool
nvme_log_req_set_lid(nvme_log_req_t *req, uint32_t lid)
{
if (!nvme_field_check_one(req->nlr_ctrl, lid, "get log page",
&nvme_log_check_lid, req->nlr_allow)) {
return (false);
}
req->nlr_lid = lid;
nvme_log_req_clear_need(req, NVME_LOG_REQ_FIELD_LID);
return (nvme_ctrl_success(req->nlr_ctrl));
}
static const nvme_field_check_t nvme_log_check_lsp = {
nvme_log_fields, NVME_LOG_REQ_FIELD_LSP,
NVME_ERR_LOG_LSP_RANGE, NVME_ERR_LOG_LSP_UNSUP,
NVME_ERR_LOG_LSP_UNUSE
};
bool
nvme_log_req_set_lsp(nvme_log_req_t *req, uint32_t lsp)
{
if (!nvme_field_check_one(req->nlr_ctrl, lsp, "get log page",
&nvme_log_check_lsp, req->nlr_allow)) {
return (false);
}
req->nlr_lsp = lsp;
nvme_log_req_clear_need(req, NVME_LOG_REQ_FIELD_LSP);
return (nvme_ctrl_success(req->nlr_ctrl));
}
static const nvme_field_check_t nvme_log_check_lsi = {
nvme_log_fields, NVME_LOG_REQ_FIELD_LSI,
NVME_ERR_LOG_LSI_RANGE, NVME_ERR_LOG_LSI_UNSUP,
NVME_ERR_LOG_LSI_UNUSE
};
bool
nvme_log_req_set_lsi(nvme_log_req_t *req, uint32_t lsi)
{
if (!nvme_field_check_one(req->nlr_ctrl, lsi, "get log page",
&nvme_log_check_lsi, req->nlr_allow)) {
return (false);
}
req->nlr_lsi = lsi;
nvme_log_req_clear_need(req, NVME_LOG_REQ_FIELD_LSI);
return (nvme_ctrl_success(req->nlr_ctrl));
}
static const nvme_field_check_t nvme_log_check_csi = {
nvme_log_fields, NVME_LOG_REQ_FIELD_CSI,
NVME_ERR_LOG_CSI_RANGE, NVME_ERR_LOG_CSI_UNSUP, 0
};
bool
nvme_log_req_set_csi(nvme_log_req_t *req, nvme_csi_t csi)
{
if (!nvme_field_check_one(req->nlr_ctrl, csi, "get log page",
&nvme_log_check_csi, req->nlr_allow)) {
return (false);
}
req->nlr_csi = csi;
nvme_log_req_clear_need(req, NVME_LOG_REQ_FIELD_CSI);
return (nvme_ctrl_success(req->nlr_ctrl));
}
static const nvme_field_check_t nvme_log_check_size = {
nvme_log_fields, NVME_LOG_REQ_FIELD_SIZE,
NVME_ERR_LOG_SIZE_RANGE, 0, 0
};
bool
nvme_log_req_set_output(nvme_log_req_t *req, void *buf, size_t buflen)
{
if (buf == NULL) {
return (nvme_ctrl_error(req->nlr_ctrl, NVME_ERR_BAD_PTR, 0,
"log request output buffer cannot be NULL"));
}
if (!nvme_field_check_one(req->nlr_ctrl, buflen, "get log page",
&nvme_log_check_size, req->nlr_allow)) {
return (false);
}
req->nlr_output = buf;
req->nlr_output_len = buflen;
nvme_log_req_clear_need(req, NVME_LOG_REQ_FIELD_SIZE);
return (nvme_ctrl_success(req->nlr_ctrl));
}
bool
nvme_log_req_clear_output(nvme_log_req_t *req)
{
req->nlr_output = NULL;
req->nlr_output_len = 0;
nvme_log_req_set_need(req, NVME_LOG_REQ_FIELD_SIZE);
return (nvme_ctrl_success(req->nlr_ctrl));
}
static const nvme_field_check_t nvme_log_check_offset = {
nvme_log_fields, NVME_LOG_REQ_FIELD_OFFSET,
NVME_ERR_LOG_OFFSET_RANGE, 0, 0
};
bool
nvme_log_req_set_offset(nvme_log_req_t *req, uint64_t off)
{
if (!nvme_field_check_one(req->nlr_ctrl, off, "get log page",
&nvme_log_check_offset, req->nlr_allow)) {
return (false);
}
req->nlr_offset = off;
nvme_log_req_clear_need(req, NVME_LOG_REQ_FIELD_OFFSET);
return (nvme_ctrl_success(req->nlr_ctrl));
}
static const nvme_field_check_t nvme_log_check_nsid = {
nvme_log_fields, NVME_LOG_REQ_FIELD_NSID, NVME_ERR_NS_RANGE, 0, 0
};
bool
nvme_log_req_set_nsid(nvme_log_req_t *req, uint32_t nsid)
{
nvme_ctrl_t *ctrl = req->nlr_ctrl;
if (nsid == NVME_NSID_BCAST &&
(req->nlr_flags & NVME_LOG_REQ_F_BCAST_NS_OK) == 0) {
return (nvme_ctrl_error(ctrl, NVME_ERR_NS_RANGE, 0, "the all "
"namespaces/controller nsid (0x%x) is not allowed for this "
"log page, valid namespaces are [0x%x, 0x%x]", nsid,
NVME_NSID_MIN, req->nlr_ctrl->nc_info.id_nn));
}
if (!nvme_field_check_one(req->nlr_ctrl, nsid, "get log page",
&nvme_log_check_nsid, req->nlr_allow)) {
return (false);
}
req->nlr_nsid = nsid;
nvme_log_req_clear_need(req, NVME_LOG_REQ_FIELD_NSID);
return (nvme_ctrl_success(req->nlr_ctrl));
}
static const nvme_field_check_t nvme_log_check_rae = {
nvme_log_fields, NVME_LOG_REQ_FIELD_RAE,
NVME_ERR_LOG_RAE_RANGE, NVME_ERR_LOG_RAE_UNSUP,
NVME_ERR_LOG_RAE_UNUSE
};
bool
nvme_log_req_set_rae(nvme_log_req_t *req, bool rae)
{
if (!nvme_field_check_one(req->nlr_ctrl, rae, "get log page",
&nvme_log_check_rae, req->nlr_allow)) {
return (false);
}
if (rae) {
req->nlr_flags |= NVME_LOG_REQ_F_RAE;
} else {
req->nlr_flags &= ~NVME_LOG_REQ_F_RAE;
}
nvme_log_req_clear_need(req, NVME_LOG_REQ_FIELD_RAE);
return (nvme_ctrl_success(req->nlr_ctrl));
}
bool
nvme_log_req_exec(nvme_log_req_t *req)
{
nvme_ctrl_t *ctrl = req->nlr_ctrl;
nvme_ioctl_get_logpage_t log;
if (req->nlr_need != 0) {
return (nvme_field_miss_err(ctrl, nvme_log_fields,
nvme_log_nfields, NVME_ERR_LOG_REQ_MISSING_FIELDS,
"get log page", req->nlr_need));
}
(void) memset(&log, 0, sizeof (nvme_ioctl_get_logpage_t));
log.nigl_common.nioc_nsid = req->nlr_nsid;
log.nigl_csi = req->nlr_csi;
log.nigl_lid = req->nlr_lid;
log.nigl_lsp = req->nlr_lsp;
log.nigl_lsi = req->nlr_lsi;
if ((req->nlr_flags & NVME_LOG_REQ_F_RAE) != 0) {
log.nigl_rae = 1;
}
log.nigl_len = req->nlr_output_len;
log.nigl_offset = req->nlr_offset;
log.nigl_data = (uintptr_t)req->nlr_output;
if (ioctl(ctrl->nc_fd, NVME_IOC_GET_LOGPAGE, &log) != 0) {
int e = errno;
return (nvme_ioctl_syserror(ctrl, e, "get log page"));
}
if (log.nigl_common.nioc_drv_err != NVME_IOCTL_E_OK) {
return (nvme_ioctl_error(ctrl, &log.nigl_common,
"get log page"));
}
return (nvme_ctrl_success(ctrl));
}