| //go:build linux | 
 |  | 
 | package nvme | 
 |  | 
 | import ( | 
 | 	"errors" | 
 | 	"fmt" | 
 | 	"math" | 
 | 	"runtime" | 
 | 	"unsafe" | 
 |  | 
 | 	"golang.org/x/sys/unix" | 
 | ) | 
 |  | 
 | // From @linux//include/uapi/linux/nvme_ioctl.h | 
 | const ( | 
 | 	nvmeIoctlAdminCmd = 0xC0484E41 // _IOWR('N', 0x41, sizeof cmd) | 
 | ) | 
 |  | 
 | // From @linux//include/uapi/linux/nvme_ioctl.h | 
 | type passthruCmd struct { | 
 | 	// Corresponding to Figure 88 | 
 | 	opcode      uint8 | 
 | 	flags       uint8 | 
 | 	rsvd1       uint16 | 
 | 	nsid        uint32 | 
 | 	cdw2        uint32 | 
 | 	cdw3        uint32 | 
 | 	metadata    uint64 | 
 | 	addr        uint64 | 
 | 	metadataLen uint32 | 
 | 	dataLen     uint32 | 
 | 	cdw10       uint32 | 
 | 	cdw11       uint32 | 
 | 	cdw12       uint32 | 
 | 	cdw13       uint32 | 
 | 	cdw14       uint32 | 
 | 	cdw15       uint32 | 
 |  | 
 | 	// Linux ioctl-specific | 
 | 	timeoutMs uint32 | 
 | 	result    uint32 | 
 | } | 
 |  | 
 | // RawCommand runs a raw command on the NVMe device. | 
 | // Please note that depending on the payload this can be very dangerous and can | 
 | // cause data loss or even firmware issues. | 
 | func (d *Device) RawCommand(cmd *Command) error { | 
 | 	conn, err := d.fd.SyscallConn() | 
 | 	if err != nil { | 
 | 		return fmt.Errorf("unable to get RawConn: %w", err) | 
 | 	} | 
 | 	cmdRaw := passthruCmd{ | 
 | 		opcode:    cmd.Opcode, | 
 | 		flags:     cmd.Flags, | 
 | 		nsid:      cmd.NamespaceID, | 
 | 		cdw2:      cmd.CDW2, | 
 | 		cdw3:      cmd.CDW3, | 
 | 		cdw10:     cmd.CDW10, | 
 | 		cdw11:     cmd.CDW11, | 
 | 		cdw12:     cmd.CDW12, | 
 | 		cdw13:     cmd.CDW13, | 
 | 		cdw14:     cmd.CDW14, | 
 | 		cdw15:     cmd.CDW15, | 
 | 		timeoutMs: uint32(cmd.Timeout.Milliseconds()), | 
 | 	} | 
 | 	var ioctlPins runtime.Pinner | 
 | 	defer ioctlPins.Unpin() | 
 | 	if cmd.Data != nil { | 
 | 		if len(cmd.Data) > math.MaxUint32 { | 
 | 			return errors.New("data buffer larger than uint32, this is unsupported") | 
 | 		} | 
 | 		ioctlPins.Pin(&cmd.Data[0]) | 
 | 		cmdRaw.dataLen = uint32(len(cmd.Data)) | 
 | 		cmdRaw.addr = uint64(uintptr(unsafe.Pointer(&cmd.Data[0]))) | 
 | 	} | 
 | 	if cmd.Metadata != nil { | 
 | 		if len(cmd.Metadata) > math.MaxUint32 { | 
 | 			return errors.New("metadata buffer larger than uint32, this is unsupported") | 
 | 		} | 
 | 		ioctlPins.Pin(&cmd.Metadata[0]) | 
 | 		cmdRaw.metadataLen = uint32(len(cmd.Metadata)) | 
 | 		cmdRaw.metadata = uint64(uintptr(unsafe.Pointer(&cmd.Metadata[0]))) | 
 | 	} | 
 | 	var errno unix.Errno | 
 | 	var status uintptr | 
 | 	err = conn.Control(func(fd uintptr) { | 
 | 		status, _, errno = unix.Syscall(unix.SYS_IOCTL, fd, nvmeIoctlAdminCmd, uintptr(unsafe.Pointer(&cmdRaw))) | 
 | 	}) | 
 | 	runtime.KeepAlive(cmdRaw) | 
 | 	runtime.KeepAlive(cmd.Data) | 
 | 	runtime.KeepAlive(cmd.Metadata) | 
 | 	if err != nil { | 
 | 		return fmt.Errorf("unable to get fd: %w", err) | 
 | 	} | 
 | 	if errno != 0 { | 
 | 		return errno | 
 | 	} | 
 | 	var commandErr Error | 
 | 	commandErr.DoNotRetry = status&(1<<15) != 0            // Bit 31 | 
 | 	commandErr.More = status&(1<<14) != 0                  // Bit 30 | 
 | 	commandErr.StatusCodeType = uint8((status >> 8) & 0x7) // Bits 27:25 | 
 | 	commandErr.StatusCode = uint8(status & 0xff)           // Bits 24:17 | 
 | 	// The only success status is in the generic status code set with value 0 | 
 | 	if commandErr.StatusCodeType != StatusCodeTypeGeneric || | 
 | 		commandErr.StatusCode != 0 { | 
 | 		return commandErr | 
 | 	} | 
 | 	return nil | 
 | } |