#!/usr/bin/bash
#
# Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
#
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES.
# SPDX-License-Identifier: LicenseRef-NVIDIA-Proprietary
#
# sysfs tool wrapper — real hardware version
# Reads/writes sysfs files for CC NP, CC global status, traffic class
source "$(dirname "$0")/_lib.sh"
trace "$@"

OP="$1"; shift
TARGET="$1"; shift
BDF=$(bdf_from_target "$TARGET")
IFACE=$(iface_from_bdf "$BDF")
RDMA_DEV=""
[[ -d "/sys/bus/pci/devices/${BDF}/infiniband" ]] && \
    RDMA_DEV=$(ls "/sys/bus/pci/devices/${BDF}/infiniband/" 2>/dev/null | head -1)

cc_global_path() {
    local protocol="$1" priority="$2"
    case "$protocol" in
        rp)
            if [[ -e "/sys/class/net/${IFACE}/ecn/roce_rp/enable/${priority}" ]]; then
                echo "/sys/class/net/${IFACE}/ecn/roce_rp/enable/${priority}"
            else
                echo "/sys/class/infiniband/${RDMA_DEV}/ecn/roce_rp/enable/${priority}"
            fi ;;
        np)
            if [[ -e "/sys/class/net/${IFACE}/ecn/roce_np/enable/${priority}" ]]; then
                echo "/sys/class/net/${IFACE}/ecn/roce_np/enable/${priority}"
            else
                echo "/sys/class/infiniband/${RDMA_DEV}/ecn/roce_np/enable/${priority}"
            fi ;;
        *) echo "" ;;
    esac
}

read_sysfs() {
    local path="$1"
    if [[ -f "$path" ]]; then
        cat "$path" 2>/dev/null
    else
        echo ""
    fi
}

write_sysfs() {
    local path="$1" value="$2"
    if [[ ! -w "$path" ]]; then
        echo "Error: sysfs path not writable: $path" >&2
        return 1
    fi
    if ! echo "$value" 2>/dev/null > "$path"; then
        echo "Error: sysfs write '$value' > $path failed (permission/EPERM/EBUSY)" >&2
        return 1
    fi
    return 0
}

if [[ "$OP" == "GLOBAL-GET" ]]; then
    PROTOCOL="$1"; PRIORITY="$2"; PARAM="$3"
    case "$PARAM" in
        protocol)
            echo "protocol=${PROTOCOL}" ;;
        priority)
            echo "priority=${PRIORITY}" ;;
        enabled)
            PATH_TO_READ=$(cc_global_path "$PROTOCOL" "$PRIORITY")
            V=$(read_sysfs "$PATH_TO_READ")
            [[ "$V" == "1" ]] && echo "enabled=true" || echo "enabled=false" ;;
        *)
            echo "${PARAM}=unknown" ;;
    esac
elif [[ "$OP" == "GLOBAL-SET" ]]; then
    PROTOCOL="$1"; PRIORITY="$2"; PARAM="$3"; VALUE="$4"
    case "$PARAM" in
        enabled)
            PATH_TO_WRITE=$(cc_global_path "$PROTOCOL" "$PRIORITY")
            case "$VALUE" in
                true|1) W=1 ;;
                false|0) W=0 ;;
                *) echo "Error: invalid enabled value: $VALUE" >&2; exit 1 ;;
            esac
            write_sysfs "$PATH_TO_WRITE" "$W" || exit 1
            echo "enabled=${VALUE}" ;;
        *)
            echo "Error: unsupported CC global-status SET param: $PARAM" >&2
            exit 1 ;;
    esac
elif [[ "$OP" == "GET" ]]; then
    for PARAM in "$@"; do
        case "$PARAM" in
            cnp_dscp)
                V=$(read_sysfs "/sys/class/net/${IFACE}/ecn/roce_np/cnp_dscp" 2>/dev/null)
                [[ -z "$V" ]] && V=$(read_sysfs "/sys/class/infiniband/${RDMA_DEV}/ecn/roce_np/cnp_dscp" 2>/dev/null)
                echo "cnp-dscp=${V:-0}" ;;
            cnp_prio_mode)
                V=$(read_sysfs "/sys/class/net/${IFACE}/ecn/roce_np/cnp_prio_mode" 2>/dev/null)
                [[ -z "$V" ]] && V=$(read_sysfs "/sys/class/infiniband/${RDMA_DEV}/ecn/roce_np/cnp_prio_mode" 2>/dev/null)
                echo "cnp-prio-mode=${V:-0}" ;;
            cnp_802p_prio)
                V=$(read_sysfs "/sys/class/net/${IFACE}/ecn/roce_np/cnp_802p_prio" 2>/dev/null)
                [[ -z "$V" ]] && V=$(read_sysfs "/sys/class/infiniband/${RDMA_DEV}/ecn/roce_np/cnp_802p_prio" 2>/dev/null)
                echo "cnp-802p-prio=${V:-0}" ;;
            is-supported)
                if [[ -d "/sys/class/net/${IFACE}/ecn/roce_np" ]] || \
                   [[ -d "/sys/class/infiniband/${RDMA_DEV}/ecn/roce_np" ]]; then
                    echo "is-supported=true"
                else
                    echo "is-supported=false"
                fi ;;
            protocol)
                echo "protocol=rp" ;;
            priority)
                echo "priority=0" ;;
            enabled)
                V=$(read_sysfs "/sys/class/infiniband/${RDMA_DEV}/ecn/roce_rp/enable/0")
                [[ "$V" == "1" ]] && echo "enabled=true" || echo "enabled=false" ;;
            *)
                echo "${PARAM}=unknown" ;;
        esac
    done
elif [[ "$OP" == "SET" ]]; then
    # Error policy: a sysfs SET that fails (EPERM, ENOENT, EBUSY) must surface
    # as non-zero exit. Previous write_sysfs() silently discarded errors via
    # `2>/dev/null` and the loop unconditionally echoed "key=value", masking
    # real driver-side failures as success. Now: write_sysfs returns non-zero
    # on real failure, missing-path also fails, and only successful writes
    # produce "key=value" output.
    declare -A PAIRS
    for PAIR in "$@"; do
        K="${PAIR%%=*}"
        V="${PAIR#*=}"
        PAIRS["$K"]="$V"
    done

    rc=0
    for K in "${!PAIRS[@]}"; do
        V="${PAIRS[$K]}"
        param_rc=0
        case "$K" in
            cnp_dscp)
                if [[ -f "/sys/class/net/${IFACE}/ecn/roce_np/cnp_dscp" ]]; then
                    write_sysfs "/sys/class/net/${IFACE}/ecn/roce_np/cnp_dscp" "$V" || param_rc=$?
                elif [[ -f "/sys/class/infiniband/${RDMA_DEV}/ecn/roce_np/cnp_dscp" ]]; then
                    write_sysfs "/sys/class/infiniband/${RDMA_DEV}/ecn/roce_np/cnp_dscp" "$V" || param_rc=$?
                else
                    echo "Error: cnp_dscp sysfs not found for ${IFACE}/${RDMA_DEV}" >&2
                    param_rc=1
                fi ;;
            cnp_prio_mode)
                if [[ -f "/sys/class/net/${IFACE}/ecn/roce_np/cnp_prio_mode" ]]; then
                    write_sysfs "/sys/class/net/${IFACE}/ecn/roce_np/cnp_prio_mode" "$V" || param_rc=$?
                elif [[ -f "/sys/class/infiniband/${RDMA_DEV}/ecn/roce_np/cnp_prio_mode" ]]; then
                    write_sysfs "/sys/class/infiniband/${RDMA_DEV}/ecn/roce_np/cnp_prio_mode" "$V" || param_rc=$?
                else
                    echo "Error: cnp_prio_mode sysfs not found" >&2
                    param_rc=1
                fi ;;
            cnp_802p_prio)
                if [[ -f "/sys/class/net/${IFACE}/ecn/roce_np/cnp_802p_prio" ]]; then
                    write_sysfs "/sys/class/net/${IFACE}/ecn/roce_np/cnp_802p_prio" "$V" || param_rc=$?
                elif [[ -f "/sys/class/infiniband/${RDMA_DEV}/ecn/roce_np/cnp_802p_prio" ]]; then
                    write_sysfs "/sys/class/infiniband/${RDMA_DEV}/ecn/roce_np/cnp_802p_prio" "$V" || param_rc=$?
                else
                    echo "Error: cnp_802p_prio sysfs not found" >&2
                    param_rc=1
                fi ;;
            enabled)
                PROTO="${PAIRS[protocol]:-rp}"
                PRIO="${PAIRS[priority]:-0}"
                BOOL_VAL="$([[ "$V" == "true" ]] && echo 1 || echo 0)"
                PATH_TO_WRITE=$(cc_global_path "$PROTO" "$PRIO")
                write_sysfs "$PATH_TO_WRITE" "$BOOL_VAL" || param_rc=$?
                ;;
            protocol|priority) ;; # selectors, handled by enabled
        esac
        if [[ $param_rc -eq 0 ]]; then
            echo "${K}=${V}"
        else
            rc=$param_rc
        fi
    done
    exit $rc
fi
