Skip to content

Commit

Permalink
linux: Added functions to enable faster telemetry data retrieval.
Browse files Browse the repository at this point in the history
Moved telemetry data area support detection into separate function.
Added possibility to modify data transfer chunk size.
Enable telemetry extraction up to specified data area.
Removed some printf() and perror().

Signed-off-by: leonardo.da.cunha <[email protected]>
  • Loading branch information
lgdacunh authored and igaw committed Sep 12, 2023
1 parent 1fe61c5 commit 40560cd
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 25 deletions.
2 changes: 2 additions & 0 deletions src/libnvme.map
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ LIBNVME_1_0 {
nvme_get_path_attr;
nvme_get_property;
nvme_get_subsys_attr;
nvme_get_telemetry_log;
nvme_get_telemetry_max;
nvme_host_get_dhchap_key;
nvme_host_get_hostid;
nvme_host_get_hostnqn;
Expand Down
91 changes: 66 additions & 25 deletions src/nvme/linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,17 +122,44 @@ int nvme_fw_download_seq(int fd, __u32 size, __u32 xfer, __u32 offset,
return err;
}

static int nvme_get_telemetry_log(int fd, bool create, bool ctrl, bool rae,
struct nvme_telemetry_log **buf, enum nvme_telemetry_da da,
size_t *size)
int nvme_get_telemetry_max(int fd, enum nvme_telemetry_da *da, size_t *data_tx)
{
struct nvme_id_ctrl id_ctrl;
int err = nvme_identify_ctrl(fd, &id_ctrl);

if (err)
return err;

if (data_tx) {
*data_tx = id_ctrl.mdts;
if (id_ctrl.mdts) {
/* assuming CAP.MPSMIN is zero minimum Memory Page Size is at least
* 4096 bytes
*/
*data_tx = (1 << id_ctrl.mdts) * 4096;
}
}
if (da) {
if (id_ctrl.lpa & 0x8)
*da = NVME_TELEMETRY_DA_3;
if (id_ctrl.lpa & 0x40)
*da = NVME_TELEMETRY_DA_4;

}
return err;
}

int nvme_get_telemetry_log(int fd, bool create, bool ctrl, bool rae, size_t max_data_tx,
enum nvme_telemetry_da da, struct nvme_telemetry_log **buf,
size_t *size)
{
static const __u32 xfer = NVME_LOG_TELEM_BLOCK_SIZE;

struct nvme_telemetry_log *telem;
enum nvme_cmd_get_log_lid lid;
struct nvme_id_ctrl id_ctrl;
void *log, *tmp;
int err;
size_t dalb;
struct nvme_get_log_args args = {
.args_size = sizeof(args),
.fd = fd,
Expand Down Expand Up @@ -178,35 +205,31 @@ static int nvme_get_telemetry_log(int fd, bool create, bool ctrl, bool rae,

switch (da) {
case NVME_TELEMETRY_DA_1:
dalb = le16_to_cpu(telem->dalb1);
break;
case NVME_TELEMETRY_DA_2:
dalb = le16_to_cpu(telem->dalb2);
break;
case NVME_TELEMETRY_DA_3:
/* dalb3 >= dalb2 >= dalb1 */
*size = (le16_to_cpu(telem->dalb3) + 1) * xfer;
dalb = le16_to_cpu(telem->dalb3);
break;
case NVME_TELEMETRY_DA_4:
err = nvme_identify_ctrl(fd, &id_ctrl);
if (err) {
perror("identify-ctrl");
errno = EINVAL;
goto free;
}

if (id_ctrl.lpa & 0x40) {
*size = (le32_to_cpu(telem->dalb4) + 1) * xfer;
} else {
fprintf(stderr, "Data area 4 unsupported, bit 6 of Log Page Attributes not set\n");
errno = EINVAL;
err = -1;
goto free;
}
dalb = le32_to_cpu(telem->dalb4);
break;
default:
fprintf(stderr, "Invalid data area parameter - %d\n", da);
errno = EINVAL;
err = -1;
goto free;
}

if (dalb == 0) {
errno = ENOENT;
err = -1;
goto free;
}

*size = (dalb + 1) * xfer;
tmp = realloc(log, *size);
if (!tmp) {
errno = ENOMEM;
Expand All @@ -218,7 +241,7 @@ static int nvme_get_telemetry_log(int fd, bool create, bool ctrl, bool rae,
args.lid = lid;
args.log = log;
args.len = *size;
err = nvme_get_log_page(fd, 4096, &args);
err = nvme_get_log_page(fd, max_data_tx, &args);
if (!err) {
*buf = log;
return 0;
Expand All @@ -228,22 +251,40 @@ static int nvme_get_telemetry_log(int fd, bool create, bool ctrl, bool rae,
return err;
}


static int nvme_check_get_telemetry_log(int fd, bool create, bool ctrl, bool rae,
struct nvme_telemetry_log **log, enum nvme_telemetry_da da,
size_t *size)
{
enum nvme_telemetry_da max_da = 0;
int err = nvme_get_telemetry_max(fd, &max_da, NULL);

if (err)
return err;
if (da > max_da) {
errno = ENOENT;
return -1;
}
return nvme_get_telemetry_log(fd, create, ctrl, rae, 4096, da, log, size);
}


int nvme_get_ctrl_telemetry(int fd, bool rae, struct nvme_telemetry_log **log,
enum nvme_telemetry_da da, size_t *size)
{
return nvme_get_telemetry_log(fd, false, true, rae, log, da, size);
return nvme_check_get_telemetry_log(fd, false, true, rae, log, da, size);
}

int nvme_get_host_telemetry(int fd, struct nvme_telemetry_log **log,
enum nvme_telemetry_da da, size_t *size)
{
return nvme_get_telemetry_log(fd, false, false, false, log, da, size);
return nvme_check_get_telemetry_log(fd, false, false, false, log, da, size);
}

int nvme_get_new_host_telemetry(int fd, struct nvme_telemetry_log **log,
enum nvme_telemetry_da da, size_t *size)
{
return nvme_get_telemetry_log(fd, true, false, false, log, da, size);
return nvme_check_get_telemetry_log(fd, true, false, false, log, da, size);
}

int nvme_get_lba_status_log(int fd, bool rae, struct nvme_lba_status_log **log)
Expand Down
31 changes: 31 additions & 0 deletions src/nvme/linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,37 @@ enum nvme_telemetry_da {
NVME_TELEMETRY_DA_4 = 4,
};

/**
* nvme_get_telemetry_max() - Get telemetry limits
* @fd: File descriptor of nvme device
* @da: On success return max supported data area
* @max_data_tx: On success set to max transfer chunk supported by the controller
*
* Return: The nvme command status if a response was received (see
* &enum nvme_status_field) or -1 with errno set otherwise.
*/
int nvme_get_telemetry_max(int fd, enum nvme_telemetry_da *da, size_t *max_data_tx);

/**
* nvme_get_telemetry_log() - Get specified telemetry log
* @fd: File descriptor of nvme device
* @create: Generate new host initated telemetry capture
* @ctrl: Get controller Initiated log
* @rae: Retain asynchronous events
* @max_data_tx: Set the max data transfer size to be used retrieving telemetry.
* @da: Log page data area, valid values: &enum nvme_telemetry_da.
* @log: On success, set to the value of the allocated and retrieved log.
* @size: Ptr to the telemetry log size, so it can be returned
*
* The total size allocated can be calculated as:
* (nvme_telemetry_log da size + 1) * NVME_LOG_TELEM_BLOCK_SIZE.
*
* Return: The nvme command status if a response was received (see
* &enum nvme_status_field) or -1 with errno set otherwise.
*/
int nvme_get_telemetry_log(int fd, bool create, bool ctrl, bool rae, size_t max_data_tx,
enum nvme_telemetry_da da, struct nvme_telemetry_log **log,
size_t *size);
/**
* nvme_get_ctrl_telemetry() - Get controller telemetry log
* @fd: File descriptor of nvme device
Expand Down

0 comments on commit 40560cd

Please sign in to comment.