#include <string.h>
#include <unistd.h>
#include "libnvme_impl.h"
void
nvme_ns_attach_req_fini(nvme_ns_attach_req_t *req)
{
free(req);
}
static void
nvme_ns_attach_req_clear_need(nvme_ns_attach_req_t *req,
nvme_ns_attach_req_field_t field)
{
req->nar_need &= ~(1 << field);
}
bool
nvme_ns_attach_req_init_by_sel(nvme_ctrl_t *ctrl, uint32_t sel,
nvme_ns_attach_req_t **reqp)
{
nvme_ns_attach_req_t *req;
nvme_valid_ctrl_data_t ctrl_data;
if (reqp == NULL) {
return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
"encountered invalid nvme_ns_attach_req_t output pointer: "
"%p", reqp));
}
ctrl_data.vcd_vers = &ctrl->nc_vers;
ctrl_data.vcd_id = &ctrl->nc_info;
if (!nvme_nsmgmt_cmds_supported(&ctrl_data)) {
return (nvme_ctrl_error(ctrl, NVME_ERR_NS_MGMT_UNSUP_BY_DEV, 0,
"controller does not support namespace management"));
}
if (sel != NVME_NS_ATTACH_CTRL_ATTACH &&
sel != NVME_NS_ATTACH_CTRL_DETACH) {
return (nvme_ctrl_error(ctrl, NVME_ERR_NS_ATTACH_BAD_SEL, 0,
"the system (and possibly device) does not support "
"attaching namespaces with selector 0x%x", sel));
}
req = calloc(1, sizeof (nvme_ns_attach_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_ns_attach_req_t: %s",
strerror(e)));
}
req->nar_ctrl = ctrl;
req->nar_sel = sel;
for (size_t i = 0; i < nvme_ns_attach_nfields; i++) {
if (nvme_ns_attach_fields[i].nlfi_def_req) {
req->nar_need |= 1 << i;
}
}
nvme_ns_attach_req_clear_need(req, NVME_NS_ATTACH_REQ_FIELD_SEL);
*reqp = req;
return (nvme_ctrl_success(ctrl));
}
static const nvme_field_check_t nvme_ns_attach_check_nsid = {
nvme_ns_attach_fields, NVME_NS_ATTACH_REQ_FIELD_NSID,
NVME_ERR_NS_RANGE, 0, 0
};
bool
nvme_ns_attach_req_set_nsid(nvme_ns_attach_req_t *req, uint32_t nsid)
{
if (!nvme_field_check_one(req->nar_ctrl, nsid, "namespace attach",
&nvme_ns_attach_check_nsid, 0)) {
return (false);
}
req->nar_nsid = nsid;
nvme_ns_attach_req_clear_need(req, NVME_NS_ATTACH_REQ_FIELD_NSID);
return (nvme_ctrl_success(req->nar_ctrl));
}
bool
nvme_ns_attach_req_set_ctrlid_self(nvme_ns_attach_req_t *req)
{
nvme_ns_attach_req_clear_need(req, NVME_NS_ATTACH_REQ_FIELD_DPTR);
return (nvme_ctrl_success(req->nar_ctrl));
}
bool
nvme_ns_attach_req_exec(nvme_ns_attach_req_t *req)
{
nvme_ctrl_t *ctrl = req->nar_ctrl;
nvme_ioctl_common_t common;
int code;
if (req->nar_need != 0) {
return (nvme_field_miss_err(ctrl, nvme_ns_attach_fields,
nvme_ns_attach_nfields,
NVME_ERR_NS_ATTACH_REQ_MISSING_FIELDS, "namespace attach",
req->nar_need));
}
(void) memset(&common, 0, sizeof (common));
common.nioc_nsid = req->nar_nsid;
code = req->nar_sel == NVME_NS_ATTACH_CTRL_ATTACH ?
NVME_IOC_CTRL_ATTACH : NVME_IOC_CTRL_DETACH;
if (ioctl(ctrl->nc_fd, code, &common) != 0) {
int e = errno;
return (nvme_ioctl_syserror(ctrl, e, "namespace attach"));
}
if (common.nioc_drv_err != NVME_IOCTL_E_OK) {
return (nvme_ioctl_error(ctrl, &common, "namespace attach"));
}
return (nvme_ctrl_success(ctrl));
}
void
nvme_ns_delete_req_fini(nvme_ns_delete_req_t *req)
{
free(req);
}
bool
nvme_ns_delete_req_init(nvme_ctrl_t *ctrl, nvme_ns_delete_req_t **reqp)
{
nvme_ns_delete_req_t *req;
nvme_valid_ctrl_data_t ctrl_data;
if (reqp == NULL) {
return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
"encountered invalid nvme_ns_delete_req_t output pointer: "
"%p", reqp));
}
ctrl_data.vcd_vers = &ctrl->nc_vers;
ctrl_data.vcd_id = &ctrl->nc_info;
if (!nvme_nsmgmt_cmds_supported(&ctrl_data)) {
return (nvme_ctrl_error(ctrl, NVME_ERR_NS_MGMT_UNSUP_BY_DEV, 0,
"controller does not support namespace management"));
}
req = calloc(1, sizeof (nvme_ns_delete_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_ns_delete_req_t: %s",
strerror(e)));
}
req->ndr_ctrl = ctrl;
for (size_t i = 0; i < nvme_ns_delete_nfields; i++) {
if (nvme_ns_delete_fields[i].nlfi_def_req) {
req->ndr_need |= 1 << i;
}
}
*reqp = req;
return (nvme_ctrl_success(ctrl));
}
static void
nvme_ns_delete_req_clear_need(nvme_ns_delete_req_t *req,
nvme_ns_delete_req_field_t field)
{
req->ndr_need &= ~(1 << field);
}
static const nvme_field_check_t nvme_ns_delete_check_nsid = {
nvme_ns_delete_fields, NVME_NS_DELETE_REQ_FIELD_NSID,
NVME_ERR_NS_RANGE, 0, 0
};
bool
nvme_ns_delete_req_set_nsid(nvme_ns_delete_req_t *req, uint32_t nsid)
{
if (!nvme_field_check_one(req->ndr_ctrl, nsid, "namespace delete",
&nvme_ns_delete_check_nsid, 0)) {
return (false);
}
req->ndr_nsid = nsid;
nvme_ns_delete_req_clear_need(req, NVME_NS_DELETE_REQ_FIELD_NSID);
return (nvme_ctrl_success(req->ndr_ctrl));
}
bool
nvme_ns_delete_req_exec(nvme_ns_delete_req_t *req)
{
nvme_ctrl_t *ctrl = req->ndr_ctrl;
nvme_ioctl_common_t common;
if (req->ndr_need != 0) {
return (nvme_field_miss_err(ctrl, nvme_ns_delete_fields,
nvme_ns_delete_nfields,
NVME_ERR_NS_DELETE_REQ_MISSING_FIELDS, "namespace delete",
req->ndr_need));
}
(void) memset(&common, 0, sizeof (common));
common.nioc_nsid = req->ndr_nsid;
if (ioctl(ctrl->nc_fd, NVME_IOC_NS_DELETE, &common) != 0) {
int e = errno;
return (nvme_ioctl_syserror(ctrl, e, "namespace delete"));
}
if (common.nioc_drv_err != NVME_IOCTL_E_OK) {
return (nvme_ioctl_error(ctrl, &common, "namespace delete"));
}
return (nvme_ctrl_success(ctrl));
}
void
nvme_ns_create_req_fini(nvme_ns_create_req_t *req)
{
free(req);
}
bool
nvme_ns_create_req_init_by_csi(nvme_ctrl_t *ctrl, nvme_csi_t csi,
nvme_ns_create_req_t **reqp)
{
nvme_ns_create_req_t *req;
nvme_valid_ctrl_data_t ctrl_data;
if (reqp == NULL) {
return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
"encountered invalid nvme_ns_create_req_t output pointer: "
"%p", reqp));
}
ctrl_data.vcd_vers = &ctrl->nc_vers;
ctrl_data.vcd_id = &ctrl->nc_info;
if (!nvme_nsmgmt_cmds_supported(&ctrl_data)) {
return (nvme_ctrl_error(ctrl, NVME_ERR_NS_MGMT_UNSUP_BY_DEV, 0,
"controller does not support namespace management"));
}
if (csi != NVME_CSI_NVM) {
return (nvme_ctrl_error(ctrl, NVME_ERR_NS_CREATE_BAD_CSI, 0,
"the system (and possibly device) does not support "
"creating namespaces with CSI 0x%x", csi));
}
req = calloc(1, sizeof (nvme_ns_create_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_ns_create_req_t: %s",
strerror(e)));
}
for (size_t i = 0; i < nvme_ns_create_fields_nvm_nreq; i++) {
req->ncr_need |= 1 << nvme_ns_create_fields_nvm_req[i];
}
for (size_t i = 0; i < nvme_ns_create_fields_nvm_nallow; i++) {
req->ncr_allow |= 1 << nvme_ns_create_fields_nvm_allow[i];
}
req->ncr_ctrl = ctrl;
req->ncr_csi = csi;
*reqp = req;
return (nvme_ctrl_success(ctrl));
}
static void
nvme_ns_create_req_clear_need(nvme_ns_create_req_t *req,
nvme_ns_create_req_field_t field)
{
req->ncr_need &= ~(1 << field);
}
static const nvme_field_check_t nvme_ns_create_check_flbas = {
nvme_ns_create_fields, NVME_NS_CREATE_REQ_FIELD_FLBAS,
NVME_ERR_NS_CREATE_FLBAS_RANGE, 0, 0
};
bool
nvme_ns_create_req_set_flbas(nvme_ns_create_req_t *req, uint32_t flbas)
{
if (!nvme_field_check_one(req->ncr_ctrl, flbas, "namespace create",
&nvme_ns_create_check_flbas, req->ncr_allow)) {
return (false);
}
req->ncr_flbas = flbas;
nvme_ns_create_req_clear_need(req, NVME_NS_CREATE_REQ_FIELD_FLBAS);
return (nvme_ctrl_success(req->ncr_ctrl));
}
static const nvme_field_check_t nvme_ns_create_check_nsze = {
nvme_ns_create_fields, NVME_NS_CREATE_REQ_FIELD_NSZE,
NVME_ERR_NS_CREATE_NSZE_RANGE, 0, 0
};
bool
nvme_ns_create_req_set_nsze(nvme_ns_create_req_t *req, uint64_t nsze)
{
if (!nvme_field_check_one(req->ncr_ctrl, nsze, "namespace create",
&nvme_ns_create_check_nsze, req->ncr_allow)) {
return (false);
}
req->ncr_nsze = nsze;
nvme_ns_create_req_clear_need(req, NVME_NS_CREATE_REQ_FIELD_NSZE);
return (nvme_ctrl_success(req->ncr_ctrl));
}
static const nvme_field_check_t nvme_ns_create_check_ncap = {
nvme_ns_create_fields, NVME_NS_CREATE_REQ_FIELD_NCAP,
NVME_ERR_NS_CREATE_NCAP_RANGE, 0, 0
};
bool
nvme_ns_create_req_set_ncap(nvme_ns_create_req_t *req, uint64_t ncap)
{
if (!nvme_field_check_one(req->ncr_ctrl, ncap, "namespace create",
&nvme_ns_create_check_ncap, req->ncr_allow)) {
return (false);
}
req->ncr_ncap = ncap;
nvme_ns_create_req_clear_need(req, NVME_NS_CREATE_REQ_FIELD_NCAP);
return (nvme_ctrl_success(req->ncr_ctrl));
}
static const nvme_field_check_t nvme_ns_create_check_nmic = {
nvme_ns_create_fields, NVME_NS_CREATE_REQ_FIELD_NMIC,
NVME_ERR_NS_CREATE_NMIC_RANGE, 0, 0
};
bool
nvme_ns_create_req_set_nmic(nvme_ns_create_req_t *req, uint32_t nmic)
{
if (!nvme_field_check_one(req->ncr_ctrl, nmic, "namespace create",
&nvme_ns_create_check_nmic, req->ncr_allow)) {
return (false);
}
req->ncr_nmic = nmic;
nvme_ns_create_req_clear_need(req, NVME_NS_CREATE_REQ_FIELD_NMIC);
return (nvme_ctrl_success(req->ncr_ctrl));
}
bool
nvme_ns_create_req_get_nsid(nvme_ns_create_req_t *req, uint32_t *nsid)
{
if (nsid == NULL) {
return (nvme_ctrl_error(req->ncr_ctrl, NVME_ERR_BAD_PTR, 0,
"encountered invalid nsid output pointer: %p", nsid));
}
if (!req->ncr_results_valid) {
return (nvme_ctrl_error(req->ncr_ctrl,
NVME_ERR_NS_CREATE_NO_RESULTS, 0, "namespace create "
"results are not currently valid and cannot be returned"));
}
*nsid = req->ncr_nsid;
return (nvme_ctrl_success(req->ncr_ctrl));
}
bool
nvme_ns_create_req_exec(nvme_ns_create_req_t *req)
{
nvme_ctrl_t *ctrl = req->ncr_ctrl;
nvme_ioctl_ns_create_t create;
req->ncr_results_valid = false;
req->ncr_nsid = 0;
if (req->ncr_need != 0) {
return (nvme_field_miss_err(ctrl, nvme_ns_create_fields,
nvme_ns_create_nfields,
NVME_ERR_NS_CREATE_REQ_MISSING_FIELDS, "namespace create",
req->ncr_need));
}
(void) memset(&create, 0, sizeof (create));
create.nnc_nsze = req->ncr_nsze;
create.nnc_ncap = req->ncr_ncap;
create.nnc_csi = req->ncr_csi;
create.nnc_flbas = req->ncr_flbas;
create.nnc_nmic = req->ncr_nmic;
if (ioctl(ctrl->nc_fd, NVME_IOC_NS_CREATE, &create) != 0) {
int e = errno;
return (nvme_ioctl_syserror(ctrl, e, "namespace create"));
}
if (create.nnc_common.nioc_drv_err != NVME_IOCTL_E_OK) {
return (nvme_ioctl_error(ctrl, &create.nnc_common,
"namespace create"));
}
req->ncr_results_valid = true;
req->ncr_nsid = create.nnc_nsid;
return (nvme_ctrl_success(ctrl));
}