Skip to content

Commit

Permalink
ioctl: Live Migration
Browse files Browse the repository at this point in the history
Continues efforts from the newly minted TP4159 PCIe Infrastructure for
Live Migration specification with new ioctls.

Signed-off-by: Nate Thornton <[email protected]>
  • Loading branch information
NateThornton committed Dec 6, 2024
1 parent 1fe7a1e commit 07fa078
Show file tree
Hide file tree
Showing 4 changed files with 268 additions and 16 deletions.
16 changes: 16 additions & 0 deletions src/libnvme.map
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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;
Expand Down
33 changes: 17 additions & 16 deletions src/nvme/api-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -969,25 +969,25 @@ 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;
void *data;
int args_size;
int fd;
__u32 timeout;
__u16 mos;
__u16 cntlid;
__u16 cdqid;
__u8 sel;
__u8 sz;
__u8 qt;
};

/**
Expand All @@ -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;
};

/**
Expand All @@ -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
Expand All @@ -1048,6 +1048,7 @@ struct nvme_lm_migration_send_args {
int fd;
__u32 timeout;
__u32 numd;
__u16 mos;
__u16 cntlid;
__u16 csuuidi;
__u8 sel;
Expand All @@ -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
Expand All @@ -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;
Expand All @@ -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;
};

Expand Down
171 changes: 171 additions & 0 deletions src/nvme/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
64 changes: 64 additions & 0 deletions src/nvme/ioctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

0 comments on commit 07fa078

Please sign in to comment.