/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef _SYS_XPVTAP_H
#define	_SYS_XPVTAP_H


#ifdef __cplusplus
extern "C" {
#endif

#include <sys/types.h>

/* Notification from user app that it has pushed responses */
#define	XPVTAP_IOCTL_RESP_PUSH		1

/* Number of bytes the user app should mmap for the gref pages */
#define	XPVTAP_GREF_BUFSIZE	\
	(BLKIF_RING_SIZE * BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGESIZE)


#ifdef	_KERNEL

#include <xen/io/blk_common.h>


#define	XPVTAP_GREF_REQADDR(base, id) (caddr_t) \
	((uintptr_t)base + (id * BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGESIZE))

/* structure used to keep track of resources */
typedef struct xpvtap_rs_s {
	/*
	 * Bounds of resource allocation. We will start allocating at rs_min
	 * and rollover at rs_max+1 (rs_max is included). e.g. for rs_min=0
	 * and rs_max=7, we will have 8 total resources which can be alloced.
	 */
	uint_t rs_min;
	uint_t rs_max;

	/*
	 * rs_free points to an array of 64-bit values used to track resource
	 * allocation. rs_free_size is the free buffer size in bytes.
	 */
	uint64_t *rs_free;
	uint_t rs_free_size;

	/*
	 * last tracks the last alloc'd resource. This allows us to do a round
	 * robin allocation.
	 */
	uint_t rs_last;

	/*
	 * set when flushing all allocated resources. We'll know the lock
	 * is held.
	 */
	boolean_t rs_flushing;

	kmutex_t rs_mutex;
} xpvtap_rs_t;
typedef struct xpvtap_rs_s *xpvtap_rs_hdl_t;

/* track if user app has the device open, and sleep waiting for close */
typedef struct xpvtap_open_s {
	kmutex_t	bo_mutex;
	boolean_t	bo_opened;
	kcondvar_t	bo_exit_cv;
} xpvtap_open_t;

/*
 * ring between driver and user app. requests are forwared from the
 * guest to the user app on this ring. reponses from the user app come in
 * on this ring are then are forwarded to the guest.
 */
typedef struct xpvtap_user_ring_s {
	/* ring state */
	blkif_front_ring_t	ur_ring;

	/*
	 * pointer to allocated memory for the ring which is shared between
	 * the driver and the app.
	 */
	blkif_sring_t		*ur_sring;

	/* umem cookie for free'ing up the umem */
	ddi_umem_cookie_t	ur_cookie;

	RING_IDX		ur_prod_polled;
} xpvtap_user_ring_t;

/*
 * track the requests that come in from the guest. we need to track the
 * requests for two reasons. first, we need to know how many grefs we need
 * to unmap when the app sends the response. second, since we use the ID in
 * the request to index into um_guest_pages (tells the app where the segments
 * are mapped), we need to have a mapping between the the ID we sent in the
 * request to the app and the ID we got from the guest request. The response
 * to the guest needs to have the later.
 */
typedef struct xpvtap_user_map_s {
	/* address space of the user app. grab this in open */
	struct as		*um_as;

	/* state to track request IDs we can send to the user app */
	xpvtap_rs_hdl_t		um_rs;

	/*
	 * base user app VA of the mapped grefs. this VA space is large enough
	 * to map the max pages per request * max outstanding requests.
	 */
	caddr_t			um_guest_pages;
	size_t			um_guest_size;

	/*
	 * have we locked down the gref buffer's ptes and registered
	 * them with segmf. This needs to happen after the user app
	 * has mmaped the gref buf.
	 */
	boolean_t		um_registered;

	/*
	 * array of outstanding requests to the user app. Index into this
	 * array using the ID in the user app request.
	 */
	blkif_request_t		*um_outstanding_reqs;
} xpvtap_user_map_t;

/* thread start, wake, exit state */
typedef struct xpvtap_user_thread_s {
	kmutex_t		ut_mutex;
	kcondvar_t		ut_wake_cv;
	volatile boolean_t	ut_wake;
	volatile boolean_t	ut_exit;
	kcondvar_t		ut_exit_done_cv;
	volatile boolean_t	ut_exit_done;
	ddi_taskq_t		*ut_taskq;
} xpvtap_user_thread_t;

/* driver state */
typedef struct xpvtap_state_s {
	dev_info_t		*bt_dip;
	int			bt_instance;

	/* ring between the guest and xpvtap */
	blk_ring_t		bt_guest_ring;

	/* ring between xpvtap and the user app */
	xpvtap_user_ring_t	bt_user_ring;

	xpvtap_user_map_t	bt_map;
	xpvtap_user_thread_t	bt_thread;
	struct pollhead		bt_pollhead;
	xpvtap_open_t		bt_open;
} xpvtap_state_t;

#endif /* _KERNEL */

#ifdef __cplusplus
}
#endif

#endif /* _SYS_XPVTAP_H */