nvme_mi_admin_get_features;
nvme_mi_admin_set_features;
nvme_mi_admin_ns_mgmt;
+ nvme_mi_admin_ns_attach;
nvme_mi_admin_xfer;
nvme_mi_admin_security_send;
nvme_mi_admin_security_recv;
return 0;
}
+int nvme_mi_admin_ns_attach(nvme_mi_ctrl_t ctrl,
+ struct nvme_ns_attach_args *args)
+{
+ 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;
+
+ if (args->args_size < sizeof(*args))
+ return -EINVAL;
+
+ nvme_mi_admin_init_req(&req, &req_hdr, ctrl->id,
+ nvme_admin_ns_attach);
+
+ req_hdr.cdw1 = cpu_to_le32(args->nsid);
+ req_hdr.cdw10 = cpu_to_le32(args->sel & 0xf);
+ req.data = args->ctrlist;
+ req.data_len = sizeof(*args->ctrlist);
+ req_hdr.dlen = cpu_to_le32(sizeof(*args->ctrlist));
+ req_hdr.flags = 0x1;
+
+ nvme_mi_calc_req_mic(&req);
+
+ nvme_mi_admin_init_resp(&resp, &resp_hdr);
+
+ rc = nvme_mi_submit(ctrl->ep, &req, &resp);
+ if (rc)
+ return rc;
+
+ if (resp_hdr.status)
+ return resp_hdr.status;
+
+ if (args->result)
+ *args->result = le32_to_cpu(resp_hdr.cdw0);
+
+ return 0;
+}
+
static int nvme_mi_read_data(nvme_mi_ep_t ep, __u32 cdw0,
void *data, size_t *data_len)
{
return nvme_mi_admin_ns_mgmt(ctrl, &args);
}
+/**
+ * nvme_mi_admin_ns_attach() - Attach or detach namespace to controller(s)
+ * @ctrl: Controller to send command to
+ * @args: Namespace Attach command arguments
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+int nvme_mi_admin_ns_attach(nvme_mi_ctrl_t ctrl,
+ struct nvme_ns_attach_args *args);
+
+/**
+ * nvme_mi_admin_ns_attach_ctrls() - Attach namespace to controllers
+ * @ctrl: Controller to send command to
+ * @nsid: Namespace ID to attach
+ * @ctrlist: Controller list to modify attachment state of nsid
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+static inline int nvme_mi_admin_ns_attach_ctrls(nvme_mi_ctrl_t ctrl, __u32 nsid,
+ struct nvme_ctrl_list *ctrlist)
+{
+ struct nvme_ns_attach_args args = {
+ .result = NULL,
+ .ctrlist = ctrlist,
+ .args_size = sizeof(args),
+ .nsid = nsid,
+ .sel = NVME_NS_ATTACH_SEL_CTRL_ATTACH,
+ };
+
+ return nvme_mi_admin_ns_attach(ctrl, &args);
+}
+
+/**
+ * nvme_mi_admin_ns_detach_ctrls() - Detach namespace from controllers
+ * @ctrl: Controller to send command to
+ * @nsid: Namespace ID to detach
+ * @ctrlist: Controller list to modify attachment state of nsid
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+static inline int nvme_mi_admin_ns_detach_ctrls(nvme_mi_ctrl_t ctrl, __u32 nsid,
+ struct nvme_ctrl_list *ctrlist)
+{
+ struct nvme_ns_attach_args args = {
+ .result = NULL,
+ .ctrlist = ctrlist,
+ .args_size = sizeof(args),
+ .nsid = nsid,
+ .sel = NVME_NS_ATTACH_SEL_CTRL_DEATTACH,
+ };
+
+ return nvme_mi_admin_ns_attach(ctrl, &args);
+}
+
#endif /* _LIBNVME_MI_MI_H */
assert(!rc);
}
+struct attach_op {
+ enum {
+ NS_ATTACH,
+ NS_DETACH,
+ } op;
+ struct nvme_ctrl_list *list;
+};
+
+static int test_admin_ns_attach_cb(struct nvme_mi_ep *ep,
+ struct nvme_mi_req *req,
+ struct nvme_mi_resp *resp,
+ void *data)
+{
+ struct attach_op *op = data;
+ __u8 *rq_hdr, sel;
+ __u32 nsid;
+
+ rq_hdr = (__u8 *)req->hdr;
+ assert(rq_hdr[4] == nvme_admin_ns_attach);
+
+ sel = rq_hdr[44];
+ nsid = rq_hdr[11] << 24 | rq_hdr[10] << 16 | rq_hdr[9] << 8 | rq_hdr[8];
+
+ assert(req->data_len == sizeof(*op->list));
+
+ assert(nsid == 0x02030405);
+ switch (op->op) {
+ case NS_ATTACH:
+ assert(sel == NVME_NS_ATTACH_SEL_CTRL_ATTACH);
+ break;
+ case NS_DETACH:
+ assert(sel == NVME_NS_ATTACH_SEL_CTRL_DEATTACH);
+ break;
+ default:
+ assert(0);
+ }
+
+ assert(!memcmp(req->data, op->list, sizeof(*op->list)));
+
+ test_transport_resp_calc_mic(resp);
+
+ return 0;
+}
+
+static void test_admin_ns_attach(struct nvme_mi_ep *ep)
+{
+ struct nvme_ctrl_list list = { 0 };
+ struct attach_op aop;
+ nvme_mi_ctrl_t ctrl;
+ int rc;
+
+ list.num = cpu_to_le16(2);
+ list.identifier[0] = 4;
+ list.identifier[1] = 5;
+
+ aop.op = NS_ATTACH;
+ aop.list = &list;
+
+ test_set_transport_callback(ep, test_admin_ns_attach_cb, &aop);
+
+ ctrl = nvme_mi_init_ctrl(ep, 5);
+ assert(ctrl);
+
+ rc = nvme_mi_admin_ns_attach_ctrls(ctrl, 0x02030405, &list);
+ assert(!rc);
+}
+
+static void test_admin_ns_detach(struct nvme_mi_ep *ep)
+{
+ struct nvme_ctrl_list list = { 0 };
+ struct attach_op aop;
+ nvme_mi_ctrl_t ctrl;
+ int rc;
+
+ list.num = cpu_to_le16(2);
+ list.identifier[0] = 6;
+ list.identifier[1] = 7;
+
+ aop.op = NS_DETACH;
+ aop.list = &list;
+
+ test_set_transport_callback(ep, test_admin_ns_attach_cb, &aop);
+
+ ctrl = nvme_mi_init_ctrl(ep, 5);
+ assert(ctrl);
+
+ rc = nvme_mi_admin_ns_detach_ctrls(ctrl, 0x02030405, &list);
+ assert(!rc);
+}
+
+
#define DEFINE_TEST(name) { #name, test_ ## name }
struct test {
const char *name;
DEFINE_TEST(admin_id_nsid_ctrl_list),
DEFINE_TEST(admin_ns_mgmt_create),
DEFINE_TEST(admin_ns_mgmt_delete),
+ DEFINE_TEST(admin_ns_attach),
+ DEFINE_TEST(admin_ns_detach),
};
static void run_test(struct test *test, FILE *logfd, nvme_mi_ep_t ep)