From 07fa078282a610b0ec486aca77076ede009e359b Mon Sep 17 00:00:00 2001 From: Nate Thornton Date: Wed, 13 Nov 2024 01:59:14 -0800 Subject: [PATCH] ioctl: Live Migration Continues efforts from the newly minted TP4159 PCIe Infrastructure for Live Migration specification with new ioctls. Signed-off-by: Nate Thornton --- src/libnvme.map | 16 ++++ src/nvme/api-types.h | 33 +++++---- src/nvme/ioctl.c | 171 +++++++++++++++++++++++++++++++++++++++++++ src/nvme/ioctl.h | 64 ++++++++++++++++ 4 files changed, 268 insertions(+), 16 deletions(-) diff --git a/src/libnvme.map b/src/libnvme.map index d60d076b..749ed186 100644 --- a/src/libnvme.map +++ b/src/libnvme.map @@ -1,4 +1,14 @@ # SPDX-License-Identifier: LGPL-2.1-or-later +LIBNVME_1.12 { + global: + nvme_lm_cdq; + nvme_lm_track_send; + nvme_lm_migration_send; + nvme_lm_migration_recv; + nvme_lm_set_features_ctrl_data_queue; + nvme_lm_get_features_ctrl_data_queue; +}; + LIBNVME_1.11 { global: nvme_ctrl_get_keyring; @@ -170,6 +180,12 @@ LIBNVME_1_0 { nvme_default_host; nvme_dev_self_test; nvme_dim_send; + nvme_lm_cdq; + nvme_lm_track_send; + nvme_lm_migration_send; + nvme_lm_migration_recv; + nvme_lm_set_features_ctrl_data_queue; + nvme_lm_get_features_ctrl_data_queue; nvme_directive_recv; nvme_directive_send; nvme_directive_send_id_endir; diff --git a/src/nvme/api-types.h b/src/nvme/api-types.h index f7c3c6ff..91263432 100644 --- a/src/nvme/api-types.h +++ b/src/nvme/api-types.h @@ -969,13 +969,13 @@ struct nvme_dim_args { * @args_size: Length of structure * @fd: File descriptor of nvme device * @timeout: Timeout in ms - * @cntlid: Controller ID: This field specifies the ID of the controller to be used by the - * specified Select (SEL) field. - * @cdqid: Controller Data Queue ID (CDQID): This field specifies the ID of the CDQ to be used - * for the specified Select (SEL) field. + * @mos: Management Operation Specific (MOS): This field is specific to the SEL type + * @cntlid: Controller ID: For Create CDQ, specifies the target migratable controller + * @cdqid: Controller Data Queue ID (CDQID): For Create CDQ, this field is the CDQID created + * by the controller if no error is present. For Delete CDQ, this field is the CDQID + * to delete. * @sel: Select (SEL): This field specifies the type of management operation to perform. - * @sz: Size of CDQ in dwords - * @qt: Queue Type (QT): This field specifies the type of queue to create + * @sz: For Create CDQ, specifies the size of CDQ, in dwords */ struct nvme_lm_cdq_args { __u32 *result; @@ -983,11 +983,11 @@ struct nvme_lm_cdq_args { int args_size; int fd; __u32 timeout; + __u16 mos; __u16 cntlid; __u16 cdqid; __u8 sel; __u8 sz; - __u8 qt; }; /** @@ -996,19 +996,18 @@ struct nvme_lm_cdq_args { * @args_size: Length of structure * @fd: File descriptor of nvme device * @timeout: Timeout in ms - * @cdqid: Controller Data Queue ID (CDQID): This field specifies the ID of the CDQ to be used - * for the logging action + * @mos: Management Operation Specific (MOS): This field is specific to the SEL type + * @cdqid: Controller Data Queue ID (CDQID) * @sel: Select (SEL): This field specifies the type of management operation to perform - * @lact: Logging Action (LACT): This field specifies the type of logging action to perform */ struct nvme_lm_track_send_args { __u32 *result; int args_size; int fd; __u32 timeout; + __u16 mos; __u16 cdqid; __u8 sel; - __u8 lact; }; /** @@ -1022,6 +1021,7 @@ struct nvme_lm_track_send_args { * @fd: File descriptor of nvme device * @timeout: Timeout in ms * @numd: Number of Dwords (NUMD): This field specifies the number of dwords being transferred + * @mos: Management Operation Specific (MOS): This field is specific to the SEL type * @cntlid: Controller ID: This field specifies the identifier of the controller to which the * operation is performed. * @csuuidi: Controller State UUID Index (CSUUIDI): A non-zero value in this field specifies the @@ -1048,6 +1048,7 @@ struct nvme_lm_migration_send_args { int fd; __u32 timeout; __u32 numd; + __u16 mos; __u16 cntlid; __u16 csuuidi; __u8 sel; @@ -1068,7 +1069,9 @@ struct nvme_lm_migration_send_args { * @args_size: Length of structure * @fd: File descriptor of nvme device * @timeout: Timeout in ms - * @numdl: Number of Dwords Lower (NMUDL): This field specifies the number of dwords to return. + * @numd: Number of Dwords (NUMD): This field specifies the number of dwords to return. This + * is a 0's based value. + * @mos: Management Operation Specific (MOS): This field is specific to the SEL type * @cntlid: Controller ID: This field specifies the identifier of the controller to which the * operation is performed. * @csuuidi: Controller State UUID Index (CSUUIDI): A non-zero value in this field specifies the @@ -1078,9 +1081,7 @@ struct nvme_lm_migration_send_args { * @uidx: UUID Index (UIDX): If this field is set to a non-zero value, then the value of this * field is the index of a UUID in the UUID List (refer to Figure 320) that is used by * the command. - * @csvi: Controller State Version Index (CSVI): A non-zero value in this field specifies the - * index to a specific entry in the NVMe Controller State Version list of the Supported - * Controller State Formats data structure. + * @csuidxp: Controller State UUID Index Parameter (CSUIDXP): This field is vendor specific. */ struct nvme_lm_migration_recv_args { __u64 offset; @@ -1090,11 +1091,11 @@ struct nvme_lm_migration_recv_args { int fd; __u32 timeout; __u32 numd; + __u16 mos; __u16 cntlid; __u16 csuuidi; __u8 sel; __u8 uidx; - __u8 csvi; __u8 csuidxp; }; diff --git a/src/nvme/ioctl.c b/src/nvme/ioctl.c index ba9d5b1f..4c13b058 100644 --- a/src/nvme/ioctl.c +++ b/src/nvme/ioctl.c @@ -2163,3 +2163,174 @@ int nvme_dim_send(struct nvme_dim_args *args) return nvme_submit_admin_passthru(args->fd, &cmd, args->result); } + + +int nvme_lm_cdq(struct nvme_lm_cdq_args *args) +{ + __u32 cdw10 = NVME_SET(args->sel, LM_CDQ_SEL) | + NVME_SET(args->mos, LM_CDQ_MOS); + __u32 cdw11 = 0, data_len = 0; + int err; + + if (args->sel == NVME_LM_SEL_CREATE_CDQ) { + cdw11 = NVME_SET(args->cntlid, LM_CREATE_CDQ_CNTLID) | + NVME_LM_CREATE_CDQ_PC; + data_len = args->sz << 2; + } else if (args->sel == NVME_LM_SEL_DELETE_CDQ) { + cdw11 = NVME_SET(args->cdqid, LM_DELETE_CDQ_CDQID); + } + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_ctrl_data_queue, + .cdw10 = cdw10, + .cdw11 = cdw11, + .cdw12 = args->sz, + .addr = (__u64)(uintptr_t)args->data, + .data_len = data_len, + .timeout_ms = args->timeout, + }; + + if (args->args_size < sizeof(*args)) { + errno = EINVAL; + return -1; + } + + err = nvme_submit_admin_passthru(args->fd, &cmd, args->result); + + if (!err) + args->cdqid = NVME_GET(cmd.result, LM_CREATE_CDQ_CDQID); + + return err; +} + +int nvme_lm_track_send(struct nvme_lm_track_send_args *args) +{ + __u32 cdw10 = NVME_SET(args->sel, LM_TRACK_SEND_SEL) | + NVME_SET(args->mos, LM_TRACK_SEND_MOS); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_track_send, + .cdw10 = cdw10, + .cdw11 = args->cdqid, + .timeout_ms = args->timeout, + }; + + if (args->args_size < sizeof(*args)) { + errno = EINVAL; + return -1; + } + + return nvme_submit_admin_passthru(args->fd, &cmd, args->result); +} + +int nvme_lm_migration_send(struct nvme_lm_migration_send_args *args) +{ + __u32 cdw10 = NVME_SET(args->sel, LM_MIGRATION_SEND_SEL) | + NVME_SET(args->mos, LM_MIGRATION_SEND_MOS); + __u32 cdw11 = 0; + + if (args->sel == NVME_LM_SEL_SUSPEND) { + cdw11 = NVME_SET(args->stype, LM_STYPE) | + NVME_SET(args->cntlid, LM_SUSPEND_CNTLID); + if (args->dudmq) + cdw11 |= NVME_LM_DUDMQ; + } else if (args->sel == NVME_LM_SEL_RESUME) { + cdw11 = NVME_SET(args->cntlid, LM_RESUME_CNTLID); + } else if (args->sel == NVME_LM_SEL_SET_CONTROLLER_STATE) { + cdw11 = NVME_SET(args->csuuidi, LM_SET_CONTROLLER_STATE_CSUUIDI) | + NVME_SET(args->csvi, LM_SET_CONTROLLER_STATE_CSVI) | + NVME_SET(args->cntlid, LM_SET_CONTROLLER_STATE_CNTLID); + } + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_migration_send, + .cdw10 = cdw10, + .cdw11 = cdw11, + .cdw12 = (__u32)args->offset, + .cdw13 = (__u32)(args->offset >> 32), + .cdw14 = NVME_SET(args->uidx, LM_MIGRATION_SEND_UIDX), + .cdw15 = args->numd, + .addr = (__u64)(uintptr_t)args->data, + .data_len = args->numd << 2, + .timeout_ms = args->timeout, + }; + + if (args->args_size < sizeof(*args)) { + errno = EINVAL; + return -1; + } + + return nvme_submit_admin_passthru(args->fd, &cmd, args->result); +} + +int nvme_lm_migration_recv(struct nvme_lm_migration_recv_args *args) +{ + __u32 cdw10 = NVME_SET(args->sel, LM_MIGRATION_RECV_SEL) | + NVME_SET(args->mos, LM_MIGRATION_RECV_MOS); + __u32 cdw11 = 0, data_len = 0; + + if (args->sel == NVME_LM_SEL_GET_CONTROLLER_STATE) { + cdw11 = NVME_SET(args->csuidxp, LM_GET_CONTROLLER_STATE_CSUIDXP) | + NVME_SET(args->csuuidi, LM_GET_CONTROLLER_STATE_CSUUIDI) | + NVME_SET(args->cntlid, LM_GET_CONTROLLER_STATE_CNTLID); + data_len = (args->numd + 1 /*0's based*/) << 2; + } + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_migration_receive, + .cdw10 = cdw10, + .cdw11 = cdw11, + .cdw12 = (__u32)args->offset, + .cdw13 = (__u32)(args->offset >> 32), + .cdw14 = NVME_SET(args->uidx, LM_MIGRATION_RECV_UIDX), + .cdw15 = args->numd, + .addr = (__u64)(uintptr_t)args->data, + .data_len = data_len, + .timeout_ms = args->timeout, + }; + + if (args->args_size < sizeof(*args)) { + errno = EINVAL; + return -1; + } + + return nvme_submit_admin_passthru(args->fd, &cmd, args->result); +} + +int nvme_lm_set_features_ctrl_data_queue(int fd, __u16 cdqid, __u32 hp, __u32 tpt, bool etpt, + __u32 *result) +{ + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = fd, + .fid = NVME_FEAT_FID_CTRL_DATA_QUEUE, + .nsid = NVME_NSID_NONE, + .cdw11 = cdqid | NVME_SET(tpt, LM_CTRL_DATA_QUEUE_ETPT), + .cdw12 = hp, + .cdw13 = tpt, + .save = false, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = result, + }; + + return nvme_set_features(&args); +} + +int nvme_lm_get_features_ctrl_data_queue(int fd, __u16 cdqid, + struct nvme_lm_ctrl_data_queue_fid_data *data, + __u32 *result) +{ + struct nvme_get_features_args args = { + .args_size = sizeof(args), + .fd = fd, + .fid = NVME_FEAT_FID_CTRL_DATA_QUEUE, + .nsid = NVME_NSID_NONE, + .cdw11 = cdqid, + .data = data, + .data_len = sizeof(*data), + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = result, + }; + + return nvme_get_features(&args); +} diff --git a/src/nvme/ioctl.h b/src/nvme/ioctl.h index e302af00..c139c977 100644 --- a/src/nvme/ioctl.h +++ b/src/nvme/ioctl.h @@ -4258,4 +4258,68 @@ int nvme_zns_append(struct nvme_zns_append_args *args); */ int nvme_dim_send(struct nvme_dim_args *args); +/** + * nvme_lm_cdq() - Controller Data Queue - Controller Data Queue command + * @args: &struct nvme_lm_cdq_args argument structure + * + * Return: The nvme command status if a response was received (see + * &enum nvme_status_field) or -1 with errno set otherwise.) + */ +int nvme_lm_cdq(struct nvme_lm_cdq_args *args); + +/** + * nvme_lm_track_send() - Track Send command + * @args: &struct nvme_lm_track_send_args argument structure + * + * Return: The nvme command status if a response was received (see + * &enum nvme_status_field) or -1 with errno set otherwise. + */ +int nvme_lm_track_send(struct nvme_lm_track_send_args *args); + +/** + * nvme_lm_migration_send() - Migration Send command + * @args: &struct nvme_lm_migration_send_args argument structure + * + * Return: The nvme command status if a response was received (see + * &enum nvme_status_field) or -1 with errno set otherwise. + */ +int nvme_lm_migration_send(struct nvme_lm_migration_send_args *args); + +/** + * nvme_lm_migration_recv - Migration Receive command + * @args: &struct nvme_lm_migration_rev_args argument structure + * + * Return: The nvme command status if a response was received (see + * &enum nvme_status_field) or -1 with errno set otherwise. + */ +int nvme_lm_migration_recv(struct nvme_lm_migration_recv_args *args); + +/** + * nvme_lm_set_features_ctrl_data_queue - Set Controller Datea Queue feature + * @fd: File descriptor of nvme device + * @cdqid: Controller Data Queue ID (CDQID) + * @hp: Head Pointer + * @tpt: Tail Pointer Trigger + * @etpt: Enable Tail Pointer Trigger + * @result: The command completions result from CQE dword0 + * + * Return: The nvme command status if a response was received (see + * &enum nvme_status_field) or -1 with errno set otherwise. + */ +int nvme_lm_set_features_ctrl_data_queue(int fd, __u16 cdqid, __u32 hp, __u32 tpt, bool etpt, + __u32 *result); + +/** + * nvme_lm_get_features_ctrl_data_queue - Get Controller Data Queue feature + * @fd: File descriptor of nvme device + * @cdqid: Controller Data Queue ID (CDQID) + * @data: Get Controller Data Queue feature data + * @result: The command completions result from CQE dword0 + * + * Return: The nvme command status if a response was received (see + * &enum nvme_status_field) or -1 with errno set otherwise. + */ +int nvme_lm_get_features_ctrl_data_queue(int fd, __u16 cdqid, + struct nvme_lm_ctrl_data_queue_fid_data *data, + __u32 *result); #endif /* _LIBNVME_IOCTL_H */