/*
 * Copyright (C) Jan 2013 Mellanox Technologies Ltd. All rights reserved.
 * Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 *
 * This software is available to you under a choice of one of two
 * licenses.  You may choose to be licensed under the terms of the GNU
 * General Public License (GPL) Version 2, available from the file
 * COPYING in the main directory of this source tree, or the
 * OpenIB.org BSD license below:
 *
 *     Redistribution and use in source and binary forms, with or
 *     without modification, are permitted provided that the following
 *     conditions are met:
 *
 *      - Redistributions of source code must retain the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer.
 *
 *      - Redistributions in binary form must reproduce the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#ifndef _MTCR_COM_DEFS_H
#define _MTCR_COM_DEFS_H

#include <stdlib.h>

#ifdef __WIN__

#include <winsock2.h>
#include <windows.h>

#ifdef __AARCH64EL__
#define MTCR_API
#else
#ifdef MTCR_EXPORTS
#define MTCR_API __declspec(dllexport)
#else
#define MTCR_API __declspec(dllimport)
#endif
#endif

#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__)
#include <stdint.h>
#ifndef MFT_TOOLS_VARS
#define MFT_TOOLS_VARS
typedef uint8_t u_int8_t;
typedef uint16_t u_int16_t;
typedef uint32_t u_int32_t;
typedef uint64_t u_int64_t;
#endif
#else
typedef __int8 int8_t;
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
#endif // !_MSC_VER
typedef unsigned __int8 u_int8_t;
typedef unsigned __int16 u_int16_t;
typedef unsigned __int32 u_int32_t;
typedef unsigned __int64 u_int64_t;

#if defined(_WIN64)
typedef __int64 MT_long_ptr_t;
typedef unsigned __int64 MT_ulong_ptr_t;
#else
typedef _W64 long MT_long_ptr_t;
typedef _W64 unsigned long MT_ulong_ptr_t;
#endif

#elif defined(__DJGPP__)

typedef unsigned char u_int8_t;
typedef char int8_t;
typedef unsigned short u_int16_t;
typedef short int16_t;
typedef unsigned int u_int32_t;
typedef long int32_t;
typedef unsigned long long u_int64_t;
typedef long long int64_t;

#define bswap_32(x) ntohl(x)
#define MTCR_API

#else /* UNIX */

#include <sys/types.h>
#define MTCR_API
#define LOCK_FILE_DIR "/tmp/mstflint_lockfiles"
#define LOCK_FILE_FORMAT "/tmp/mstflint_lockfiles/%04x:%02x:%02x.%x_%s"
#define LOCK_VIRTUAL_PCI_FILE_FORMAT "/tmp/mstflint_lockfiles/%s_%s"
#define MAX_RETRY_CNT 4096
#endif

#ifdef __FreeBSD__
typedef unsigned long u_long;
typedef unsigned int u_int;
#endif

#define DEV_NAME_SZ 513
#define MAX_PAGES_SIZE 8
#define SMP_SEMAPHOE_LOCK_CMD 0xff53
#define ADDRESS_OUT_OF_RANGE 0x3 // syndrome_code value

/*
 * MST <--> MTCR API defines
 */
#define MST_HEADER_VERSION 1
#define MST_META_DATA_MAJOR 1
#define MST_META_DATA_MINOR 0
#define MTCR_SUPP_MST_API_MAJOR_VERSION 1

#define MTCR_I2C_secondary_ADDRESS 0x48
#define SLV_ADDRS_NUM 128

#define STRING_TLV_SIZE 128

// Service name.
#define MST_PREFIX_64_BIT "mst64_"
#define MST_PREFIX_32_BIT "mst32_"
#define MST_SUFFIX_MAXLEN 11
#define MST_SERVICE_NAME_SIZE \
    (sizeof(MST_PREFIX_64_BIT) + sizeof(MFT_VERSION_STR) + MST_SUFFIX_MAXLEN + 9) // 9 is just in case reserve

// Remote connection.
#define DEFAULT_SSH_PORT 23108
#define DBG_PRINTF(...)                   \
    do                                    \
    {                                     \
        if (getenv("MFT_DEBUG") != NULL)  \
        {                                 \
            fprintf(stderr, __VA_ARGS__); \
        }                                 \
    } while (0)

// Methods supported by SemaphoreLock SMP.
typedef enum
{
    SEM_LOCK_GET = 0x0,
    SEM_LOCK_SET = 0x1
} sem_lock_method_t;

typedef enum MError
{
    ME_OK = 0,
    ME_ERROR,
    ME_PCI_CONFIG_SPACE_ACCESS_ERROR,
    ME_BAD_PARAMS,
    ME_CR_ERROR,
    ME_NOT_IMPLEMENTED,
    ME_SEM_LOCKED,
    ME_MEM_ERROR,
    ME_TIMEOUT,
    ME_ADDRESS_OUT_OF_RANGE,

    ME_MAD_SEND_FAILED,
    ME_UNKOWN_ACCESS_TYPE,
    ME_UNSUPPORTED_DEVICE,
    ME_REG_NOT_SUPPORTED,

    ME_PCI_READ_ERROR,
    ME_PCI_WRITE_ERROR,
    ME_PCI_SPACE_NOT_SUPPORTED,
    ME_PCI_IFC_TOUT,

    ME_UNSUPPORTED_OPERATION,
    ME_UNSUPPORTED_ACCESS_TYPE,
    ME_GMP_MAD_UNSUPPORTED_OPERATION,

    // errors regarding REG_ACCESS
    ME_REG_ACCESS_OK = 0,
    ME_REG_ACCESS_BAD_STATUS_ERR = 0x100,
    ME_REG_ACCESS_BAD_METHOD,
    ME_REG_ACCESS_NOT_SUPPORTED,
    ME_REG_ACCESS_DEV_BUSY,
    ME_REG_ACCESS_VER_NOT_SUPP,
    ME_REG_ACCESS_UNKNOWN_TLV,
    ME_REG_ACCESS_REG_NOT_SUPP,
    ME_REG_ACCESS_CLASS_NOT_SUPP,
    ME_REG_ACCESS_METHOD_NOT_SUPP,
    ME_REG_ACCESS_BAD_PARAM,
    ME_REG_ACCESS_RES_NOT_AVLBL,
    ME_REG_ACCESS_MSG_RECPT_ACK,
    ME_REG_ACCESS_UNKNOWN_ERR,
    ME_REG_ACCESS_SIZE_EXCEEDS_LIMIT,
    ME_REG_ACCESS_CONF_CORRUPT,
    ME_REG_ACCESS_LEN_TOO_SMALL,
    ME_REG_ACCESS_BAD_CONFIG,
    ME_REG_ACCESS_ERASE_EXCEEDED,
    ME_REG_ACCESS_INTERNAL_ERROR,
    ME_REG_ACCESS_NOT_SUPPORTED_BY_SECONDARY,
    ME_REG_ACCESS_INSUFFICIENT_PERMISSIONS,

    // errors regarding ICMD
    ME_ICMD_STATUS_CR_FAIL = 0x200, // cr-space access failure
    ME_ICMD_INVALID_OPCODE,
    ME_ICMD_INVALID_CMD,
    ME_ICMD_OPERATIONAL_ERROR,
    ME_ICMD_BAD_PARAM,
    ME_ICMD_BUSY,
    ME_ICMD_INIT_FAILED,
    ME_ICMD_NOT_SUPPORTED,
    ME_ICMD_STATUS_SEMAPHORE_TO, // timed out while trying to take semaphore
    ME_ICMD_STATUS_EXECUTE_TO,   // timed out while waiting for command to execute
    ME_ICMD_STATUS_IFC_BUSY,
    ME_ICMD_STATUS_ICMD_NOT_READY,
    ME_ICMD_UNSUPPORTED_ICMD_VERSION,
    ME_ICMD_UNKNOWN_STATUS,
    ME_ICMD_ICM_NOT_AVAIL,
    ME_ICMD_WRITE_PROTECT,
    ME_ICMD_SIZE_EXCEEDS_LIMIT,
    ME_ICMD_UNABLE_TO_TAKE_SEMAOHORE,
    ME_ICMD_REMOTE_CONNECTION_ERROR,

    // errors regarding Tools CMDIF
    ME_CMDIF_BUSY = 0x300,
    ME_CMDIF_TOUT,
    ME_CMDIF_BAD_STATUS,
    ME_CMDIF_BAD_OP,
    ME_CMDIF_NOT_SUPP,
    ME_CMDIF_BAD_SYS,
    ME_CMDIF_UNKN_TLV,
    ME_CMDIF_RES_STATE,
    ME_CMDIF_UNKN_STATUS,

    // errors regarding MAD IF
    ME_MAD_BUSY = 0x400,
    ME_MAD_REDIRECT,
    ME_MAD_BAD_VER,
    ME_MAD_METHOD_NOT_SUPP,
    ME_MAD_METHOD_ATTR_COMB_NOT_SUPP,
    ME_MAD_BAD_DATA,
    ME_MAD_GENERAL_ERR,

    // errors regarding gearbox icmd new interface gateway
    ME_GB_ICMD_OK = 0x500,
    ME_GB_ICMD_FAILED,
    ME_GB_ICMD_FAILED_ACCESS,
    ME_GB_ICMD_FAILED_BAD_PARAM,
    ME_GB_ICMD_TIMEOUT,
    ME_GB_ICMD_NOT_SUPPORTED,
    ME_GB_ICMD_UNKNOWN_STATUS,

    ME_LAST
} MError;

typedef enum MType_t
{
    MST_ERROR = 0x0,
    MST_MLNXOS = 0x2,
    MST_NVJTAG = 0x3,
    MST_LPC = 0x4,
    MST_PCI = 0x8,
    MST_PCICONF = 0x10,
    MST_PLANARIZED = 0x20,
    MST_IB = 0x40,
    // reserved = 0x80
    // reserved = 0x100
    MST_USB_DIMAX = 0x200,
    MST_NICX = 0x400,
    MST_REMOTE = 0x800,
    MST_DEV_I2C = 0x1000,
    // reserved = 0x2000,
    // reserved = 0x4000,
    MST_CABLE = 0x8000,
    // reserved = 0x10000,
    MST_SOFTWARE = 0x20000,
    MST_DRIVER_CONF = 0x40000,
    MST_DRIVER_CR = 0x80000,
    MST_LINKX_CHIP = 0x100000,
    MST_BAR0_GW_PCI = 0x200000,
    MST_GEARBOX = 0x400000,
    MST_RM_DRIVER = 0x800000,
    MST_NDC = 0x1000000,
    MST_RETIMER = 0x2000000,
    MST_I2C_JSON_DEVICE = 0x4000000,
    MST_VFIO_DEVICE = 0x8000000,
    MST_VIRT_MEM = 0x10000000,
    MST_DEFAULT = 0xffffffff & ~MST_CABLE & ~MST_LINKX_CHIP
} MType;

typedef enum DType_t
{
    MST_GAMLA,
    MST_TAVOR,
    MST_DIMM,
    MST_NOADDR
} DType;

typedef enum Mdevs_t
{
    MDEVS_NICX = 0x01,            /* NICX Simulator */
    MDEVS_I2CM = 0x02,            /*  Each device that can work as I2C primary */
    MDEVS_TAVOR_DDR = 0x08,       /*  Each device that maps to DDR (deprecated) */
    MDEVS_TAVOR_UAR = 0x10,       /*  Each device that maps to UAR (deprecated) */
    MDEVS_TAVOR_CR = 0x20,        /*  Each device that maps to CR */
    MDEVS_REM = 0x80,             /*  Remote devices */
    MDEVS_DEV_I2C = 0x200,        /* Generic linux kernel i2c device */
    MDEVS_IB = 0x400,             /* Cr access over IB Mads */
    MDEVS_MLNX_OS = 0x800,        /* access by CmdIf in MlnxOS */
    MDEVS_LPC = 0x1000,           /* Access LPC region */
    MDEVS_NVL = 0x2000,           /* NVLink Devices */
    MDEVS_CABLE = 0x8000,         /* Cable Devices */
    MDEVS_SOFTWARE = 0x10000,     /* Software system char dev */
    MDEVS_LINKX_CHIP = 0x200000,  /*  Link-X devices */
    MDEVS_GBOX = 0x400000,        /*  Gearbox devices */
    MDEVS_NVJTAG = 0x800000,      /*  USB2JTAG devices */
    MDEVS_RM_DRIVER = 0x1000000,  /*  GPU devices */
    MDEVS_RETIMER = 0x2000000,    /* Access to retimer chips */
    MDEVS_PLANARIZED = 0x4000000, /* Aggregated Port Devices */
    MDEVS_REDFISH = 0x8000000,    /* Redfish devices */
    MDEVS_VMDL = 0x10000000,      /* Virtual Module devices */
    MDEVS_VIRT_MEM = 0x20000000,  /* Virtual memory devices */
    MDEVS_TAVOR = (MDEVS_TAVOR_DDR | MDEVS_TAVOR_UAR | MDEVS_TAVOR_CR),
    MDEVS_ALL = 0xffffffff
} Mdevs;

typedef enum
{
    MACCESS_REG_METHOD_GET = 1,
    MACCESS_REG_METHOD_SET = 2,
    MACCESS_LAST_REG_METHOD = 3
} maccess_reg_method_t;

typedef enum
{
    VCC_INITIALIZED = 0x0,
    VCC_ICMD_EXT_SPACE_SUPPORTED = 0x1,
    VCC_CRSPACE_SPACE_SUPPORTED = 0x2,
    VCC_ICMD_SPACE_SUPPORTED = 0x3,
    VCC_NODNIC_INIT_SEG_SPACE_SUPPORTED = 0x4,
    VCC_EXPANSION_ROM_SPACE_SUPPORTED = 0x5,
    VCC_ND_CRSPACE_SPACE_SUPPORTED = 0x6,
    VCC_SCAN_CRSPACE_SPACE_SUPPORTED = 0x7,
    VCC_SEMAPHORE_SPACE_SUPPORTED = 0x8,
    VCC_MAC_SPACE_SUPPORTED = 0x9,
    VCC_PCI_ICMD_SPACE_SUPPORTED = 0xa,
    VCC_PCI_CRSPACE_SPACE_SUPPORTED = 0xb,
    VCC_PCI_ALL_ICMD_SPACE_SUPPORTED = 0xc,
    VCC_PCI_SCAN_CRSPACE_SPACE_SUPPORTED = 0xd,
    VCC_PCI_GLOBAL_SEMAPHORE_SPACE_SUPPORTED = 0xe,
    VCC_RECOVERY_SPACE_SUPPORTED = 0xf
} VSCCapCom;

typedef enum
{
    AS_ICMD_EXT = 0x1,
    AS_CR_SPACE = 0x2,
    AS_ICMD = 0x3,
    AS_NODNIC_INIT_SEG = 0x4,
    AS_EXPANSION_ROM = 0x5,
    AS_ND_CRSPACE = 0x6,
    AS_SCAN_CRSPACE = 0x7,
    AS_SEMAPHORE = 0xa,
    AS_RECOVERY = 0Xc,
    AS_MAC = 0xf,
    AS_PCI_ICMD = 0x101,
    AS_PCI_CRSPACE = 0x102,
    AS_PCI_ALL_ICMD = 0x103,
    AS_PCI_SCAN_CRSPACE = 0x107,
    AS_PCI_GLOBAL_SEMAPHORE = 0x10a,
    AS_END
} address_space_t;

typedef struct vf_info_t
{
    char dev_name[512];
    u_int16_t domain;
    u_int8_t bus;
    u_int8_t dev;
    u_int8_t func;
    char** net_devs; // Null terminated array
    char** ib_devs;  // Null terminated array
} vf_info;

typedef struct dev_info_t
{
    Mdevs type;
    char dev_name[DEV_NAME_SZ];
    int ul_mode;

    union
    {
        struct
        {
            u_int16_t domain;
            u_int8_t bus;
            u_int8_t dev;
            u_int8_t func;

            u_int16_t dev_id;
            u_int16_t vend_id;
            u_int32_t class_id;
            u_int16_t subsys_id;
            u_int16_t subsys_vend_id;

            char cr_dev[512];
            char conf_dev[DEV_NAME_SZ];
            char** net_devs;      // Null terminated array
            char** ib_devs;       // Null terminated array
            char numa_node[4096]; //
            vf_info* virtfn_arr;
            u_int16_t virtfn_count;
        } pci;

        struct
        {
            u_int32_t mtusb_serial;
            u_int32_t TBD;
        } usb;

        struct
        {
            u_int32_t TBD;
        } ib;
    };
} dev_info;

typedef enum
{
    GEARBOX_OVER_MTUSB = 1,
    GEARBOX_OVER_I2C = 2,
    GEARBOX_OVER_SWITCH = 3,
    GEARBOX_UNKNOWN_CONNECTION = 0
} gearbox_connection_t;

typedef enum
{
    RETIMER_OVER_MTUSB = 1,
    RETIMER_OVER_CABLE = 2,
    RETIMER_OVER_SWITCH = 3,
    RETIMER_UNKNOWN_CONNECTION = 0
} retimer_connection_t;

typedef enum
{
    MTCR_STATUS_UNKNOWN,
    MTCR_STATUS_TRUE,
    MTCR_STATUS_FALSE,
} mtcr_status_e;

typedef struct icmd_params_t
{
    int icmd_opened;
    int took_semaphore;
    int ctrl_addr;
    int cmd_addr;
    int cmd_ptr_bitlen;
    int version_addr;
    int version_bit_offset;
    int version_bitlen;
    u_int32_t max_cmd_size;
    int semaphore_addr;
    int static_cfg_not_done_addr;
    int static_cfg_not_done_offs;
    u_int32_t lock_key;
    int ib_semaphore_lock_supported;
    int string_tlv_supported;
    u_int8_t string_tlv[STRING_TLV_SIZE];
    u_int64_t dma_pa;
    u_int32_t dma_size;
    int dma_icmd;
    mtcr_status_e icmd_ready;
    int syndrome_addr;
    int syndrome;
} icmd_params;

typedef struct io_region_t
{
    unsigned int start;
    unsigned int end;
} io_region;

typedef struct tools_hcr_params_t
{
    int supp_cr_mbox; // 1: mbox supported , -1: mbox not supported
} tools_hcr_params;

// max_reg_size depends on the desired method operated on the register.
// max_reg_size[<method_enum_value>] will give the relevant max_reg_size.
// For example max_reg_size[MACCESS_REG_METHOD_GET] will give max_reg_size for Get() method.
typedef struct access_reg_params_t
{
    int max_reg_size[MACCESS_LAST_REG_METHOD];
} access_reg_params;

struct mtcr_page_addresses
{
    u_int64_t dma_address;
    u_int64_t virtual_address;
};

struct page_list
{
    // User space buffer page aligned.
    char* page_list;
    int page_amount;
};

struct page_list_fbsd
{
    // User space buffer page aligned.
    char* page_list[MAX_PAGES_SIZE];
    int page_amount;
};

struct mtcr_page_info
{
    unsigned int page_amount;
    unsigned long page_pointer_start;
    struct mtcr_page_addresses page_addresses_array[MAX_PAGES_SIZE];
};

struct mtcr_read_dword_from_config_space
{
    unsigned int offset;
    unsigned int data;
};

typedef enum
{
    GB_UNKNOWN = 0,
    GB_AMOS,
    GB_ABIR
} gearbox_type;

typedef struct gearbox_info_t
{
    gearbox_type gb_type;
    u_int8_t is_gearbox;
    u_int8_t is_gb_mngr;
    int gearbox_index;
    int ilne_card_id;
    gearbox_connection_t gb_conn_type;
    char gb_mngr_full_name[DEV_NAME_SZ];
    char gearbox_full_name[DEV_NAME_SZ];
    unsigned char i2c_secondary;
    u_int8_t addr_width;
    char device_orig_name[DEV_NAME_SZ];
    char device_real_name[DEV_NAME_SZ];
    u_int32_t data_req_addr;
    u_int32_t data_res_addr;
} gearbox_info;

typedef struct retimer_info_t
{
    int retimer_index;
    retimer_connection_t rt_conn_type;
    char mst_dev_name[DEV_NAME_SZ];
    unsigned char i2c_secondary;
    u_int8_t addr_width;
    char cable_name[DEV_NAME_SZ];
} retimer_info;

typedef struct cables_info_t
{
    int secondary_addr_additional_offset;
} cables_info;

#define HW_ID_ADDR 0xf0014
#define MLNX_PCI_VENDOR_ID 0x15b3
#define NVDA_PCI_VENDOR_ID 0x10de

enum mtcr_mad_types
{
    SMP,
    GMP,
    CLASS_A
};

enum
{
    MAD_CLASS_1_REG_ACCESS = 1,
    MAD_CLASS_A_REG_ACCESS = 0x0A,
};

#define MAX_TILE_NUM 8

typedef struct address_boundary_t
{
    u_int8_t is_active;
    u_int32_t min;
    u_int32_t max;
} addr_bound;

// *************************************
// INTERNAL ONLY
// Do not export to mstflint!!!!!!!
// *************************************
#ifndef MST_UL
enum cpo_device_type
{
    VIRTUAL_MODULE = 0,
    VMDL_ELS = 1,
    VMDL_OE_0 = 2,
    VMDL_OE_1 = 3,
};
#endif

typedef struct virtual_module_info_t
{
#ifndef MST_UL
    enum cpo_device_type type; // 0: virtual module, 1: ELS, 2: OE_0, 3: OE_1
#endif
    u_int8_t is_vmdl_device;
    u_int8_t local_module_num; // Local module number for FW to send MCIA
} virtual_module_info;

#endif // _MTCR_COM_DEFS_H