nvme-cli

# Completions

## bash

```sh
tokunori@tokunori-desktop:~/nvme-cli$ source completions/bash-nvme-completion.sh && source ~/.bashrc
```

## zsh

```sh
tokunori@tokunori-desktop:~/nvme-cli$ sudo apt install zsh
...
tokunori@tokunori-desktop:~/nvme-cli$ zsh
```

```
if your working shell is zsh...
-------------------------------
create the zsh completions directory if you don't have it
#if [ ! -e "~/.zsh" ]; then
#	mkdir ~/.zsh
#	mkdir ~/.zsh/completion
#fi

#cp `pwd`/_nvme ~/.zsh/completion/_nvme

add compinit if you don't have it in your .zshrc
#echo "autoload -Uz compinit && compinit" >> ~/.zshrc

add nvme autocompletions to your .zshrc
#echo "# source for tab autocompletions" >> ~/.zshrc
#echo "fpath=(~/.zsh/completion $fpath)" >> ~/.zshrc
#echo "source ~/.zsh/completion/_nvme" >> ~/.zshrc

make sure this zsh knows where everything is
#source ~/.zsh/completion/_nvme && source ~/.zshrc

You should be able to autocomplete with the nvme utility now (single TAB press
should get you a completion with descriptions -- sadly, bash doesn't support
descriptions within completions). If autocompletes disappear, just re-source
_nvme and .zshrc. Also, make sure your .zshrc is ordered correctly: we want to
source _nvme before updating our fpath. Both of these should occur before
compinit is loaded.
```

```sh
tokunori-desktop% cp completions/_nvme ~/.zsh/completion/_nvme
tokunori-desktop% source ~/.zsh/completion/_nvme && source ~/.zshrc
```

### .zshrc

```sh
tokunori-desktop% nano ~/.zshrc
autoload -Uz compinit && compinit
# source for tab autocompletions
fpath=(~/.zsh/completion /usr/local/share/zsh/site-functions /usr/share/zsh/vendor-functions /usr/share/zsh/vendor-c>
source ~/.zsh/completion/_nvme
setopt interactivecomments
bindkey "^[[3~" delete-char
bindkey "^[[1~" beginning-of-line
bindkey "^[[4~" end-of-line
```

# read

## master: nvme version 2.4 (git 2.4-50-g4e7b9fd+) / libnvme version 1.4 (git 1.4-13-gc90eeff)

```c
	if (cfg.metadata_size) {
		err = nvme_cli_identify_ns(dev, cfg.namespace_id, &ns);
		if (err > 0) {
			nvme_show_status(err);
			goto free_buffer;
		} else if (err < 0) {
			nvme_show_error("identify namespace: %s", nvme_strerror(errno));
			goto free_buffer;
		}
```

```c
	struct nvme_io_args args = {
		.args_size	= sizeof(args),
		.fd		= dev_fd(dev),
		.nsid		= cfg.namespace_id,
		.slba		= cfg.start_block,
		.nlb		= nblocks,
		.control	= control,
		.dsm		= cfg.dsmgmt,
		.sts		= sts,
		.pif		= pif,
		.dspec		= cfg.dspec,
		.reftag_u64	= cfg.ref_tag,
		.apptag		= cfg.app_tag,
		.appmask	= cfg.app_tag_mask,
		.storage_tag	= cfg.storage_tag,
		.data_len	= buffer_size,
		.data		= buffer,
		.metadata_len	= cfg.metadata_size,
		.metadata	= mbuffer,
		.timeout	= NVME_DEFAULT_IOCTL_TIMEOUT,
		.result		= NULL,
	};
```

```c
struct nvme_passthru_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	result;
};
```

```c
	struct nvme_passthru_cmd cmd = {
		.opcode		= opcode,
		.nsid		= args->nsid,
		.cdw2		= cdw2,
		.cdw3		= cdw3,
		.cdw10		= cdw10,
		.cdw11		= cdw11,
		.cdw12		= cdw12,
		.cdw13		= cdw13,
		.cdw14		= cdw14,
		.cdw15		= cdw15,
		.data_len	= args->data_len,
		.metadata_len	= args->metadata_len,
		.addr		= (__u64)(uintptr_t)args->data,
		.metadata	= (__u64)(uintptr_t)args->metadata,
		.timeout_ms	= args->timeout,
	};
```

```c
	return nvme_submit_passthru(fd, NVME_IOCTL_IO_CMD, cmd, result);
```

## 1.8

```c
	if (cfg.metadata_size) {
		mbuffer = malloc(cfg.metadata_size);
		if (!mbuffer) {
			fprintf(stderr, "can not allocate io metadata "
					"payload: %s\n", strerror(errno));
			err = ENOMEM;
			goto free_buffer;
		}
	}
```

```c
struct nvme_user_io {
	__u8	opcode;
	__u8	flags;
	__u16	control;
	__u16	nblocks;
	__u16	rsvd;
	__u64	metadata;
	__u64	addr;
	__u64	slba;
	__u32	dsmgmt;
	__u32	reftag;
	__u16	apptag;
	__u16	appmask;
};
```

```c
	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);
```

## v1.16: nvme version 1.16

```c
	if (cfg.metadata_size) {
		err = nsid = nvme_get_nsid(fd);
		if (err < 0) {
			perror("get-namespace-id");
			goto close_mfd;
		}
```

```c
struct nvme_passthru_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	result;
};
```

```c
	struct nvme_passthru_cmd cmd = {
		.opcode		= opcode,
		.nsid		= nsid,
		.metadata	= (__u64)(uintptr_t) metadata,
		.addr		= (__u64)(uintptr_t) data,
		.cdw2		= storage_tag & 0xffffffff,
		.cdw3		= (storage_tag >> 32) & 0xffff,
		.cdw10		= slba & 0xffffffff,
		.cdw11		= slba >> 32,
		.cdw12		= nblocks | (control << 16),
		.cdw13		= dsmgmt,
		.cdw14		= reftag,
		.cdw15		= apptag | (appmask << 16),
		.data_len	= buffer_size,
		.metadata_len	= mbuffer_size,
	};
```

```c
	return ioctl(fd, NVME_IOCTL_IO_CMD, cmd);
```

# kernel: master

```c
static int nvme_ns_ioctl(struct nvme_ns *ns, unsigned int cmd,
		void __user *argp, unsigned int flags, fmode_t mode)
{
	switch (cmd) {
	case NVME_IOCTL_ID:
		force_successful_syscall_return();
		return ns->head->ns_id;
	case NVME_IOCTL_IO_CMD:
		return nvme_user_cmd(ns->ctrl, ns, argp, flags, mode);
	/*
	 * struct nvme_user_io can have different padding on some 32-bit ABIs.
	 * Just accept the compat version as all fields that are used are the
	 * same size and at the same offset.
	 */
#ifdef COMPAT_FOR_U64_ALIGNMENT
	case NVME_IOCTL_SUBMIT_IO32:
#endif
	case NVME_IOCTL_SUBMIT_IO:
		return nvme_submit_io(ns, argp);
```

```c
struct nvme_user_io {
	__u8	opcode;
	__u8	flags;
	__u16	control;
	__u16	nblocks;
	__u16	rsvd;
	__u64	metadata;
	__u64	addr;
	__u64	slba;
	__u32	dsmgmt;
	__u32	reftag;
	__u16	apptag;
	__u16	appmask;
};
```

```c
static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
{
	struct nvme_user_io io;
	struct nvme_command c;
	unsigned length, meta_len;
	void __user *metadata;

	if (copy_from_user(&io, uio, sizeof(io)))
		return -EFAULT;
```

```c
struct nvme_passthru_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	result;
};
```

```c
static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
		struct nvme_passthru_cmd __user *ucmd, unsigned int flags,
		fmode_t mode)
{
	struct nvme_passthru_cmd cmd;
	struct nvme_command c;
	unsigned timeout = 0;
	u64 result;
	int status;

	if (copy_from_user(&cmd, ucmd, sizeof(cmd)))
		return -EFAULT;
```