#!/bin/bash
# SPDX-License-Identifier: GPL-3.0+
# Copyright (C) 2018 Johannes Thumshirn
#
# Test specific to NVMe devices

. common/rc

group_requires() {
	_have_root
}

group_device_requires() {
	_test_dev_is_nvme
}

NVMET_CFS="/sys/kernel/config/nvmet/"

_test_dev_is_nvme() {
	if ! readlink -f "$TEST_DEV_SYSFS/device" | grep -q nvme; then
		SKIP_REASON="$TEST_DEV is not a NVMe device"
		return 1
	fi
	return 0
}

_create_nvmet_port() {
	local trtype="$1"

	local port
	for ((port = 0; ; port++)); do
		if [[ ! -e "${NVMET_CFS}/ports/${port}" ]]; then
			break
		fi
	done

	mkdir "${NVMET_CFS}/ports/${port}"
	echo "${trtype}" > "${NVMET_CFS}/ports/${port}/addr_trtype"

	echo "${port}"
}

_remove_nvmet_port() {
	local port="$1"
	rmdir "${NVMET_CFS}/ports/${port}"
}

_create_nvmet_ns() {
	local nvmet_subsystem="$1"
	local nsid="$2"
	local blkdev="$3"
	local uuid="00000000-0000-0000-0000-000000000000"
	local subsys_path="${NVMET_CFS}/subsystems/${nvmet_subsystem}"
	local ns_path="${subsys_path}/namespaces/${nsid}"

	if [[ $# -eq 4 ]]; then
		uuid="$4"
	fi

	mkdir "${ns_path}"
	printf "%s" "${blkdev}" > "${ns_path}/device_path"
	printf "%s" "${uuid}" > "${ns_path}/device_uuid"
	printf 1 > "${ns_path}/enable"
}

_create_nvmet_subsystem() {
	local nvmet_subsystem="$1"
	local blkdev="$2"
	local uuid=$3
	local cfs_path="${NVMET_CFS}/subsystems/${nvmet_subsystem}"

	mkdir -p "${cfs_path}"
	echo 1 > "${cfs_path}/attr_allow_any_host"
	_create_nvmet_ns "${nvmet_subsystem}" "1" "${blkdev}" "${uuid}"
}

_remove_nvmet_ns() {
	local nvmet_subsystem="$1"
	local nsid=$2
	local subsys_path="${NVMET_CFS}/subsystems/${nvmet_subsystem}"
	local nvmet_ns_path="${subsys_path}/namespaces/${nsid}"

	echo 0 > "${nvmet_ns_path}/enable"
	rmdir "${nvmet_ns_path}"
}

_remove_nvmet_subsystem() {
	local nvmet_subsystem="$1"
	local subsys_path="${NVMET_CFS}/subsystems/${nvmet_subsystem}"

	_remove_nvmet_ns "${nvmet_subsystem}" "1"
	rmdir "${subsys_path}"
}

_add_nvmet_subsys_to_port() {
	local port="$1"
	local nvmet_subsystem="$2"

	ln -s "${NVMET_CFS}/subsystems/${nvmet_subsystem}" \
		"${NVMET_CFS}/ports/${port}/subsystems/${nvmet_subsystem}"
}

_remove_nvmet_subsystem_from_port() {
	local port="$1"
	local nvmet_subsystem="$2"

	rm "${NVMET_CFS}/ports/${port}/subsystems/${nvmet_subsystem}"
}

_find_nvme_loop_dev() {
	local dev
	local transport
	for dev in /sys/class/nvme/nvme*; do
		dev="$(basename "$dev")"
		transport="$(cat "/sys/class/nvme/${dev}/transport")"
		if [[ "$transport" == "loop" ]]; then
			echo "$dev"
		fi
	done
}
