root/usr/src/uts/common/xen/sys/xendev.h
/*
 * 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 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef _SYS_XENDEV_H
#define _SYS_XENDEV_H


#include <sys/hypervisor.h>
#include <sys/taskq.h>
#ifndef __xpv
#include <public/io/ring.h>
#include <public/event_channel.h>
#include <public/grant_table.h>
#endif
#include <xen/sys/xenbus_impl.h>

#ifdef  __cplusplus
extern "C" {
#endif

/*
 * Xenbus property interfaces, initialized by framework
 */
#define XBP_HP_STATUS           "hotplug-status"        /* backend prop: str */
#define XBV_HP_STATUS_CONN      "connected"             /* backend prop val */
#define XBP_DEV_TYPE            "device-type"           /* backend prop: str */
#define XBV_DEV_TYPE_CD         "cdrom"                 /* backend prop val */

/*
 * Xenbus property interfaces, initialized by backend disk driver
 */
#define XBP_SECTOR_SIZE "sector-size"           /* backend prop: uint */
#define XBP_SECTORS     "sectors"               /* backend prop: uint64 */
#define XBP_INFO        "info"                  /* backend prop: uint */
#define XBP_FB          "feature-barrier"       /* backend prop: boolean int */

/*
 * Xenbus property interfaces, initialized by frontend disk driver
 */
#define XBP_RING_REF    "ring-ref"              /* frontend prop: long */
#define XBP_EVENT_CHAN  "event-channel"         /* frontend prop: long */
#define XBP_PROTOCOL    "protocol"              /* frontend prop: string */

/*
 * Xenbus CDROM property interfaces, used by backend and frontend
 *
 * XBP_MEDIA_REQ_SUP
 *      - Backend xenbus property located at:
 *              backend/vbd/<domU_id>/<domU_dev>/media-req-sup
 *      - Set by the backend, consumed by the frontend.
 *      - Cosumed by the frontend.
 *      - A boolean integer property indicating backend support
 *        for the XBP_MEDIA_REQ property.
 *
 * XBP_MEDIA_REQ
 *      - Frontend xenbus property located at:
 *              /local/domain/<domU_id>/device/vbd/<domU_dev>/media-req
 *      - Set and consumed by both the frontend and backend.
 *      - Possible values:
 *              XBV_MEDIA_REQ_NONE, XBV_MEDIA_REQ_LOCK, and XBV_MEDIA_REQ_EJECT
 *      - Only applies to CDROM devices.
 *
 * XBV_MEDIA_REQ_NONE
 *      - XBP_MEDIA_REQ property valud
 *      - Set and consumed by both the frontend and backend.
 *      - Indicates that there are no currently outstanding media requet
 *        operations.
 *
 * XBV_MEDIA_REQ_LOCK
 *      - XBP_MEDIA_REQ property valud
 *      - Set by the frontend, consumed by the backend.
 *      - Indicates to the backend that the currenct media is locked
 *        and changes to the media (via xm block-configure for example)
 *        should not be allowed.
 *
 * XBV_MEDIA_REQ_EJECT
 *      - XBP_MEDIA_REQ property valud
 *      - Set by the frontend, consumed by the backend.
 *      - Indicates to the backend that the currenct media should be ejected.
 *        This means that the backend should close it's connection to
 *        the frontend device, close it's current backing store device/file,
 *        and then set the media-req property to XBV_MEDIA_REQ_NONE.  (to
 *        indicate that the eject operation is complete.)
 */
#define XBP_MEDIA_REQ_SUP       "media-req-sup" /* backend prop: boolean int */
#define XBP_MEDIA_REQ           "media-req"     /* frontend prop: str */
#define XBV_MEDIA_REQ_NONE      "none"          /* frontend prop val */
#define XBV_MEDIA_REQ_LOCK      "lock"          /* frontend prop val */
#define XBV_MEDIA_REQ_EJECT     "eject"         /* frontend prop val */

/*
 * Xen device class codes
 */
typedef enum {
        XEN_INVAL = -1,
        XEN_CONSOLE = 0,
        XEN_VNET,
        XEN_VBLK,
        XEN_XENBUS,
        XEN_DOMCAPS,
        XEN_BALLOON,
        XEN_EVTCHN,
        XEN_PRIVCMD,
        XEN_BLKTAP,
        XEN_LASTCLASS
} xendev_devclass_t;

/*
 * Hotplug request sent to userland event handler.
 */
typedef enum {
        XEN_HP_ADD,
        XEN_HP_REMOVE
} xendev_hotplug_cmd_t;

/*
 * Hotplug status.
 *
 * In fact, the Xen tools can write any arbitrary string into the
 * hotplug-status node. We represent the known values here - anything
 * else will be 'Unrecognized'.
 */
typedef enum {
        Unrecognized,
        Connected
} xendev_hotplug_state_t;

struct xendev_ppd {
        kmutex_t                xd_evt_lk;
        int                     xd_evtchn;
        struct intrspec         xd_ispec;

        xendev_devclass_t       xd_devclass;
        domid_t                 xd_domain;
        int                     xd_vdevnum;

        kmutex_t                xd_ndi_lk;
        struct xenbus_device    xd_xsdev;
        struct xenbus_watch     xd_hp_watch;
        struct xenbus_watch     xd_bepath_watch;
        ddi_callback_id_t       xd_oe_ehid;
        ddi_callback_id_t       xd_hp_ehid;
        ddi_taskq_t             *xd_oe_taskq;
        ddi_taskq_t             *xd_hp_taskq;
        ddi_taskq_t             *xd_xb_watch_taskq;
        list_t                  xd_xb_watches;
};

#define XS_OE_STATE     "SUNW,xendev:otherend_state"
#define XS_HP_STATE     "SUNW,xendev:hotplug_state"

/*
 * A device with xd_vdevnum == VDEV_NOXS does not participate in
 * xenstore.
 */
#define VDEV_NOXS       (-1)

void    xendev_enum_class(dev_info_t *, xendev_devclass_t);
void    xendev_enum_all(dev_info_t *, boolean_t);
xendev_devclass_t       xendev_nodename_to_devclass(char *);
int     xendev_devclass_ipl(xendev_devclass_t);
struct intrspec *xendev_get_ispec(dev_info_t *, uint_t);
void    xvdi_suspend(dev_info_t *);
int     xvdi_resume(dev_info_t *);
int     xvdi_alloc_evtchn(dev_info_t *);
int     xvdi_bind_evtchn(dev_info_t *, evtchn_port_t);
void    xvdi_free_evtchn(dev_info_t *);
int     xvdi_add_event_handler(dev_info_t *, char *,
        void (*)(dev_info_t *, ddi_eventcookie_t, void *, void *),
        void *arg);
void    xvdi_remove_event_handler(dev_info_t *, char *);
int     xvdi_get_evtchn(dev_info_t *);
int     xvdi_get_vdevnum(dev_info_t *);
char    *xvdi_get_xsname(dev_info_t *);
char    *xvdi_get_oename(dev_info_t *);
domid_t xvdi_get_oeid(dev_info_t *);
void    xvdi_dev_error(dev_info_t *, int, char *);
void    xvdi_fatal_error(dev_info_t *, int, char *);
void    xvdi_notify_oe(dev_info_t *);
int     xvdi_post_event(dev_info_t *, xendev_hotplug_cmd_t);
struct  xenbus_device *xvdi_get_xsd(dev_info_t *);
int     xvdi_switch_state(dev_info_t *, xenbus_transaction_t, XenbusState);
dev_info_t      *xvdi_create_dev(dev_info_t *, xendev_devclass_t,
    domid_t, int);
int     xvdi_init_dev(dev_info_t *);
void    xvdi_uninit_dev(dev_info_t *);
dev_info_t      *xvdi_find_dev(dev_info_t *, xendev_devclass_t, domid_t, int);

extern int xvdi_add_xb_watch_handler(dev_info_t *, const char *,
    const char *, xvdi_xb_watch_cb_t cb, void *);
extern void xvdi_remove_xb_watch_handlers(dev_info_t *);

/*
 * common ring interfaces
 */

/*
 * we need the pad between ring index
 * and the real ring containing requests/responses,
 * so that we can map comif_sring_t structure to
 * any xxxif_sring_t structure defined via macros in ring.h
 */
#define SRINGPAD                48

typedef struct comif_sring {
        RING_IDX req_prod, req_event;
        RING_IDX rsp_prod, rsp_event;
        uint8_t  pad[SRINGPAD];
        /*
         * variable length
         * stores real request/response entries
         * entry size is fixed per ring
         */
        char ring[1];
} comif_sring_t;

typedef struct comif_ring_fe {
        /*
         * keep the member names as defined in ring.h
         * in order to make use of the pre-defined macros
         */
        RING_IDX req_prod_pvt;
        RING_IDX rsp_cons;
        unsigned int nr_ents;
        comif_sring_t *sring;
} comif_ring_fe_t;

typedef struct comif_ring_be {
        /*
         * keep the member names as defined in ring.h
         * in order to make use of the pre-defined macros
         */
        RING_IDX rsp_prod_pvt;
        RING_IDX req_cons;
        unsigned int nr_ents;
        comif_sring_t  *sring;
} comif_ring_be_t;

typedef union comif_ring {
        comif_ring_fe_t fr;
        comif_ring_be_t br;
} comif_ring_t;

typedef struct xendev_req {
        unsigned long next;
        void *req;
} xendev_req_t;

typedef struct xendev_ring {
        ddi_dma_handle_t xr_dma_hdl;
        ddi_acc_handle_t xr_acc_hdl;
        grant_handle_t xr_grant_hdl;
        caddr_t xr_vaddr;
        paddr_t xr_paddr;
        grant_ref_t xr_gref;
        int xr_entry_size;
        int xr_frontend;
        comif_ring_t xr_sring;
} xendev_ring_t;

int     xvdi_alloc_ring(dev_info_t *, size_t, size_t, grant_ref_t *,
        xendev_ring_t **);
void    xvdi_free_ring(xendev_ring_t *);
int     xvdi_map_ring(dev_info_t *, size_t, size_t, grant_ref_t,
        xendev_ring_t **);
void    xvdi_unmap_ring(xendev_ring_t *);
uint_t  xvdi_ring_avail_slots(xendev_ring_t *);
int     xvdi_ring_has_unconsumed_requests(xendev_ring_t *);
int     xvdi_ring_has_incomp_request(xendev_ring_t *);
int     xvdi_ring_has_unconsumed_responses(xendev_ring_t *);
void*   xvdi_ring_get_request(xendev_ring_t *);
int     xvdi_ring_push_request(xendev_ring_t *);
void*   xvdi_ring_get_response(xendev_ring_t *);
int     xvdi_ring_push_response(xendev_ring_t *);

#ifdef  __cplusplus
}
#endif

#endif  /* _SYS_XENDEV_H */