From ff91bfb1cd33fc0e0eabcfdf53bc05baf8052fda Mon Sep 17 00:00:00 2001
From: Nugraha <richiisei@gmail.com>
Date: Sun, 16 Apr 2023 03:58:57 +0700
Subject: [PATCH] feat: essential ioctl and nvme package support

---
 ioctl/hdr_ioctl.go |  50 +++++++++++
 nvme/hdr_nvme.go   | 210 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 260 insertions(+)
 create mode 100644 ioctl/hdr_ioctl.go
 create mode 100644 nvme/hdr_nvme.go

diff --git a/ioctl/hdr_ioctl.go b/ioctl/hdr_ioctl.go
new file mode 100644
index 0000000..3c616da
--- /dev/null
+++ b/ioctl/hdr_ioctl.go
@@ -0,0 +1,50 @@
+package ioctl
+
+// Based on `ioctl.h`
+
+const (
+	_IOC_NRBITS   = 8
+	_IOC_TYPEBITS = 8
+
+	_IOC_SIZEBITS = 14 // OVERRIDE
+	_IOC_DIRBITS  = 2  // OVERRIDE
+
+	_IOC_NRMASK   = (1 << _IOC_NRBITS) - 1
+	_IOC_TYPEMASK = (1 << _IOC_TYPEBITS) - 1
+	_IOC_SIZEMASK = (1 << _IOC_SIZEBITS) - 1
+	_IOC_DIRMASK  = (1 << _IOC_DIRBITS) - 1
+
+	_IOC_NRSHIFT   = 0
+	_IOC_TYPESHIFT = (_IOC_NRSHIFT + _IOC_NRBITS)
+	_IOC_SIZESHIFT = (_IOC_TYPESHIFT + _IOC_TYPEBITS)
+	_IOC_DIRSHIFT  = (_IOC_SIZESHIFT + _IOC_SIZEBITS)
+
+	_IOC_NONE  = 0b00 // OVERRIDE
+	_IOC_WRITE = 0b01 // OVERRIDE
+	_IOC_READ  = 0b10 // OVERRIDE
+)
+
+//go:nosplit
+func IOC(dir, typ, nr, siz int) int {
+	return 0 |
+		(dir << _IOC_DIRSHIFT) |
+		(typ << _IOC_TYPESHIFT) |
+		(nr << _IOC_NRSHIFT) |
+		(siz << _IOC_SIZESHIFT)
+}
+
+/*
+ IO ops
+*/
+
+//go:nosplit
+func IO(typ, nr int) int { return IOC(_IOC_NONE, typ, nr, 0) }
+
+//go:nosplit
+func IOR(typ, nr, siz int) int { return IOC(_IOC_READ, typ, nr, siz) }
+
+//go:nosplit
+func IOW(typ, nr, siz int) int { return IOC(_IOC_WRITE, typ, nr, siz) }
+
+//go:nosplit
+func IOWR(typ, nr, siz int) int { return IOC(_IOC_WRITE|_IOC_READ, typ, nr, siz) }
diff --git a/nvme/hdr_nvme.go b/nvme/hdr_nvme.go
new file mode 100644
index 0000000..482385e
--- /dev/null
+++ b/nvme/hdr_nvme.go
@@ -0,0 +1,210 @@
+package nvme
+
+import (
+	"unsafe"
+
+	"github.com/ii64/gouring/ioctl"
+)
+
+// Based on `nvme.h` w.r.t. `linux/nvme_ioctl.h`
+
+const (
+	SizeofNvmeAdminCmd      = unsafe.Sizeof(NvmeAdminCmd{})
+	SizeofNvmeUserIo        = unsafe.Sizeof(NvmeUserIo{})
+	SizeofNvmePassthruCmd   = unsafe.Sizeof(NvmePassthruCmd{})
+	SizeofNvmePassthruCmd64 = unsafe.Sizeof(NvmePassthruCmd64{})
+	SizeofNvmeUringCmd      = unsafe.Sizeof(NvmeUringCmd{})
+	SizeofNvmeIdNs          = unsafe.Sizeof(NvmeIdNs{})
+	SizeofNvmeLbaf          = unsafe.Sizeof(NvmeLbaf{})
+
+	NVME_DEFAULT_IOCTL_TIMEOUT = 0
+	NVME_IDENTIFY_DATA_SIZE    = 0x1000
+	NVME_IDENTIFY_CSI_SHIFT    = 24
+	NVME_IDENTIFY_CNS_NS       = 0
+	NVME_CSI_NVM               = 0
+)
+
+func _SizeChecker() {
+	var x [1]struct{}
+	_ = x[SizeofNvmeAdminCmd-72]
+	_ = x[SizeofNvmeUserIo-48]
+	_ = x[SizeofNvmePassthruCmd-72]
+	_ = x[SizeofNvmePassthruCmd64-80]
+	_ = x[SizeofNvmeUringCmd-72]
+	_ = x[SizeofNvmeLbaf-4]
+	_ = x[SizeofNvmeIdNs-0x1000]
+}
+
+// Can this NVME_URING_CMD_* folds into constant literal?
+
+var (
+	NVME_IOCTL_ID           = ioctl.IO('N', 0x40)
+	NVME_IOCTL_ADMIN_CMD    = ioctl.IOWR('N', 0x41, int(SizeofNvmeAdminCmd))
+	NVME_IOCTL_SUBMIT_IO    = ioctl.IOW('N', 0x42, int(SizeofNvmeUserIo))
+	NVME_IOCTL_IO_CMD       = ioctl.IOR('N', 0x43, int(SizeofNvmePassthruCmd))
+	NVME_IOCTL_RESET        = ioctl.IO('N', 0x44)
+	NVME_IOCTL_SUBSYS_RESET = ioctl.IO('N', 0x45)
+	NVME_IOCTL_RESCAN       = ioctl.IO('N', 0x46)
+	NVME_IOCTL_ADMIN64_CMD  = ioctl.IOWR('N', 0x47, int(SizeofNvmePassthruCmd64))
+	NVME_IOCTL_IO64_CMD     = ioctl.IOWR('N', 0x48, int(SizeofNvmePassthruCmd64))
+	NVME_IOCTL_IO64_CMD_VEC = ioctl.IOWR('N', 0x49, int(SizeofNvmePassthruCmd64))
+
+	NVME_URING_CMD_IO        = ioctl.IOWR('N', 0x80, int(SizeofNvmeUringCmd))
+	NVME_URING_CMD_IO_VEC    = ioctl.IOWR('N', 0x81, int(SizeofNvmeUringCmd))
+	NVME_URING_CMD_ADMIN     = ioctl.IOWR('N', 0x82, int(SizeofNvmeUringCmd))
+	NVME_URING_CMD_ADMIN_VEC = ioctl.IOWR('N', 0x83, int(SizeofNvmeUringCmd))
+)
+
+func init() {
+	println("dbg NVME_URING_CMD_IO", NVME_URING_CMD_IO)
+	println("dbg NVME_URING_CMD_IO_VEC", NVME_URING_CMD_IO_VEC)
+	println("dbg NVME_URING_CMD_ADMIN", NVME_URING_CMD_ADMIN)
+	println("dbg NVME_URING_CMD_ADMIN_VEC", NVME_URING_CMD_ADMIN_VEC)
+}
+
+// nvme_admin_opcode
+const (
+	NVME_ADMIN_IDENTIFY = 0x06
+)
+
+// nvme_io_opcode
+const (
+	NVME_CMD_WRITE = 0x01
+	NVME_CMD_READ  = 0x02
+)
+
+type NvmeAdminCmd = NvmePassthruCmd
+
+type NvmeUserIo struct {
+	Opcode   uint8
+	Flags    uint8
+	Control  uint16
+	Nblocks  uint16
+	Rsvd     uint16
+	Metadata uint64
+	Addr     uint64
+	Slba     uint64
+	Dsmgmt   uint32
+	Reftag   uint32
+	Apptag   uint16
+	Appmask  uint16
+	_pad     [4]byte
+}
+
+type NvmePassthruCmd struct {
+	Opcode uint8
+	Flags  uint8
+	Rsvd1  uint16
+	Nsid   uint32
+	Cdw2,
+	Cdw3 uint32
+	Metadata    uint64
+	Addr        uint64
+	MetadataLen uint32
+	DataLen     uint32
+	Cdw10,
+	Cdw11,
+	Cdw12,
+	Cdw13,
+	Cdw14,
+	Cdw15 uint32
+	TimeoutMs uint32
+	Result    uint32
+}
+
+type NvmePassthruCmd64_Union1 uint32
+
+func (u *NvmePassthruCmd64_Union1) SetDataLen(v uint32)  { *u = NvmePassthruCmd64_Union1(v) }
+func (u *NvmePassthruCmd64_Union1) SetVecCount(v uint32) { *u = NvmePassthruCmd64_Union1(v) }
+
+type NvmePassthruCmd64 struct {
+	Opcode uint8
+	Flags  uint8
+	Rsvd1  uint16
+	Nsid   uint32
+	Cdw2,
+	Cdw3 uint32
+	Metadata    uint64
+	Addr        uint64
+	MetadataLen uint32
+	// union {
+	// 	__u32	data_len; /* for non-vectored io */
+	// 	__u32	vec_cnt; /* for vectored io */
+	// };
+	NvmePassthruCmd64_Union1
+	Cdw10,
+	Cdw11,
+	Cdw12,
+	Cdw13,
+	Cdw14,
+	Cdw15 uint32
+	TimeoutMs uint32
+	Rsvd2     uint32
+	Result    uint64
+}
+
+type NvmeUringCmd struct {
+	Opcode      uint8
+	Flags       uint8
+	Rsvd1       uint16
+	Nsid        uint32
+	Cdw2, Cdw3  uint32
+	Metadata    uint64
+	Addr        uint64
+	MetadataLen uint32
+	DataLen     uint32
+
+	Cdw10, Cdw11, Cdw12, Cdw13, Cdw14, Cdw15 uint32
+
+	TimeoutMs uint32
+	Rsvd2     uint32
+}
+
+type NvmeLbaf struct {
+	Ms uint16 // bo: Little
+	Ds uint8
+	Rp uint8
+}
+
+type NvmeIdNs struct {
+	Nsze,
+	Ncap,
+	Nuse uint64 // bo: Little
+	Nsfeat,
+	Nlbaf,
+	Flbas,
+	Mc,
+	Dpc,
+	Dps,
+	Nmic,
+	Rescap,
+	Fpi,
+	Dlfeat uint8
+	Nawun,
+	Nawupf,
+	Nacwu,
+	Nabsn,
+	Nabo,
+	Nabspf,
+	Noiob uint16 // bo: Little
+	Nvmcap [16]byte
+	Npwg,
+	Npwa,
+	Npdg,
+	Npda,
+	Nows uint16 // bo: Little
+	Msrl     uint16 // bo: Little
+	Mcl      uint32 // bo: Little
+	Msrc     uint8
+	Resvd81  [11]byte
+	Anagrpid uint32 // bo: Little
+	Rsvd96   [3]byte
+	Nsattr   uint8
+	Nvmsetid uint16 // bo: Little
+	Endgid   uint16 // bo: Little
+	Nguid    [16]byte
+	Eui64    [8]byte
+	Lbaf     [16]NvmeLbaf
+	Rsvd192  [192]byte
+	Vs       [3712]byte
+}