/*-
 * Copyright (c) 2009-2012 Microsoft Corp.
 * Copyright (c) 2010-2012 Citrix Inc.
 * Copyright (c) 2012 NetApp Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice unmodified, this list of conditions, and the following
 *    disclaimer.
 * 2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * $FreeBSD: head/sys/dev/hyperv/netvsc/hv_net_vsc.h 274231 2014-11-07 15:14:10Z glebius $
 */

/*
 * HyperV vmbus (virtual machine bus) network VSC (virtual services client)
 * header file
 *
 * (Updated from unencumbered NvspProtocol.h)
 */

#ifndef __HV_NET_VSC_H__
#define __HV_NET_VSC_H__

#include <sys/types.h>
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/sx.h>

#include <dev/hyperv/include/hyperv.h>


#define NVSP_INVALID_PROTOCOL_VERSION           (0xFFFFFFFF)

#define NVSP_PROTOCOL_VERSION_1                 2
#define NVSP_PROTOCOL_VERSION_2                 0x30002
#define NVSP_MIN_PROTOCOL_VERSION               (NVSP_PROTOCOL_VERSION_1)
#define NVSP_MAX_PROTOCOL_VERSION               (NVSP_PROTOCOL_VERSION_2)

#define NVSP_PROTOCOL_VERSION_CURRENT           NVSP_PROTOCOL_VERSION_2

#define NVSP_OPERATIONAL_STATUS_OK              (0x00000000)
#define NVSP_OPERATIONAL_STATUS_DEGRADED        (0x00000001)
#define NVSP_OPERATIONAL_STATUS_NONRECOVERABLE  (0x00000002)
#define NVSP_OPERATIONAL_STATUS_NO_CONTACT      (0x00000003)
#define NVSP_OPERATIONAL_STATUS_LOST_COMMUNICATION (0x00000004)

/*
 * Maximun number of transfer pages (packets) the VSP will use on a receive
 */
#define NVSP_MAX_PACKETS_PER_RECEIVE            375


typedef enum nvsp_msg_type_ {
	nvsp_msg_type_none                      = 0,

	/*
	 * Init Messages
	 */
	nvsp_msg_type_init                      = 1,
	nvsp_msg_type_init_complete             = 2,

	nvsp_version_msg_start                  = 100,

	/*
	 * Version 1 Messages
	 */
	nvsp_msg_1_type_send_ndis_vers          = nvsp_version_msg_start,

	nvsp_msg_1_type_send_rx_buf,
	nvsp_msg_1_type_send_rx_buf_complete,
	nvsp_msg_1_type_revoke_rx_buf,

	nvsp_msg_1_type_send_send_buf,
	nvsp_msg_1_type_send_send_buf_complete,
	nvsp_msg_1_type_revoke_send_buf,

	nvsp_msg_1_type_send_rndis_pkt,
	nvsp_msg_1_type_send_rndis_pkt_complete,
    
	/*
	 * Version 2 Messages
	 */
	nvsp_msg_2_type_send_chimney_delegated_buf,
	nvsp_msg_2_type_send_chimney_delegated_buf_complete,
	nvsp_msg_2_type_revoke_chimney_delegated_buf,

	nvsp_msg_2_type_resume_chimney_rx_indication,

	nvsp_msg_2_type_terminate_chimney,
	nvsp_msg_2_type_terminate_chimney_complete,

	nvsp_msg_2_type_indicate_chimney_event,

	nvsp_msg_2_type_send_chimney_packet,
	nvsp_msg_2_type_send_chimney_packet_complete,

	nvsp_msg_2_type_post_chimney_rx_request,
	nvsp_msg_2_type_post_chimney_rx_request_complete,

	nvsp_msg_2_type_alloc_rx_buf,
	nvsp_msg_2_type_alloc_rx_buf_complete,

	nvsp_msg_2_type_free_rx_buf,

	nvsp_msg_2_send_vmq_rndis_pkt,
	nvsp_msg_2_send_vmq_rndis_pkt_complete,

	nvsp_msg_2_type_send_ndis_config,

	nvsp_msg_2_type_alloc_chimney_handle,
	nvsp_msg_2_type_alloc_chimney_handle_complete,
} nvsp_msg_type;

typedef enum nvsp_status_ {
	nvsp_status_none = 0,
	nvsp_status_success,
	nvsp_status_failure,
	/* Deprecated */
	nvsp_status_prot_vers_range_too_new,
	/* Deprecated */
	nvsp_status_prot_vers_range_too_old,
	nvsp_status_invalid_rndis_pkt,
	nvsp_status_busy,
	nvsp_status_max,
} nvsp_status;

typedef struct nvsp_msg_hdr_ {
	uint32_t                                msg_type;
} __packed nvsp_msg_hdr;

/*
 * Init Messages
 */

/*
 * This message is used by the VSC to initialize the channel
 * after the channels has been opened. This message should 
 * never include anything other then versioning (i.e. this
 * message will be the same for ever).
 *
 * Forever is a long time.  The values have been redefined
 * in Win7 to indicate major and minor protocol version
 * number.
 */
typedef struct nvsp_msg_init_ {
	union {
		struct {
			uint16_t                minor_protocol_version;
			uint16_t                major_protocol_version;
		} s;
		/* Formerly min_protocol_version */
		uint32_t                        protocol_version;
	} p1;
	/* Formerly max_protocol_version */
	uint32_t                                protocol_version_2;
} __packed nvsp_msg_init;

/*
 * This message is used by the VSP to complete the initialization
 * of the channel. This message should never include anything other 
 * then versioning (i.e. this message will be the same forever).
 */
typedef struct nvsp_msg_init_complete_ {
	/* Deprecated */
	uint32_t                                negotiated_prot_vers;
	uint32_t                                max_mdl_chain_len;
	uint32_t                                status;
} __packed nvsp_msg_init_complete;

typedef union nvsp_msg_init_uber_ {
	nvsp_msg_init                           init;
	nvsp_msg_init_complete                  init_compl;
} __packed nvsp_msg_init_uber;

/*
 * Version 1 Messages
 */

/*
 * This message is used by the VSC to send the NDIS version
 * to the VSP.  The VSP can use this information when handling
 * OIDs sent by the VSC.
 */
typedef struct nvsp_1_msg_send_ndis_version_ {
	uint32_t                                ndis_major_vers;
	/* Deprecated */
	uint32_t                                ndis_minor_vers;
} __packed nvsp_1_msg_send_ndis_version;

/*
 * This message is used by the VSC to send a receive buffer
 * to the VSP. The VSP can then use the receive buffer to
 * send data to the VSC.
 */
typedef struct nvsp_1_msg_send_rx_buf_ {
	uint32_t                                gpadl_handle;
	uint16_t                                id;
} __packed nvsp_1_msg_send_rx_buf;

typedef struct nvsp_1_rx_buf_section_ {
	uint32_t                                offset;
	uint32_t                                sub_allocation_size;
	uint32_t                                num_sub_allocations;
	uint32_t                                end_offset;
} __packed nvsp_1_rx_buf_section;

/*
 * This message is used by the VSP to acknowledge a receive 
 * buffer send by the VSC.  This message must be sent by the 
 * VSP before the VSP uses the receive buffer.
 */
typedef struct nvsp_1_msg_send_rx_buf_complete_ {
	uint32_t                                status;
	uint32_t                                num_sections;

	/*
	 * The receive buffer is split into two parts, a large
	 * suballocation section and a small suballocation
	 * section. These sections are then suballocated by a 
	 * certain size.
	 *
	 * For example, the following break up of the receive
	 * buffer has 6 large suballocations and 10 small
	 * suballocations.
	 *
	 * |            Large Section          |  |   Small Section   |
	 * ------------------------------------------------------------
	 * |     |     |     |     |     |     |  | | | | | | | | | | |
	 * |                                      |  
	 * LargeOffset                            SmallOffset
	 */
	nvsp_1_rx_buf_section                   sections[1];

} __packed nvsp_1_msg_send_rx_buf_complete;

/*
 * This message is sent by the VSC to revoke the receive buffer.
 * After the VSP completes this transaction, the VSP should never
 * use the receive buffer again.
 */
typedef struct nvsp_1_msg_revoke_rx_buf_ {
	uint16_t                                id;
} __packed nvsp_1_msg_revoke_rx_buf;

/*
 * This message is used by the VSC to send a send buffer
 * to the VSP. The VSC can then use the send buffer to
 * send data to the VSP.
 */
typedef struct nvsp_1_msg_send_send_buf_ {
	uint32_t                                gpadl_handle;
	uint16_t                                id;
} __packed nvsp_1_msg_send_send_buf;

/*
 * This message is used by the VSP to acknowledge a send 
 * buffer sent by the VSC. This message must be sent by the 
 * VSP before the VSP uses the sent buffer.
 */
typedef struct nvsp_1_msg_send_send_buf_complete_ {
	uint32_t                                status;

	/*
	 * The VSC gets to choose the size of the send buffer and
	 * the VSP gets to choose the sections size of the buffer.
	 * This was done to enable dynamic reconfigurations when
	 * the cost of GPA-direct buffers decreases.
	 */
	uint32_t                                section_size;
} __packed nvsp_1_msg_send_send_buf_complete;

/*
 * This message is sent by the VSC to revoke the send buffer.
 * After the VSP completes this transaction, the vsp should never
 * use the send buffer again.
 */
typedef struct nvsp_1_msg_revoke_send_buf_ {
	uint16_t                                id;
} __packed nvsp_1_msg_revoke_send_buf;

/*
 * This message is used by both the VSP and the VSC to send
 * an RNDIS message to the opposite channel endpoint.
 */
typedef struct nvsp_1_msg_send_rndis_pkt_ {
	/*
	 * This field is specified by RNIDS.  They assume there's
	 * two different channels of communication. However, 
	 * the Network VSP only has one.  Therefore, the channel
	 * travels with the RNDIS packet.
	 */
	uint32_t                                chan_type;

	/*
	 * This field is used to send part or all of the data
	 * through a send buffer. This values specifies an 
	 * index into the send buffer.  If the index is 
	 * 0xFFFFFFFF, then the send buffer is not being used
	 * and all of the data was sent through other VMBus
	 * mechanisms.
	 */
	uint32_t                                send_buf_section_idx;
	uint32_t                                send_buf_section_size;
} __packed nvsp_1_msg_send_rndis_pkt;

/*
 * This message is used by both the VSP and the VSC to complete
 * a RNDIS message to the opposite channel endpoint.  At this
 * point, the initiator of this message cannot use any resources
 * associated with the original RNDIS packet.
 */
typedef struct nvsp_1_msg_send_rndis_pkt_complete_ {
	uint32_t                                status;
} __packed nvsp_1_msg_send_rndis_pkt_complete;


/*
 * Version 2 Messages
 */

/*
 * This message is used by the VSC to send the NDIS version
 * to the VSP.  The VSP can use this information when handling
 * OIDs sent by the VSC.
 */
typedef struct nvsp_2_netvsc_capabilities_ {
	union {
		uint64_t                        as_uint64;
		struct {
			uint64_t                vmq           : 1;
			uint64_t                chimney       : 1;
			uint64_t                sriov         : 1;
			uint64_t                ieee8021q     : 1;
			uint64_t                correlationid : 1;
			uint64_t                teaming       : 1;
		} u2;
	} u1;
} __packed nvsp_2_netvsc_capabilities;

typedef struct nvsp_2_msg_send_ndis_config_ {
	uint32_t                                mtu;
	uint32_t                                reserved;
	nvsp_2_netvsc_capabilities              capabilities;
} __packed nvsp_2_msg_send_ndis_config;

/*
 * NvspMessage2TypeSendChimneyDelegatedBuffer
 */
typedef struct nvsp_2_msg_send_chimney_buf_
{
	/*
	 * On WIN7 beta, delegated_obj_max_size is defined as a uint32_t
	 * Since WIN7 RC, it was split into two uint16_t.  To have the same
	 * struct layout, delegated_obj_max_size shall be the first field.
	 */
	uint16_t                                delegated_obj_max_size;

	/*
	 * The revision # of chimney protocol used between NVSC and NVSP.
	 *
	 * This revision is NOT related to the chimney revision between
	 * NDIS protocol and miniport drivers.
	 */
	uint16_t                                revision;

	uint32_t                                gpadl_handle;
} __packed nvsp_2_msg_send_chimney_buf;


/* Unsupported chimney revision 0 (only present in WIN7 beta) */
#define NVSP_CHIMNEY_REVISION_0                 0

/* WIN7 Beta Chimney QFE */
#define NVSP_CHIMNEY_REVISION_1                 1

/* The chimney revision since WIN7 RC */
#define NVSP_CHIMNEY_REVISION_2                 2


/*
 * NvspMessage2TypeSendChimneyDelegatedBufferComplete
 */
typedef struct nvsp_2_msg_send_chimney_buf_complete_ {
	uint32_t                                status;

	/*
	 * Maximum number outstanding sends and pre-posted receives.
	 *
	 * NVSC should not post more than SendQuota/ReceiveQuota packets.
	 * Otherwise, it can block the non-chimney path for an indefinite
	 * amount of time.
	 * (since chimney sends/receives are affected by the remote peer).
	 *
	 * Note: NVSP enforces the quota restrictions on a per-VMBCHANNEL
	 * basis.  It doesn't enforce the restriction separately for chimney
	 * send/receive.  If NVSC doesn't voluntarily enforce "SendQuota",
	 * it may kill its own network connectivity.
	 */
	uint32_t                                send_quota;
	uint32_t                                rx_quota;
} __packed nvsp_2_msg_send_chimney_buf_complete;

/*
 * NvspMessage2TypeRevokeChimneyDelegatedBuffer
 */
typedef struct nvsp_2_msg_revoke_chimney_buf_ {
	uint32_t                                gpadl_handle;
} __packed nvsp_2_msg_revoke_chimney_buf;


#define NVSP_CHIMNEY_OBJECT_TYPE_NEIGHBOR       0
#define NVSP_CHIMNEY_OBJECT_TYPE_PATH4          1
#define NVSP_CHIMNEY_OBJECT_TYPE_PATH6          2
#define NVSP_CHIMNEY_OBJECT_TYPE_TCP            3

/*
 * NvspMessage2TypeAllocateChimneyHandle
 */
typedef struct nvsp_2_msg_alloc_chimney_handle_ {
	uint64_t                                vsc_context;
	uint32_t                                object_type;
} __packed nvsp_2_msg_alloc_chimney_handle;

/*
 * NvspMessage2TypeAllocateChimneyHandleComplete
 */
typedef struct nvsp_2_msg_alloc_chimney_handle_complete_ {
	uint32_t                                vsp_handle;
} __packed nvsp_2_msg_alloc_chimney_handle_complete;


/*
 * NvspMessage2TypeResumeChimneyRXIndication
 */
typedef struct nvsp_2_msg_resume_chimney_rx_indication {
	/*
	 * Handle identifying the offloaded connection
	 */
	uint32_t                                vsp_tcp_handle;
} __packed nvsp_2_msg_resume_chimney_rx_indication;


#define NVSP_2_MSG_TERMINATE_CHIMNEY_FLAGS_FIRST_STAGE      (0x01u)
#define NVSP_2_MSG_TERMINATE_CHIMNEY_FLAGS_RESERVED         (~(0x01u))

/*
 * NvspMessage2TypeTerminateChimney
 */
typedef struct nvsp_2_msg_terminate_chimney_ {
	/*
	* Handle identifying the offloaded object
	*/
	uint32_t                                vsp_handle;

	/*
	 * Terminate Offload Flags
	 *     Bit 0:
	 *         When set to 0, terminate the offload at the destination NIC
	 *     Bit 1-31:  Reserved, shall be zero
	 */
	uint32_t                                flags;

	union {
		/*
		 * This field is valid only when bit 0 of flags is clear.
		 * It specifies the index into the premapped delegated
		 * object buffer.  The buffer was sent through the
		 * NvspMessage2TypeSendChimneyDelegatedBuffer
		 * message at initialization time.
		 *
		 * NVSP will write the delegated state into the delegated
		 * buffer upon upload completion.
		 */
		uint32_t                        index;

		/*
		 * This field is valid only when bit 0 of flags is set.
		 *
		 * The seqence number of the most recently accepted RX
		 * indication when VSC sets its TCP context into
		 * "terminating" state.
		 *
		 * This allows NVSP to determines if there are any in-flight
		 * RX indications for which the acceptance state is still
		 * undefined.
		 */
		uint64_t                        last_accepted_rx_seq_no;
	} f0;
} __packed nvsp_2_msg_terminate_chimney;


#define NVSP_TERMINATE_CHIMNEY_COMPLETE_FLAG_DATA_CORRUPTED     0x0000001u

/*
 * NvspMessage2TypeTerminateChimneyComplete
 */
typedef struct nvsp_2_msg_terminate_chimney_complete_ {
	uint64_t                                vsc_context;
	uint32_t                                flags;
} __packed nvsp_2_msg_terminate_chimney_complete;

/*
 * NvspMessage2TypeIndicateChimneyEvent
 */
typedef struct nvsp_2_msg_indicate_chimney_event_ {
	/*
	 * When VscTcpContext is 0, event_type is an NDIS_STATUS event code
	 * Otherwise, EventType is an TCP connection event (defined in
	 * NdisTcpOffloadEventHandler chimney DDK document).
	 */
	uint32_t                                event_type;

	/*
	 * When VscTcpContext is 0, EventType is an NDIS_STATUS event code
	 * Otherwise, EventType is an TCP connection event specific information
	 * (defined in NdisTcpOffloadEventHandler chimney DDK document).
	 */
	uint32_t                                event_specific_info;

	/*
	 * If not 0, the event is per-TCP connection event.  This field
	 * contains the VSC's TCP context.
	 * If 0, the event indication is global.
	 */
	uint64_t                                vsc_tcp_context;
} __packed nvsp_2_msg_indicate_chimney_event;


#define NVSP_1_CHIMNEY_SEND_INVALID_OOB_INDEX       0xffffu
#define NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX   0xffffu

/*
 * NvspMessage2TypeSendChimneyPacket
 */
typedef struct nvsp_2_msg_send_chimney_pkt_ {
    /*
     * Identify the TCP connection for which this chimney send is
     */
    uint32_t                                    vsp_tcp_handle;

    /*
     * This field is used to send part or all of the data
     * through a send buffer. This values specifies an
     * index into the send buffer. If the index is
     * 0xFFFF, then the send buffer is not being used
     * and all of the data was sent through other VMBus
     * mechanisms.
     */
    uint16_t                                    send_buf_section_index;
    uint16_t                                    send_buf_section_size;

    /*
     * OOB Data Index
     * This an index to the OOB data buffer. If the index is 0xFFFFFFFF,
     * then there is no OOB data.
     *
     * This field shall be always 0xFFFFFFFF for now. It is reserved for
     * the future.
     */
    uint16_t                                    oob_data_index;

    /*
     * DisconnectFlags = 0
     *      Normal chimney send. See MiniportTcpOffloadSend for details.
     *
     * DisconnectFlags = TCP_DISCONNECT_GRACEFUL_CLOSE (0x01)
     *      Graceful disconnect. See MiniportTcpOffloadDisconnect for details.
     *
     * DisconnectFlags = TCP_DISCONNECT_ABORTIVE_CLOSE (0x02)
     *      Abortive disconnect. See MiniportTcpOffloadDisconnect for details.
     */
    uint16_t                                    disconnect_flags;

    uint32_t                                    seq_no;
} __packed nvsp_2_msg_send_chimney_pkt;

/*
 * NvspMessage2TypeSendChimneyPacketComplete
 */
typedef struct nvsp_2_msg_send_chimney_pkt_complete_ {
    /*
     * The NDIS_STATUS for the chimney send
     */
    uint32_t                                    status;

    /*
     * Number of bytes that have been sent to the peer (and ACKed by the peer).
     */
    uint32_t                                    bytes_transferred;
} __packed nvsp_2_msg_send_chimney_pkt_complete;


#define NVSP_1_CHIMNEY_RECV_FLAG_NO_PUSH        0x0001u
#define NVSP_1_CHIMNEY_RECV_INVALID_OOB_INDEX   0xffffu

/*
 * NvspMessage2TypePostChimneyRecvRequest
 */
typedef struct nvsp_2_msg_post_chimney_rx_request_ {
	/*
	 * Identify the TCP connection which this chimney receive request
	 * is for.
	 */
	uint32_t                                vsp_tcp_handle;

	/*
	 * OOB Data Index
	 * This an index to the OOB data buffer. If the index is 0xFFFFFFFF,
	 * then there is no OOB data.
	 *
	 * This field shall be always 0xFFFFFFFF for now. It is reserved for
	 * the future.
	 */
	uint32_t                                oob_data_index;

	/*
	 * Bit 0
	 *      When it is set, this is a "no-push" receive.
	 *      When it is clear, this is a "push" receive.
	 *
	 * Bit 1-15:  Reserved and shall be zero
	 */
	uint16_t                                flags;

	/*
	 * For debugging and diagnoses purpose.
	 * The SeqNo is per TCP connection and starts from 0.
	 */
	uint32_t                                seq_no;
} __packed nvsp_2_msg_post_chimney_rx_request;

/*
 * NvspMessage2TypePostChimneyRecvRequestComplete
 */
typedef struct nvsp_2_msg_post_chimney_rx_request_complete_ {
	/*
	 * The NDIS_STATUS for the chimney send
	 */
	uint32_t                                status;

	/*
	 * Number of bytes that have been sent to the peer (and ACKed by
	 * the peer).
	 */
	uint32_t                                bytes_xferred;
} __packed nvsp_2_msg_post_chimney_rx_request_complete;

/*
 * NvspMessage2TypeAllocateReceiveBuffer
 */
typedef struct nvsp_2_msg_alloc_rx_buf_ {
	/*
	 * Allocation ID to match the allocation request and response
	 */
	uint32_t                                allocation_id;

	/*
	 * Length of the VM shared memory receive buffer that needs to
	 * be allocated
	 */
	uint32_t                                length;
} __packed nvsp_2_msg_alloc_rx_buf;

/*
 * NvspMessage2TypeAllocateReceiveBufferComplete
 */
typedef struct nvsp_2_msg_alloc_rx_buf_complete_ {
	/*
	 * The NDIS_STATUS code for buffer allocation
	 */
	uint32_t                                status;

	/*
	 * Allocation ID from NVSP_2_MESSAGE_ALLOCATE_RECEIVE_BUFFER
	 */
	uint32_t                                allocation_id;

	/*
	 * GPADL handle for the allocated receive buffer
	 */
	uint32_t                                gpadl_handle;

	/*
	 * Receive buffer ID that is further used in
	 * NvspMessage2SendVmqRndisPacket
	 */
	uint64_t                                rx_buf_id;
} __packed nvsp_2_msg_alloc_rx_buf_complete;

/*
 * NvspMessage2TypeFreeReceiveBuffer
 */
typedef struct nvsp_2_msg_free_rx_buf_ {
	/*
	 * Receive buffer ID previous returned in
	 * NvspMessage2TypeAllocateReceiveBufferComplete message
	 */
	uint64_t                                rx_buf_id;
} __packed nvsp_2_msg_free_rx_buf;

/*
 * This structure is used in defining the buffers in
 * NVSP_2_MESSAGE_SEND_VMQ_RNDIS_PACKET structure
 */
typedef struct nvsp_xfer_page_range_ {
	/*
	 * Specifies the ID of the receive buffer that has the buffer. This
	 * ID can be the general receive buffer ID specified in
	 * NvspMessage1TypeSendReceiveBuffer or it can be the shared memory
	 * receive buffer ID allocated by the VSC and specified in
	 * NvspMessage2TypeAllocateReceiveBufferComplete message
	 */
	uint64_t                                xfer_page_set_id;

	/*
	 * Number of bytes
	 */
	uint32_t                                byte_count;

	/*
	 * Offset in bytes from the beginning of the buffer
	 */
	uint32_t                                byte_offset;
} __packed nvsp_xfer_page_range;

/*
 * NvspMessage2SendVmqRndisPacket
 */
typedef struct nvsp_2_msg_send_vmq_rndis_pkt_ {
	/*
	 * This field is specified by RNIDS. They assume there's
	 * two different channels of communication. However,
	 * the Network VSP only has one. Therefore, the channel
	 * travels with the RNDIS packet. It must be RMC_DATA
	 */
	uint32_t                                channel_type;

	/*
	 * Only the Range element corresponding to the RNDIS header of
	 * the first RNDIS message in the multiple RNDIS messages sent
	 * in one NVSP message.  Information about the data portions as well
	 * as the subsequent RNDIS messages in the same NVSP message are
	 * embedded in the RNDIS header itself
	 */
	nvsp_xfer_page_range                    range;
} __packed nvsp_2_msg_send_vmq_rndis_pkt;

/*
 * This message is used by the VSC to complete
 * a RNDIS VMQ message to the VSP.  At this point,
 * the initiator of this message can use any resources
 * associated with the original RNDIS VMQ packet.
 */
typedef struct nvsp_2_msg_send_vmq_rndis_pkt_complete_
{
	uint32_t                                status;
} __packed nvsp_2_msg_send_vmq_rndis_pkt_complete;


typedef union nvsp_1_msg_uber_ {
	nvsp_1_msg_send_ndis_version            send_ndis_vers;

	nvsp_1_msg_send_rx_buf                  send_rx_buf;
	nvsp_1_msg_send_rx_buf_complete         send_rx_buf_complete;
	nvsp_1_msg_revoke_rx_buf                revoke_rx_buf;

	nvsp_1_msg_send_send_buf                send_send_buf;
	nvsp_1_msg_send_send_buf_complete       send_send_buf_complete;
	nvsp_1_msg_revoke_send_buf              revoke_send_buf;

	nvsp_1_msg_send_rndis_pkt               send_rndis_pkt;
	nvsp_1_msg_send_rndis_pkt_complete      send_rndis_pkt_complete;
} __packed nvsp_1_msg_uber;


typedef union nvsp_2_msg_uber_ {
	nvsp_2_msg_send_ndis_config             send_ndis_config;

	nvsp_2_msg_send_chimney_buf             send_chimney_buf;
	nvsp_2_msg_send_chimney_buf_complete    send_chimney_buf_complete;
	nvsp_2_msg_revoke_chimney_buf           revoke_chimney_buf;

	nvsp_2_msg_resume_chimney_rx_indication resume_chimney_rx_indication;
	nvsp_2_msg_terminate_chimney            terminate_chimney;
	nvsp_2_msg_terminate_chimney_complete   terminate_chimney_complete;
	nvsp_2_msg_indicate_chimney_event       indicate_chimney_event;

	nvsp_2_msg_send_chimney_pkt             send_chimney_packet;
	nvsp_2_msg_send_chimney_pkt_complete    send_chimney_packet_complete;
	nvsp_2_msg_post_chimney_rx_request      post_chimney_rx_request;
	nvsp_2_msg_post_chimney_rx_request_complete
	                                       post_chimney_rx_request_complete;

	nvsp_2_msg_alloc_rx_buf                 alloc_rx_buffer;
	nvsp_2_msg_alloc_rx_buf_complete        alloc_rx_buffer_complete;
	nvsp_2_msg_free_rx_buf                  free_rx_buffer;

	nvsp_2_msg_send_vmq_rndis_pkt           send_vmq_rndis_pkt;
	nvsp_2_msg_send_vmq_rndis_pkt_complete  send_vmq_rndis_pkt_complete;
	nvsp_2_msg_alloc_chimney_handle         alloc_chimney_handle;
	nvsp_2_msg_alloc_chimney_handle_complete alloc_chimney_handle_complete;
} __packed nvsp_2_msg_uber;


typedef union nvsp_all_msgs_ {
	nvsp_msg_init_uber                      init_msgs;
	nvsp_1_msg_uber                         vers_1_msgs;
	nvsp_2_msg_uber                         vers_2_msgs;
} __packed nvsp_all_msgs;

/*
 * ALL Messages
 */
typedef struct nvsp_msg_ {
	nvsp_msg_hdr                            hdr; 
	nvsp_all_msgs                           msgs;
} __packed nvsp_msg;


/*
 * The following arguably belongs in a separate header file
 */

/*
 * Defines
 */

#define NETVSC_SEND_BUFFER_SIZE			(64*1024)   /* 64K */
#define NETVSC_SEND_BUFFER_ID			0xface


#define NETVSC_RECEIVE_BUFFER_SIZE		(1024*1024) /* 1MB */

#define NETVSC_RECEIVE_BUFFER_ID		0xcafe

#define NETVSC_RECEIVE_SG_COUNT			1

/* Preallocated receive packets */
#define NETVSC_RECEIVE_PACKETLIST_COUNT		256

/*
 * Maximum MTU we permit to be configured for a netvsc interface.
 * When the code was developed, a max MTU of 12232 was tested and
 * proven to work.  9K is a reasonable maximum for an Ethernet.
 */
#define NETVSC_MAX_CONFIGURABLE_MTU		(9 * 1024)

/*
 * Data types
 */

/*
 * Per netvsc channel-specific
 */
typedef struct netvsc_dev_ {
	struct hv_device			*dev;
	int					num_outstanding_sends;

	/* List of free preallocated NETVSC_PACKET to represent RX packet */
	STAILQ_HEAD(PQ, netvsc_packet_)		myrx_packet_list;
	struct mtx				rx_pkt_list_lock;

	/* Send buffer allocated by us but manages by NetVSP */
	void					*send_buf;
	uint32_t				send_buf_size;
	uint32_t				send_buf_gpadl_handle;
	uint32_t				send_section_size;

	/* Receive buffer allocated by us but managed by NetVSP */
	void					*rx_buf;
	uint32_t				rx_buf_size;
	uint32_t				rx_buf_gpadl_handle;
	uint32_t				rx_section_count;
	nvsp_1_rx_buf_section			*rx_sections;

	/* Used for NetVSP initialization protocol */
	struct sema				channel_init_sema;
	nvsp_msg				channel_init_packet;

	nvsp_msg				revoke_packet;
	/*uint8_t				hw_mac_addr[HW_MACADDR_LEN];*/

	/* Holds rndis device info */
	void					*extension;

	hv_bool_uint8_t				destroy;
	/* Negotiated NVSP version */
	uint32_t				nvsp_version;
} netvsc_dev;


typedef void (*pfn_on_send_rx_completion)(void *);

#define NETVSC_DEVICE_RING_BUFFER_SIZE   (64 * PAGE_SIZE)
#define NETVSC_PACKET_MAXPAGE            16


typedef struct xfer_page_packet_ {
	/*
	 * This needs to be here because the network RX code casts
	 * an instantiation of this structure to a netvsc_packet.
	 */
	STAILQ_ENTRY(netvsc_packet_) mylist_entry;

	uint32_t count;
} xfer_page_packet;

typedef struct netvsc_packet_ {
	/*
	 * List used when enqueued on &net_dev->rx_packet_list,
	 * and when enqueued within the netvsc code
	 */
	STAILQ_ENTRY(netvsc_packet_) mylist_entry;
	struct hv_device           *device;
	hv_bool_uint8_t            is_data_pkt;      /* One byte */
	uint16_t		   vlan_tci;
	xfer_page_packet           *xfer_page_pkt;

	/* Completion */
	union {
		struct {
			uint64_t   rx_completion_tid;
			void	   *rx_completion_context;
			/* This is no longer used */
			pfn_on_send_rx_completion   on_rx_completion;
		} rx;
		struct {
			uint64_t    send_completion_tid;
			void	    *send_completion_context;
			/* Still used in netvsc and filter code */
			pfn_on_send_rx_completion   on_send_completion;
		} send;
	} compl;

	void		*extension;
	uint32_t	tot_data_buf_len;
	uint32_t	page_buf_count;
	hv_vmbus_page_buffer	page_buffers[NETVSC_PACKET_MAXPAGE];
} netvsc_packet;

typedef struct {
	uint8_t		mac_addr[6];  /* Assumption unsigned long */
	hv_bool_uint8_t	link_state;
} netvsc_device_info;

/*
 * Device-specific softc structure
 */
typedef struct hn_softc {
	struct ifnet    *hn_ifp;
	device_t        hn_dev;
	uint8_t         hn_unit;
	int             hn_carrier;
	int             hn_if_flags;
	struct mtx      hn_lock;
	int             hn_initdone;
	/* See hv_netvsc_drv_freebsd.c for rules on how to use */
	int             temp_unusable;
	struct hv_device  *hn_dev_obj;
	netvsc_dev  	*net_dev;
} hn_softc_t;


/*
 * Externs
 */
extern int hv_promisc_mode;

extern void netvsc_linkstatus_callback(struct hv_device *device_obj,
				       uint32_t status);
extern int  netvsc_recv(struct hv_device *device_obj, netvsc_packet *packet);
extern void netvsc_xmit_completion(void *context);

extern void hv_nv_on_receive_completion(void *context);
extern netvsc_dev *hv_nv_on_device_add(struct hv_device *device, void *additional_info);
extern int  hv_nv_on_device_remove(struct hv_device *device,
				   boolean_t destroy_channel);
extern int  hv_nv_on_send(struct hv_device *device, netvsc_packet *pkt);

#endif  /* __HV_NET_VSC_H__ */

