* @nsid: Namespace identifier
* @sel: Type of management operation to perform
* @csi: Command Set Identifier
+ * @rsvd1: Reserved
+ * @rsvd2: Reserved
+ * @data: Host Software Specified Fields
*/
struct nvme_ns_mgmt_args {
__u32 *result;
__u32 nsid;
enum nvme_ns_mgmt_sel sel;
__u8 csi;
+ __u8 rsvd1[3];
+ void *rsvd2;
+ struct nvme_ns_mgmt_host_sw_specified *data;
};
/**
int nvme_ns_mgmt(struct nvme_ns_mgmt_args *args)
{
+ const size_t size_v1 = sizeof_args(struct nvme_ns_mgmt_args, csi, __u64);
+ const size_t size_v2 = sizeof_args(struct nvme_ns_mgmt_args, data, __u64);
__u32 cdw10 = NVME_SET(args->sel, NAMESPACE_MGMT_CDW10_SEL);
__u32 cdw11 = NVME_SET(args->csi, NAMESPACE_MGMT_CDW11_CSI);
- __u32 data_len = args->ns ? sizeof(*args->ns) : 0;
+
+ if (args->args_size < size_v1 || args->args_size > size_v2) {
+ errno = EINVAL;
+ return -1;
+ }
struct nvme_passthru_cmd cmd = {
.nsid = args->nsid,
.cdw10 = cdw10,
.cdw11 = cdw11,
.timeout_ms = args->timeout,
- .data_len = data_len,
- .addr = (__u64)(uintptr_t)args->ns,
};
- if (args->args_size < sizeof(*args)) {
- errno = EINVAL;
- return -1;
+ if (args->args_size == size_v2) {
+ if (args->data) {
+ cmd.data_len = sizeof(*args->data);
+ cmd.addr = (__u64)(uintptr_t)args->data;
+ }
+ }
+ else {
+ if (args->ns) {
+ cmd.data_len = sizeof(*args->ns);
+ cmd.addr = (__u64)(uintptr_t)args->ns;
+ }
}
return nvme_submit_admin_passthru(args->fd, &cmd, args->result);
}
* @timeout: Override the default timeout to this value in milliseconds;
* set to 0 to use the system default.
* @csi: Command Set Identifier
+ * @data: Host Software Specified Fields that defines ns creation parameters
*
* On successful creation, the namespace exists in the subsystem, but is not
* attached to any controller. Use the nvme_ns_attach_ctrls() to assign the
* &enum nvme_status_field) or -1 with errno set otherwise.
*/
static inline int nvme_ns_mgmt_create(int fd, struct nvme_id_ns *ns,
- __u32 *nsid, __u32 timeout, __u8 csi)
+ __u32 *nsid, __u32 timeout, __u8 csi,
+ struct nvme_ns_mgmt_host_sw_specified *data)
{
struct nvme_ns_mgmt_args args = {
.result = nsid,
.nsid = NVME_NSID_NONE,
.sel = NVME_NS_MGMT_SEL_CREATE,
.csi = csi,
+ .data = data,
};
return nvme_ns_mgmt(&args);
int nvme_mi_admin_ns_mgmt(nvme_mi_ctrl_t ctrl,
struct nvme_ns_mgmt_args *args)
{
+ const size_t size_v1 = sizeof_args(struct nvme_ns_mgmt_args, csi, __u64);
+ const size_t size_v2 = sizeof_args(struct nvme_ns_mgmt_args, data, __u64);
struct nvme_mi_admin_resp_hdr resp_hdr;
struct nvme_mi_admin_req_hdr req_hdr;
struct nvme_mi_resp resp;
struct nvme_mi_req req;
int rc;
+ size_t data_len;
- if (args->args_size < sizeof(*args))
- return -EINVAL;
+ if (args->args_size < size_v1 || args->args_size > size_v2) {
+ errno = EINVAL;
+ return -1;
+ }
nvme_mi_admin_init_req(&req, &req_hdr, ctrl->id,
nvme_admin_ns_mgmt);
req_hdr.cdw1 = cpu_to_le32(args->nsid);
req_hdr.cdw10 = cpu_to_le32(args->sel & 0xf);
req_hdr.cdw11 = cpu_to_le32(args->csi << 24);
- if (args->ns) {
- req.data = args->ns;
- req.data_len = sizeof(*args->ns);
- req_hdr.dlen = cpu_to_le32(sizeof(*args->ns));
+
+ if (args->args_size == size_v2) {
+ if (args->data) {
+ req.data = args->data;
+ data_len = sizeof(*args->data);
+ }
+ }
+ else {
+ if (args->ns) {
+ req.data = args->ns;
+ data_len = sizeof(*args->ns);
+ }
+ }
+
+ if (req.data) {
+ req.data_len = data_len;
+ req_hdr.dlen = cpu_to_le32(data_len);
req_hdr.flags = 0x1;
}
* @ns: New namespace parameters
* @csi: Command Set Identifier for new NS
* @nsid: Set to new namespace ID on create
+ * @data: Host Software Specified Fields that defines ns creation parameters
*
* Issues a Namespace Management (Create) command to @ctrl, to create a
* new namespace specified by @ns, using command set @csi. On success,
* &enum nvme_status_field) or -1 with errno set otherwise.
*/
static inline int nvme_mi_admin_ns_mgmt_create(nvme_mi_ctrl_t ctrl,
- struct nvme_id_ns *ns,
- __u8 csi, __u32 *nsid)
+ struct nvme_id_ns *ns, __u8 csi, __u32 *nsid,
+ struct nvme_ns_mgmt_host_sw_specified *data)
{
struct nvme_ns_mgmt_args args = {
.result = nsid,
.nsid = NVME_NSID_NONE,
.sel = NVME_NS_MGMT_SEL_CREATE,
.csi = csi,
+ .data = data,
};
return nvme_mi_admin_ns_mgmt(ctrl, &args);
NVME_IO_MGMT_SEND_RUH_UPDATE = 0x1,
};
+/**
+ * struct nvme_ns_mgmt_host_sw_specified - Namespace management Host Software
+ * Specified Fields.
+ * @nsze: Namespace Size indicates the total size of the namespace in
+ * logical blocks. The number of logical blocks is based on the
+ * formatted LBA size.
+ * @ncap: Namespace Capacity indicates the maximum number of logical blocks
+ * that may be allocated in the namespace at any point in time. The
+ * number of logical blocks is based on the formatted LBA size.
+ * @rsvd16: Reserved
+ * @flbas: Formatted LBA Size, see &enum nvme_id_ns_flbas.
+ * @rsvd27: Reserved
+ * @dps: End-to-end Data Protection Type Settings, see
+ * &enum nvme_id_ns_dps.
+ * @nmic: Namespace Multi-path I/O and Namespace Sharing Capabilities, see
+ * &enum nvme_id_ns_nmic.
+ * @rsvd31: Reserved
+ * @anagrpid: ANA Group Identifier indicates the ANA Group Identifier of the
+ * ANA group of which the namespace is a member.
+ * @rsvd96: Reserved
+ * @nvmsetid: NVM Set Identifier indicates the NVM Set with which this
+ * namespace is associated.
+ * @endgid: Endurance Group Identifier indicates the Endurance Group with
+ * which this namespace is associated.
+ * @rsvd104: Reserved
+ * @lbstm: Logical Block Storage Tag Mask Identifies the mask for the
+ * Storage Tag field for the protection information
+ * @nphndls: Number of Placement Handles specifies the number of Placement
+ * Handles included in the Placement Handle List
+ * @rsvd394: Reserved
+ * @rsvd499: Reserved for I/O Command Sets that extend this specification.
+ * @phndl: Placement Handle Associated RUH : This field specifies the Reclaim
+ * Unit Handle Identifier to be associated with the Placement Handle
+ * value. If the Flexible Data Placement capability is not supported or
+ * not enabled in specified Endurance Group, then the controller shall
+ * ignore this field.
+ * @rsvd768: Reserved
+ */
+struct nvme_ns_mgmt_host_sw_specified {
+ __le64 nsze;
+ __le64 ncap;
+ __u8 rsvd16[10];
+ __u8 flbas;
+ __u8 rsvd27[2];
+ __u8 dps;
+ __u8 nmic;
+ __u8 rsvd31[61];
+ __le32 anagrpid;
+ __u8 rsvd96[4];
+ __le16 nvmsetid;
+ __le16 endgid;
+ __u8 rsvd104[280];
+ __le64 lbstm;
+ __le16 nphndls;
+ __u8 rsvd394[105];
+ __u8 rsvd499[13];
+ __le16 phndl[128];
+ __u8 rsvd768[3328];
+};
+
#endif /* _LIBNVME_TYPES_H */
void *data)
{
__u8 *rq_hdr, *rs_hdr, sel, csi;
- struct nvme_id_ns *id;
+ struct nvme_ns_mgmt_host_sw_specified *create_data;
__u32 nsid;
rq_hdr = (__u8 *)req->hdr;
switch (sel) {
case NVME_NS_MGMT_SEL_CREATE:
- assert(req->data_len == sizeof(struct nvme_id_ns));
- id = req->data;
+ assert(req->data_len == sizeof(struct nvme_ns_mgmt_host_sw_specified));
+ create_data = req->data;
/* No NSID on created namespaces */
assert(nsid == 0);
assert(csi == 0);
/* allow operations on nsze == 42, reject others */
- if (le64_to_cpu(id->nsze) != 42) {
+ if (le64_to_cpu(create_data->nsze) != 42) {
rs_hdr[4] = 0;
/* response cdw0 is created NSID */
rs_hdr[8] = 0x04;
static void test_admin_ns_mgmt_create(struct nvme_mi_ep *ep)
{
- struct nvme_id_ns nsid = { 0 };
+ struct nvme_ns_mgmt_host_sw_specified data = { 0 };
nvme_mi_ctrl_t ctrl;
__u32 ns;
int rc;
ctrl = nvme_mi_init_ctrl(ep, 5);
assert(ctrl);
- rc = nvme_mi_admin_ns_mgmt_create(ctrl, &nsid, 0, &ns);
+ rc = nvme_mi_admin_ns_mgmt_create(ctrl, NULL, 0, &ns, &data);
assert(!rc);
assert(ns == 0x01020304);
- nsid.nsze = cpu_to_le64(42);
- rc = nvme_mi_admin_ns_mgmt_create(ctrl, &nsid, 0, &ns);
+ data.nsze = cpu_to_le64(42);
+ rc = nvme_mi_admin_ns_mgmt_create(ctrl, NULL, 0, &ns, &data);
assert(rc);
}