/* 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 #include /* * 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, }; int nsid; __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; } 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