#include <assert.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <errno.h>
#include <getopt.h>
#include <fcntl.h>
#include <inttypes.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include "nvme-ioctl.h"
static int nvme_verify_chr(int fd)
{
static struct stat nvme_stat;
int err = fstat(fd, &nvme_stat);
if (err < 0) {
perror("fstat");
return errno;
}
if (!S_ISCHR(nvme_stat.st_mode)) {
fprintf(stderr,
"Error: requesting reset on non-controller handle\n");
return ENOTBLK;
}
return 0;
}
int nvme_subsystem_reset(int fd)
{
int ret;
ret = nvme_verify_chr(fd);
if (ret)
return ret;
return ioctl(fd, NVME_IOCTL_SUBSYS_RESET);
}
int nvme_reset_controller(int fd)
{
int ret;
ret = nvme_verify_chr(fd);
if (ret)
return ret;
return ioctl(fd, NVME_IOCTL_RESET);
}
int nvme_ns_rescan(int fd)
{
int ret;
ret = nvme_verify_chr(fd);
if (ret)
return ret;
return ioctl(fd, NVME_IOCTL_RESCAN);
}
int nvme_get_nsid(int fd)
{
static struct stat nvme_stat;
int err = fstat(fd, &nvme_stat);
if (err < 0)
return -errno;
if (!S_ISBLK(nvme_stat.st_mode)) {
fprintf(stderr,
"Error: requesting namespace-id from non-block device\n");
errno = ENOTBLK;
return -errno;
}
return ioctl(fd, NVME_IOCTL_ID);
}
int nvme_submit_passthru(int fd, unsigned long ioctl_cmd,
struct nvme_passthru_cmd *cmd)
{
return ioctl(fd, ioctl_cmd, cmd);
}
static int nvme_submit_admin_passthru(int fd, struct nvme_passthru_cmd *cmd)
{
return ioctl(fd, NVME_IOCTL_ADMIN_CMD, cmd);
}
static int nvme_submit_io_passthru(int fd, struct nvme_passthru_cmd *cmd)
{
return ioctl(fd, NVME_IOCTL_IO_CMD, cmd);
}
int nvme_passthru(int fd, unsigned long ioctl_cmd, __u8 opcode,
__u8 flags, __u16 rsvd,
__u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11,
__u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15,
__u32 data_len, void *data, __u32 metadata_len,
void *metadata, __u32 timeout_ms, __u32 *result)
{
struct nvme_passthru_cmd cmd = {
.opcode = opcode,
.flags = flags,
.rsvd1 = rsvd,
.nsid = nsid,
.cdw2 = cdw2,
.cdw3 = cdw3,
.metadata = (__u64)(uintptr_t) metadata,
.addr = (__u64)(uintptr_t) data,
.metadata_len = metadata_len,
.data_len = data_len,
.cdw10 = cdw10,
.cdw11 = cdw11,
.cdw12 = cdw12,
.cdw13 = cdw13,
.cdw14 = cdw14,
.cdw15 = cdw15,
.timeout_ms = timeout_ms,
.result = 0,
};
int err;
err = nvme_submit_passthru(fd, ioctl_cmd, &cmd);
if (!err && result)
*result = cmd.result;
return err;
}
int nvme_io(int fd, __u8 opcode, __u64 slba, __u16 nblocks, __u16 control,
__u32 dsmgmt, __u32 reftag, __u16 apptag, __u16 appmask, void *data,
void *metadata)
{
struct nvme_user_io io = {
.opcode = opcode,
.flags = 0,
.control = control,
.nblocks = nblocks,
.rsvd = 0,
.metadata = (__u64)(uintptr_t) metadata,
.addr = (__u64)(uintptr_t) data,
.slba = slba,
.dsmgmt = dsmgmt,
.reftag = reftag,
.appmask = appmask,
.apptag = apptag,
};
return ioctl(fd, NVME_IOCTL_SUBMIT_IO, &io);
}
int nvme_read(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
__u32 reftag, __u16 apptag, __u16 appmask, void *data,
void *metadata)
{
printf(">>>>>>>>>>>nvme_read\n");
return nvme_io(fd, nvme_cmd_read, slba, nblocks, control, dsmgmt,
reftag, apptag, appmask, data, metadata);
}
int nvme_write(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
__u32 reftag, __u16 apptag, __u16 appmask, void *data,
void *metadata)
{
return nvme_io(fd, nvme_cmd_write, slba, nblocks, control, dsmgmt,
reftag, apptag, appmask, data, metadata);
}
int nvme_compare(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
__u32 reftag, __u16 apptag, __u16 appmask, void *data,
void *metadata)
{
return nvme_io(fd, nvme_cmd_compare, slba, nblocks, control, dsmgmt,
reftag, apptag, appmask, data, metadata);
}
int nvme_verify(int fd, __u32 nsid, __u64 slba, __u16 nblocks,
__u16 control, __u32 reftag, __u16 apptag, __u16 appmask)
{
struct nvme_passthru_cmd cmd = {
.opcode = nvme_cmd_verify,
.nsid = nsid,
.cdw10 = slba & 0xffffffff,
.cdw11 = slba >> 32,
.cdw12 = nblocks | (control << 16),
.cdw14 = reftag,
.cdw15 = apptag | (appmask << 16),
};
return nvme_submit_io_passthru(fd, &cmd);
}
int nvme_passthru_io(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
__u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10,
__u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14,
__u32 cdw15, __u32 data_len, void *data,
__u32 metadata_len, void *metadata, __u32 timeout_ms)
{
return nvme_passthru(fd, NVME_IOCTL_IO_CMD, opcode, flags, rsvd, nsid,
cdw2, cdw3, cdw10, cdw11, cdw12, cdw13, cdw14,
cdw15, data_len, data, metadata_len, metadata,
timeout_ms, NULL);
}
int nvme_write_zeros(int fd, __u32 nsid, __u64 slba, __u16 nlb,
__u16 control, __u32 reftag, __u16 apptag, __u16 appmask)
{
struct nvme_passthru_cmd cmd = {
.opcode = nvme_cmd_write_zeroes,
.nsid = nsid,
.cdw10 = slba & 0xffffffff,
.cdw11 = slba >> 32,
.cdw12 = nlb | (control << 16),
.cdw14 = reftag,
.cdw15 = apptag | (appmask << 16),
};
return nvme_submit_io_passthru(fd, &cmd);
}
int nvme_write_uncorrectable(int fd, __u32 nsid, __u64 slba, __u16 nlb)
{
struct nvme_passthru_cmd cmd = {
.opcode = nvme_cmd_write_uncor,
.nsid = nsid,
.cdw10 = slba & 0xffffffff,
.cdw11 = slba >> 32,
.cdw12 = nlb,
};
return nvme_submit_io_passthru(fd, &cmd);
}
int nvme_flush(int fd, __u32 nsid)
{
struct nvme_passthru_cmd cmd = {
.opcode = nvme_cmd_flush,
.nsid = nsid,
};
return nvme_submit_io_passthru(fd, &cmd);
}
int nvme_dsm(int fd, __u32 nsid, __u32 cdw11, struct nvme_dsm_range *dsm,
__u16 nr_ranges)
{
struct nvme_passthru_cmd cmd = {
.opcode = nvme_cmd_dsm,
.nsid = nsid,
.addr = (__u64)(uintptr_t) dsm,
.data_len = nr_ranges * sizeof(*dsm),
.cdw10 = nr_ranges - 1,
.cdw11 = cdw11,
};
return nvme_submit_io_passthru(fd, &cmd);
}
struct nvme_dsm_range *nvme_setup_dsm_range(__u32 *ctx_attrs, __u32 *llbas,
__u64 *slbas, __u16 nr_ranges)
{
int i;
struct nvme_dsm_range *dsm = malloc(nr_ranges * sizeof(*dsm));
if (!dsm) {
fprintf(stderr, "malloc: %s\n", strerror(errno));
return NULL;
}
for (i = 0; i < nr_ranges; i++) {
dsm[i].cattr = cpu_to_le32(ctx_attrs[i]);
dsm[i].nlb = cpu_to_le32(llbas[i]);
dsm[i].slba = cpu_to_le64(slbas[i]);
}
return dsm;
}
int nvme_resv_acquire(int fd, __u32 nsid, __u8 rtype, __u8 racqa,
bool iekey, __u64 crkey, __u64 nrkey)
{
__le64 payload[2] = { cpu_to_le64(crkey), cpu_to_le64(nrkey) };
__u32 cdw10 = (racqa & 0x7) | (iekey ? 1 << 3 : 0) | rtype << 8;
struct nvme_passthru_cmd cmd = {
.opcode = nvme_cmd_resv_acquire,
.nsid = nsid,
.cdw10 = cdw10,
.addr = (__u64)(uintptr_t) (payload),
.data_len = sizeof(payload),
};
return nvme_submit_io_passthru(fd, &cmd);
}
int nvme_resv_register(int fd, __u32 nsid, __u8 rrega, __u8 cptpl,
bool iekey, __u64 crkey, __u64 nrkey)
{
__le64 payload[2] = { cpu_to_le64(crkey), cpu_to_le64(nrkey) };
__u32 cdw10 = (rrega & 0x7) | (iekey ? 1 << 3 : 0) | cptpl << 30;
struct nvme_passthru_cmd cmd = {
.opcode = nvme_cmd_resv_register,
.nsid = nsid,
.cdw10 = cdw10,
.addr = (__u64)(uintptr_t) (payload),
.data_len = sizeof(payload),
};
return nvme_submit_io_passthru(fd, &cmd);
}
int nvme_resv_release(int fd, __u32 nsid, __u8 rtype, __u8 rrela,
bool iekey, __u64 crkey)
{
__le64 payload[1] = { cpu_to_le64(crkey) };
__u32 cdw10 = (rrela & 0x7) | (iekey ? 1 << 3 : 0) | rtype << 8;
struct nvme_passthru_cmd cmd = {
.opcode = nvme_cmd_resv_release,
.nsid = nsid,
.cdw10 = cdw10,
.addr = (__u64)(uintptr_t) (payload),
.data_len = sizeof(payload),
}
评论0