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,
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;
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;
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)
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