843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * CDDL HEADER START
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * The contents of this file are subject to the terms of the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Common Development and Distribution License (the "License").
843e19887f64dde75055cf8842fc4db2171eff45johnlev * You may not use this file except in compliance with the License.
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
843e19887f64dde75055cf8842fc4db2171eff45johnlev * or http://www.opensolaris.org/os/licensing.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * See the License for the specific language governing permissions
843e19887f64dde75055cf8842fc4db2171eff45johnlev * and limitations under the License.
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * When distributing Covered Code, include this CDDL HEADER in each
843e19887f64dde75055cf8842fc4db2171eff45johnlev * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * If applicable, add the following below this CDDL HEADER, with the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * fields enclosed by brackets "[]" replaced with your own identifying
843e19887f64dde75055cf8842fc4db2171eff45johnlev * information: Portions Copyright [yyyy] [name of copyright owner]
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * CDDL HEADER END
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Use is subject to license terms.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * xenbus_dev.c
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Driver giving user-space access to the kernel's xenbus connection
843e19887f64dde75055cf8842fc4db2171eff45johnlev * to xenstore.
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Copyright (c) 2005, Christian Limpach
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Copyright (c) 2005, Rusty Russell, IBM Corporation
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * This file may be distributed separately from the Linux kernel, or
843e19887f64dde75055cf8842fc4db2171eff45johnlev * incorporated into other software packages, subject to the following license:
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Permission is hereby granted, free of charge, to any person obtaining a copy
843e19887f64dde75055cf8842fc4db2171eff45johnlev * of this source file (the "Software"), to deal in the Software without
843e19887f64dde75055cf8842fc4db2171eff45johnlev * restriction, including without limitation the rights to use, copy, modify,
843e19887f64dde75055cf8842fc4db2171eff45johnlev * merge, publish, distribute, sublicense, and/or sell copies of the Software,
843e19887f64dde75055cf8842fc4db2171eff45johnlev * and to permit persons to whom the Software is furnished to do so, subject to
843e19887f64dde75055cf8842fc4db2171eff45johnlev * the following conditions:
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * The above copyright notice and this permission notice shall be included in
843e19887f64dde75055cf8842fc4db2171eff45johnlev * all copies or substantial portions of the Software.
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
843e19887f64dde75055cf8842fc4db2171eff45johnlev * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
843e19887f64dde75055cf8842fc4db2171eff45johnlev * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
843e19887f64dde75055cf8842fc4db2171eff45johnlev * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
843e19887f64dde75055cf8842fc4db2171eff45johnlev * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
843e19887f64dde75055cf8842fc4db2171eff45johnlev * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
843e19887f64dde75055cf8842fc4db2171eff45johnlev * IN THE SOFTWARE.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/types.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/sysmacros.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/conf.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/stat.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/modctl.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/uio.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/list.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/file.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/errno.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/open.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/cred.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/condvar.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/ddi.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/sunddi.h>
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev#include <sys/policy.h>
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#ifdef XPV_HVM_DRIVER
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <public/io/xenbus.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <public/io/xs_wire.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <sys/xpv_support.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#endif
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/hypervisor.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <xen/sys/xenbus.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <xen/sys/xenbus_comms.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <xen/sys/xenbus_impl.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <xen/public/io/xs_wire.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#ifdef DEBUG
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define XENBUSDRV_DBPRINT(fmt) { if (xenbusdrv_debug) cmn_err fmt; }
843e19887f64dde75055cf8842fc4db2171eff45johnlev#else
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define XENBUSDRV_DBPRINT(fmt)
843e19887f64dde75055cf8842fc4db2171eff45johnlev#endif /* ifdef DEBUG */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/* Some handy macros */
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define XENBUSDRV_MASK_READ_IDX(idx) ((idx) & (PAGESIZE - 1))
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define XENBUSDRV_MINOR2INST(minor) ((int)(minor))
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define XENBUSDRV_NCLONES 256
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define XENBUSDRV_INST2SOFTS(instance) \
843e19887f64dde75055cf8842fc4db2171eff45johnlev ((xenbus_dev_t *)ddi_get_soft_state(xenbusdrv_statep, (instance)))
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xenbusdrv_debug = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xenbusdrv_clone_tab[XENBUSDRV_NCLONES];
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic dev_info_t *xenbusdrv_dip;
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic kmutex_t xenbusdrv_clone_tab_mutex;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstruct xenbus_dev_transaction {
843e19887f64dde75055cf8842fc4db2171eff45johnlev list_t list;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbus_transaction_t handle;
843e19887f64dde75055cf8842fc4db2171eff45johnlev};
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/* Soft state data structure for xenbus driver */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstruct xenbus_dev_data {
843e19887f64dde75055cf8842fc4db2171eff45johnlev dev_info_t *dip;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* In-progress transaction. */
843e19887f64dde75055cf8842fc4db2171eff45johnlev list_t transactions;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* Partial request. */
843e19887f64dde75055cf8842fc4db2171eff45johnlev unsigned int len;
843e19887f64dde75055cf8842fc4db2171eff45johnlev union {
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct xsd_sockmsg msg;
843e19887f64dde75055cf8842fc4db2171eff45johnlev char buffer[MMU_PAGESIZE];
843e19887f64dde75055cf8842fc4db2171eff45johnlev } u;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* Response queue. */
843e19887f64dde75055cf8842fc4db2171eff45johnlev char read_buffer[MMU_PAGESIZE];
843e19887f64dde75055cf8842fc4db2171eff45johnlev unsigned int read_cons, read_prod;
843e19887f64dde75055cf8842fc4db2171eff45johnlev kcondvar_t read_cv;
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmutex_t read_mutex;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int xenstore_inst;
843e19887f64dde75055cf8842fc4db2171eff45johnlev};
843e19887f64dde75055cf8842fc4db2171eff45johnlevtypedef struct xenbus_dev_data xenbus_dev_t;
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void *xenbusdrv_statep;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xenbusdrv_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xenbusdrv_attach(dev_info_t *, ddi_attach_cmd_t);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xenbusdrv_detach(dev_info_t *, ddi_detach_cmd_t);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xenbusdrv_open(dev_t *, int, int, cred_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xenbusdrv_close(dev_t, int, int, cred_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xenbusdrv_read(dev_t, struct uio *, cred_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xenbusdrv_write(dev_t, struct uio *, cred_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xenbusdrv_devmap(dev_t, devmap_cookie_t, offset_t, size_t, size_t *,
843e19887f64dde75055cf8842fc4db2171eff45johnlev uint_t);
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlevstatic int xenbusdrv_segmap(dev_t, off_t, ddi_as_handle_t, caddr_t *, off_t,
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev uint_t, uint_t, uint_t, cred_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xenbusdrv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xenbusdrv_queue_reply(xenbus_dev_t *, const struct xsd_sockmsg *,
843e19887f64dde75055cf8842fc4db2171eff45johnlev const char *);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/* Solaris driver framework */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic struct cb_ops xenbusdrv_cb_ops = {
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbusdrv_open, /* cb_open */
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbusdrv_close, /* cb_close */
843e19887f64dde75055cf8842fc4db2171eff45johnlev nodev, /* cb_strategy */
843e19887f64dde75055cf8842fc4db2171eff45johnlev nodev, /* cb_print */
843e19887f64dde75055cf8842fc4db2171eff45johnlev nodev, /* cb_dump */
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbusdrv_read, /* cb_read */
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbusdrv_write, /* cb_write */
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbusdrv_ioctl, /* cb_ioctl */
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbusdrv_devmap, /* cb_devmap */
843e19887f64dde75055cf8842fc4db2171eff45johnlev NULL, /* cb_mmap */
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev xenbusdrv_segmap, /* cb_segmap */
843e19887f64dde75055cf8842fc4db2171eff45johnlev nochpoll, /* cb_chpoll */
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_prop_op, /* cb_prop_op */
843e19887f64dde75055cf8842fc4db2171eff45johnlev 0, /* cb_stream */
843e19887f64dde75055cf8842fc4db2171eff45johnlev D_DEVMAP | D_NEW | D_MP, /* cb_flag */
843e19887f64dde75055cf8842fc4db2171eff45johnlev CB_REV
843e19887f64dde75055cf8842fc4db2171eff45johnlev};
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic struct dev_ops xenbusdrv_dev_ops = {
843e19887f64dde75055cf8842fc4db2171eff45johnlev DEVO_REV, /* devo_rev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev 0, /* devo_refcnt */
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbusdrv_info, /* devo_getinfo */
843e19887f64dde75055cf8842fc4db2171eff45johnlev nulldev, /* devo_identify */
843e19887f64dde75055cf8842fc4db2171eff45johnlev nulldev, /* devo_probe */
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbusdrv_attach, /* devo_attach */
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbusdrv_detach, /* devo_detach */
843e19887f64dde75055cf8842fc4db2171eff45johnlev nodev, /* devo_reset */
843e19887f64dde75055cf8842fc4db2171eff45johnlev &xenbusdrv_cb_ops, /* devo_cb_ops */
843e19887f64dde75055cf8842fc4db2171eff45johnlev NULL, /* devo_bus_ops */
193974072f41a843678abf5f61979c748687e66bSherry Moore NULL, /* devo_power */
193974072f41a843678abf5f61979c748687e66bSherry Moore ddi_quiesce_not_needed, /* devo_quiesce */
843e19887f64dde75055cf8842fc4db2171eff45johnlev};
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic struct modldrv modldrv = {
843e19887f64dde75055cf8842fc4db2171eff45johnlev &mod_driverops, /* Type of module. This one is a driver */
193974072f41a843678abf5f61979c748687e66bSherry Moore "virtual bus driver", /* Name of the module. */
843e19887f64dde75055cf8842fc4db2171eff45johnlev &xenbusdrv_dev_ops /* driver ops */
843e19887f64dde75055cf8842fc4db2171eff45johnlev};
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic struct modlinkage modlinkage = {
843e19887f64dde75055cf8842fc4db2171eff45johnlev MODREV_1,
843e19887f64dde75055cf8842fc4db2171eff45johnlev &modldrv,
843e19887f64dde75055cf8842fc4db2171eff45johnlev NULL
843e19887f64dde75055cf8842fc4db2171eff45johnlev};
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevint
843e19887f64dde75055cf8842fc4db2171eff45johnlev_init(void)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev int e;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev e = ddi_soft_state_init(&xenbusdrv_statep, sizeof (xenbus_dev_t), 1);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (e)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (e);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev e = mod_install(&modlinkage);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (e)
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_soft_state_fini(&xenbusdrv_statep);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (e);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevint
843e19887f64dde75055cf8842fc4db2171eff45johnlev_fini(void)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev int e;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev e = mod_remove(&modlinkage);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (e)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (e);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_soft_state_fini(&xenbusdrv_statep);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevint
843e19887f64dde75055cf8842fc4db2171eff45johnlev_info(struct modinfo *modinfop)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (mod_info(&modlinkage, modinfop));
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/* ARGSUSED */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxenbusdrv_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev dev_t dev = (dev_t)arg;
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor_t minor = getminor(dev);
843e19887f64dde75055cf8842fc4db2171eff45johnlev int retval;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev switch (cmd) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DDI_INFO_DEVT2DEVINFO:
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (minor != 0 || xenbusdrv_dip == NULL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev *result = (void *)NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev retval = DDI_FAILURE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev *result = (void *)xenbusdrv_dip;
843e19887f64dde75055cf8842fc4db2171eff45johnlev retval = DDI_SUCCESS;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DDI_INFO_DEVT2INSTANCE:
843e19887f64dde75055cf8842fc4db2171eff45johnlev *result = (void *)0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev retval = DDI_SUCCESS;
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev default:
843e19887f64dde75055cf8842fc4db2171eff45johnlev retval = DDI_FAILURE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (retval);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxenbusdrv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev int error;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int unit = ddi_get_instance(dip);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev switch (cmd) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DDI_ATTACH:
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DDI_RESUME:
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_SUCCESS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev default:
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xenbus_attach: unknown cmd 0x%x\n", cmd);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* DDI_ATTACH */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * only one instance - but we clone using the open routine
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ddi_get_instance(dip) > 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_init(&xenbusdrv_clone_tab_mutex, NULL, MUTEX_DRIVER,
843e19887f64dde75055cf8842fc4db2171eff45johnlev NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = ddi_create_minor_node(dip, "xenbus", S_IFCHR, unit,
843e19887f64dde75055cf8842fc4db2171eff45johnlev DDI_PSEUDO, NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (error != DDI_SUCCESS)
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto fail;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * save dip for getinfo
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbusdrv_dip = dip;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_report_dev(dip);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#ifndef XPV_HVM_DRIVER
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (DOMAIN_IS_INITDOMAIN(xen_info))
843e19887f64dde75055cf8842fc4db2171eff45johnlev xs_dom0_init();
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#endif
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_SUCCESS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevfail:
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) xenbusdrv_detach(dip, DDI_DETACH);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (error);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxenbusdrv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * again, only one instance
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ddi_get_instance(dip) > 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev switch (cmd) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DDI_DETACH:
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_remove_minor_node(dip, NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_destroy(&xenbusdrv_clone_tab_mutex);
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbusdrv_dip = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_SUCCESS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DDI_SUSPEND:
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_SUCCESS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev default:
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xenbus_detach: unknown cmd 0x%x\n", cmd);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/* ARGSUSED */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlevxenbusdrv_open(dev_t *devp, int flag, int otyp, cred_t *cr)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbus_dev_t *xbs;
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor_t minor = getminor(*devp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (otyp == OTYP_BLK)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * only allow open on minor = 0 - the clone device
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (minor != 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * find a free slot and grab it
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&xenbusdrv_clone_tab_mutex);
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (minor = 1; minor < XENBUSDRV_NCLONES; minor++) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xenbusdrv_clone_tab[minor] == 0) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbusdrv_clone_tab[minor] = 1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&xenbusdrv_clone_tab_mutex);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (minor == XENBUSDRV_NCLONES)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EAGAIN);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* Allocate softstate structure */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ddi_soft_state_zalloc(xenbusdrv_statep,
843e19887f64dde75055cf8842fc4db2171eff45johnlev XENBUSDRV_MINOR2INST(minor)) != DDI_SUCCESS) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&xenbusdrv_clone_tab_mutex);
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbusdrv_clone_tab[minor] = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&xenbusdrv_clone_tab_mutex);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EAGAIN);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(minor));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* ... and init it */
843e19887f64dde75055cf8842fc4db2171eff45johnlev xbs->dip = xenbusdrv_dip;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_init(&xbs->read_mutex, NULL, MUTEX_DRIVER, NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev cv_init(&xbs->read_cv, NULL, CV_DEFAULT, NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev list_create(&xbs->transactions, sizeof (struct xenbus_dev_transaction),
843e19887f64dde75055cf8842fc4db2171eff45johnlev offsetof(struct xenbus_dev_transaction, list));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* clone driver */
843e19887f64dde75055cf8842fc4db2171eff45johnlev *devp = makedevice(getmajor(*devp), minor);
843e19887f64dde75055cf8842fc4db2171eff45johnlev XENBUSDRV_DBPRINT((CE_NOTE, "Xenbus drv open succeeded, minor=%d",
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/* ARGSUSED */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlevxenbusdrv_close(dev_t dev, int flag, int otyp, struct cred *cr)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbus_dev_t *xbs;
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor_t minor = getminor(dev);
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct xenbus_dev_transaction *trans;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(minor));
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xbs == NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#ifdef notyet
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * XXPV - would like to be able to notify xenstore down here, but
843e19887f64dde75055cf8842fc4db2171eff45johnlev * as the daemon is currently written, it doesn't leave the device
843e19887f64dde75055cf8842fc4db2171eff45johnlev * open after initial setup, so we have no way of knowing if it has
843e19887f64dde75055cf8842fc4db2171eff45johnlev * gone away.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xbs->xenstore_inst)
843e19887f64dde75055cf8842fc4db2171eff45johnlev xs_notify_xenstore_down();
843e19887f64dde75055cf8842fc4db2171eff45johnlev#endif
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* free pending transaction */
843e19887f64dde75055cf8842fc4db2171eff45johnlev while (trans = (struct xenbus_dev_transaction *)
843e19887f64dde75055cf8842fc4db2171eff45johnlev list_head(&xbs->transactions)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) xenbus_transaction_end(trans->handle, 1);
843e19887f64dde75055cf8842fc4db2171eff45johnlev list_remove(&xbs->transactions, (void *)trans);
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_free(trans, sizeof (*trans));
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_destroy(&xbs->read_mutex);
843e19887f64dde75055cf8842fc4db2171eff45johnlev cv_destroy(&xbs->read_cv);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_soft_state_free(xenbusdrv_statep, XENBUSDRV_MINOR2INST(minor));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * free clone tab slot
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&xenbusdrv_clone_tab_mutex);
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbusdrv_clone_tab[minor] = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&xenbusdrv_clone_tab_mutex);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev XENBUSDRV_DBPRINT((CE_NOTE, "Xenbus drv close succeeded, minor=%d",
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/* ARGSUSED */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlevxenbusdrv_read(dev_t dev, struct uio *uiop, cred_t *cr)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbus_dev_t *xbs;
843e19887f64dde75055cf8842fc4db2171eff45johnlev size_t len;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int res, ret;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int idx;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev XENBUSDRV_DBPRINT((CE_NOTE, "xenbusdrv_read called"));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev if (secpolicy_xvm_control(cr))
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev return (EPERM);
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(getminor(dev)));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&xbs->read_mutex);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* check if we have something to read */
843e19887f64dde75055cf8842fc4db2171eff45johnlev while (xbs->read_prod == xbs->read_cons) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (cv_wait_sig(&xbs->read_cv, &xbs->read_mutex) == 0) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&xbs->read_mutex);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EINTR);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev idx = XENBUSDRV_MASK_READ_IDX(xbs->read_cons);
843e19887f64dde75055cf8842fc4db2171eff45johnlev res = uiop->uio_resid;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev len = xbs->read_prod - xbs->read_cons;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (len > (sizeof (xbs->read_buffer) - idx))
843e19887f64dde75055cf8842fc4db2171eff45johnlev len = sizeof (xbs->read_buffer) - idx;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (len > res)
843e19887f64dde75055cf8842fc4db2171eff45johnlev len = res;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev ret = uiomove(xbs->read_buffer + idx, len, UIO_READ, uiop);
843e19887f64dde75055cf8842fc4db2171eff45johnlev xbs->read_cons += res - uiop->uio_resid;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&xbs->read_mutex);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ret);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * prepare data for xenbusdrv_read()
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxenbusdrv_queue_reply(xenbus_dev_t *xbs, const struct xsd_sockmsg *msg,
843e19887f64dde75055cf8842fc4db2171eff45johnlev const char *reply)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev int i;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int remaining;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev XENBUSDRV_DBPRINT((CE_NOTE, "xenbusdrv_queue_reply called"));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&xbs->read_mutex);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev remaining = sizeof (xbs->read_buffer) -
843e19887f64dde75055cf8842fc4db2171eff45johnlev (xbs->read_prod - xbs->read_cons);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (sizeof (*msg) + msg->len > remaining) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&xbs->read_mutex);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EOVERFLOW);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (i = 0; i < sizeof (*msg); i++, xbs->read_prod++) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev xbs->read_buffer[XENBUSDRV_MASK_READ_IDX(xbs->read_prod)] =
843e19887f64dde75055cf8842fc4db2171eff45johnlev ((char *)msg)[i];
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (i = 0; i < msg->len; i++, xbs->read_prod++) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev xbs->read_buffer[XENBUSDRV_MASK_READ_IDX(xbs->read_prod)] =
843e19887f64dde75055cf8842fc4db2171eff45johnlev reply[i];
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev cv_broadcast(&xbs->read_cv);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&xbs->read_mutex);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev XENBUSDRV_DBPRINT((CE_NOTE, "xenbusdrv_queue_reply exited"));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/* ARGSUSED */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlevxenbusdrv_write(dev_t dev, struct uio *uiop, cred_t *cr)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbus_dev_t *xbs;
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct xenbus_dev_transaction *trans;
843e19887f64dde75055cf8842fc4db2171eff45johnlev void *reply;
843e19887f64dde75055cf8842fc4db2171eff45johnlev size_t len;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int rc = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev XENBUSDRV_DBPRINT((CE_NOTE, "xenbusdrv_write called"));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev if (secpolicy_xvm_control(cr))
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev return (EPERM);
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(getminor(dev)));
843e19887f64dde75055cf8842fc4db2171eff45johnlev len = uiop->uio_resid;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((len + xbs->len) > sizeof (xbs->u.buffer)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev XENBUSDRV_DBPRINT((CE_WARN, "Request is too big"));
843e19887f64dde75055cf8842fc4db2171eff45johnlev rc = EINVAL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto out;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (uiomove(xbs->u.buffer + xbs->len, len, UIO_WRITE, uiop) != 0) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev XENBUSDRV_DBPRINT((CE_WARN, "Uiomove failed"));
843e19887f64dde75055cf8842fc4db2171eff45johnlev rc = EFAULT;
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto out;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xbs->len += len;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xbs->len < (sizeof (xbs->u.msg)) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev xbs->len < (sizeof (xbs->u.msg) + xbs->u.msg.len)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev XENBUSDRV_DBPRINT((CE_NOTE, "Partial request"));
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev switch (xbs->u.msg.type) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XS_TRANSACTION_START:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XS_TRANSACTION_END:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XS_DIRECTORY:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XS_READ:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XS_GET_PERMS:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XS_RELEASE:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XS_GET_DOMAIN_PATH:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XS_WRITE:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XS_MKDIR:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XS_RM:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XS_SET_PERMS:
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* send the request to xenstore and get feedback */
843e19887f64dde75055cf8842fc4db2171eff45johnlev rc = xenbus_dev_request_and_reply(&xbs->u.msg, &reply);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (rc) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev XENBUSDRV_DBPRINT((CE_WARN,
843e19887f64dde75055cf8842fc4db2171eff45johnlev "xenbus_dev_request_and_reply failed"));
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto out;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* handle transaction start/end */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xbs->u.msg.type == XS_TRANSACTION_START) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev trans = kmem_alloc(sizeof (*trans), KM_SLEEP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) ddi_strtoul((char *)reply, NULL, 0,
843e19887f64dde75055cf8842fc4db2171eff45johnlev (unsigned long *)&trans->handle);
843e19887f64dde75055cf8842fc4db2171eff45johnlev list_insert_tail(&xbs->transactions, (void *)trans);
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else if (xbs->u.msg.type == XS_TRANSACTION_END) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* try to find out the ending transaction */
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (trans = (struct xenbus_dev_transaction *)
843e19887f64dde75055cf8842fc4db2171eff45johnlev list_head(&xbs->transactions); trans;
843e19887f64dde75055cf8842fc4db2171eff45johnlev trans = (struct xenbus_dev_transaction *)
843e19887f64dde75055cf8842fc4db2171eff45johnlev list_next(&xbs->transactions, (void *)trans))
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (trans->handle ==
843e19887f64dde75055cf8842fc4db2171eff45johnlev (xenbus_transaction_t)
843e19887f64dde75055cf8842fc4db2171eff45johnlev xbs->u.msg.tx_id)
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(trans);
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* free it, if we find it */
843e19887f64dde75055cf8842fc4db2171eff45johnlev list_remove(&xbs->transactions, (void *)trans);
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_free(trans, sizeof (*trans));
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* prepare data for xenbusdrv_read() to get */
843e19887f64dde75055cf8842fc4db2171eff45johnlev rc = xenbusdrv_queue_reply(xbs, &xbs->u.msg, reply);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_free(reply, xbs->u.msg.len + 1);
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev default:
843e19887f64dde75055cf8842fc4db2171eff45johnlev rc = EINVAL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevout:
843e19887f64dde75055cf8842fc4db2171eff45johnlev xbs->len = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (rc);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxenbusdrv_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
843e19887f64dde75055cf8842fc4db2171eff45johnlev size_t *maplen, uint_t model)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbus_dev_t *xbs;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int err;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(getminor(dev)));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (off != 0 || len != PAGESIZE)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (-1);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!DOMAIN_IS_INITDOMAIN(xen_info))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (-1);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev err = devmap_umem_setup(dhp, xbs->dip, NULL, xb_xenstore_cookie(),
843e19887f64dde75055cf8842fc4db2171eff45johnlev 0, PAGESIZE, PROT_READ | PROT_WRITE | PROT_USER, 0, NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (err)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (err);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev *maplen = PAGESIZE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlevstatic int
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlevxenbusdrv_segmap(dev_t dev, off_t off, ddi_as_handle_t as, caddr_t *addrp,
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev off_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr)
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev{
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev if (secpolicy_xvm_control(cr))
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev return (EPERM);
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev return (ddi_devmap_segmap(dev, off, as, addrp, len, prot,
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev maxprot, flags, cr));
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev}
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlevxenbusdrv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr,
843e19887f64dde75055cf8842fc4db2171eff45johnlev int *rvalp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbus_dev_t *xbs;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev if (secpolicy_xvm_control(cr))
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev return (EPERM);
b26a64ae582e72d0b4c710cd8eba9c4afd4a9fddjohnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(getminor(dev)));
843e19887f64dde75055cf8842fc4db2171eff45johnlev switch (cmd) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev case IOCTL_XENBUS_XENSTORE_EVTCHN:
843e19887f64dde75055cf8842fc4db2171eff45johnlev *rvalp = xen_info->store_evtchn;
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev case IOCTL_XENBUS_NOTIFY_UP:
843e19887f64dde75055cf8842fc4db2171eff45johnlev xs_notify_xenstore_up();
843e19887f64dde75055cf8842fc4db2171eff45johnlev xbs->xenstore_inst = 1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev default:
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EINVAL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}