blob: 1254b92d21d17eaaac465c3d870f8b1a8a955ed4 [file] [log] [blame]
/* SPDX-License-Identifier: MIT */
/*
* Description: Helpers for NVMe uring passthrough commands
*/
#ifndef LIBURING_NVME_H
#define LIBURING_NVME_H
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/ioctl.h>
#include <linux/nvme_ioctl.h>
/*
* If the uapi headers installed on the system lacks nvme uring command
* support, use the local version to prevent compilation issues.
*/
#ifndef CONFIG_HAVE_NVME_URING
struct nvme_uring_cmd {
__u8 opcode;
__u8 flags;
__u16 rsvd1;
__u32 nsid;
__u32 cdw2;
__u32 cdw3;
__u64 metadata;
__u64 addr;
__u32 metadata_len;
__u32 data_len;
__u32 cdw10;
__u32 cdw11;
__u32 cdw12;
__u32 cdw13;
__u32 cdw14;
__u32 cdw15;
__u32 timeout_ms;
__u32 rsvd2;
};
#define NVME_URING_CMD_IO _IOWR('N', 0x80, struct nvme_uring_cmd)
#define NVME_URING_CMD_IO_VEC _IOWR('N', 0x81, struct nvme_uring_cmd)
#endif /* CONFIG_HAVE_NVME_URING */
#define NVME_DEFAULT_IOCTL_TIMEOUT 0
#define NVME_IDENTIFY_DATA_SIZE 4096
#define NVME_IDENTIFY_CSI_SHIFT 24
#define NVME_IDENTIFY_CNS_NS 0
#define NVME_CSI_NVM 0
enum nvme_admin_opcode {
nvme_admin_identify = 0x06,
};
enum nvme_io_opcode {
nvme_cmd_write = 0x01,
nvme_cmd_read = 0x02,
};
static int nsid;
static __u32 lba_shift;
struct nvme_lbaf {
__le16 ms;
__u8 ds;
__u8 rp;
};
struct nvme_id_ns {
__le64 nsze;
__le64 ncap;
__le64 nuse;
__u8 nsfeat;
__u8 nlbaf;
__u8 flbas;
__u8 mc;
__u8 dpc;
__u8 dps;
__u8 nmic;
__u8 rescap;
__u8 fpi;
__u8 dlfeat;
__le16 nawun;
__le16 nawupf;
__le16 nacwu;
__le16 nabsn;
__le16 nabo;
__le16 nabspf;
__le16 noiob;
__u8 nvmcap[16];
__le16 npwg;
__le16 npwa;
__le16 npdg;
__le16 npda;
__le16 nows;
__le16 mssrl;
__le32 mcl;
__u8 msrc;
__u8 rsvd81[11];
__le32 anagrpid;
__u8 rsvd96[3];
__u8 nsattr;
__le16 nvmsetid;
__le16 endgid;
__u8 nguid[16];
__u8 eui64[8];
struct nvme_lbaf lbaf[16];
__u8 rsvd192[192];
__u8 vs[3712];
};
static inline int ilog2(uint32_t i)
{
int log = -1;
while (i) {
i >>= 1;
log++;
}
return log;
}
__attribute__((__unused__))
static int nvme_get_info(const char *file)
{
struct nvme_id_ns ns;
int fd, err;
__u32 lba_size;
fd = open(file, O_RDONLY);
if (fd < 0) {
perror("file open");
return -errno;
}
nsid = ioctl(fd, NVME_IOCTL_ID);
if (nsid < 0) {
close(fd);
return -errno;
}
struct nvme_passthru_cmd cmd = {
.opcode = nvme_admin_identify,
.nsid = nsid,
.addr = (__u64)(uintptr_t)&ns,
.data_len = NVME_IDENTIFY_DATA_SIZE,
.cdw10 = NVME_IDENTIFY_CNS_NS,
.cdw11 = NVME_CSI_NVM << NVME_IDENTIFY_CSI_SHIFT,
.timeout_ms = NVME_DEFAULT_IOCTL_TIMEOUT,
};
err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
if (err) {
close(fd);
return err;
}
lba_size = 1 << ns.lbaf[(ns.flbas & 0x0f)].ds;
lba_shift = ilog2(lba_size);
close(fd);
return 0;
}
#ifdef __cplusplus
}
#endif
#endif