17756SMark.Johnson@Sun.COM /*
27756SMark.Johnson@Sun.COM * CDDL HEADER START
37756SMark.Johnson@Sun.COM *
47756SMark.Johnson@Sun.COM * The contents of this file are subject to the terms of the
57756SMark.Johnson@Sun.COM * Common Development and Distribution License (the "License").
67756SMark.Johnson@Sun.COM * You may not use this file except in compliance with the License.
77756SMark.Johnson@Sun.COM *
87756SMark.Johnson@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97756SMark.Johnson@Sun.COM * or http://www.opensolaris.org/os/licensing.
107756SMark.Johnson@Sun.COM * See the License for the specific language governing permissions
117756SMark.Johnson@Sun.COM * and limitations under the License.
127756SMark.Johnson@Sun.COM *
137756SMark.Johnson@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
147756SMark.Johnson@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157756SMark.Johnson@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
167756SMark.Johnson@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
177756SMark.Johnson@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
187756SMark.Johnson@Sun.COM *
197756SMark.Johnson@Sun.COM * CDDL HEADER END
207756SMark.Johnson@Sun.COM */
217756SMark.Johnson@Sun.COM
227756SMark.Johnson@Sun.COM /*
23*11066Srafael.vanoni@sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
247756SMark.Johnson@Sun.COM * Use is subject to license terms.
257756SMark.Johnson@Sun.COM */
267756SMark.Johnson@Sun.COM
277756SMark.Johnson@Sun.COM
287756SMark.Johnson@Sun.COM #include <sys/errno.h>
297756SMark.Johnson@Sun.COM #include <sys/types.h>
307756SMark.Johnson@Sun.COM #include <sys/conf.h>
317756SMark.Johnson@Sun.COM #include <sys/kmem.h>
327756SMark.Johnson@Sun.COM #include <sys/ddi.h>
337756SMark.Johnson@Sun.COM #include <sys/stat.h>
347756SMark.Johnson@Sun.COM #include <sys/sunddi.h>
357756SMark.Johnson@Sun.COM #include <sys/file.h>
367756SMark.Johnson@Sun.COM #include <sys/open.h>
377756SMark.Johnson@Sun.COM #include <sys/modctl.h>
387756SMark.Johnson@Sun.COM #include <sys/ddi_impldefs.h>
397756SMark.Johnson@Sun.COM #include <sys/sysmacros.h>
407756SMark.Johnson@Sun.COM #include <sys/ddidevmap.h>
417756SMark.Johnson@Sun.COM #include <sys/policy.h>
427756SMark.Johnson@Sun.COM
437756SMark.Johnson@Sun.COM #include <sys/vmsystm.h>
447756SMark.Johnson@Sun.COM #include <vm/hat_i86.h>
457756SMark.Johnson@Sun.COM #include <vm/hat_pte.h>
467756SMark.Johnson@Sun.COM #include <vm/seg_kmem.h>
477756SMark.Johnson@Sun.COM #include <vm/seg_mf.h>
487756SMark.Johnson@Sun.COM
497756SMark.Johnson@Sun.COM #include <xen/io/blkif_impl.h>
507756SMark.Johnson@Sun.COM #include <xen/io/blk_common.h>
517756SMark.Johnson@Sun.COM #include <xen/io/xpvtap.h>
527756SMark.Johnson@Sun.COM
537756SMark.Johnson@Sun.COM
547756SMark.Johnson@Sun.COM static int xpvtap_open(dev_t *devp, int flag, int otyp, cred_t *cred);
557756SMark.Johnson@Sun.COM static int xpvtap_close(dev_t devp, int flag, int otyp, cred_t *cred);
567756SMark.Johnson@Sun.COM static int xpvtap_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
577756SMark.Johnson@Sun.COM cred_t *cred, int *rval);
587756SMark.Johnson@Sun.COM static int xpvtap_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off,
597756SMark.Johnson@Sun.COM size_t len, size_t *maplen, uint_t model);
607756SMark.Johnson@Sun.COM static int xpvtap_segmap(dev_t dev, off_t off, struct as *asp, caddr_t *addrp,
617756SMark.Johnson@Sun.COM off_t len, unsigned int prot, unsigned int maxprot, unsigned int flags,
627756SMark.Johnson@Sun.COM cred_t *cred_p);
637756SMark.Johnson@Sun.COM static int xpvtap_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
647756SMark.Johnson@Sun.COM struct pollhead **phpp);
657756SMark.Johnson@Sun.COM
667756SMark.Johnson@Sun.COM static struct cb_ops xpvtap_cb_ops = {
677756SMark.Johnson@Sun.COM xpvtap_open, /* cb_open */
687756SMark.Johnson@Sun.COM xpvtap_close, /* cb_close */
697756SMark.Johnson@Sun.COM nodev, /* cb_strategy */
707756SMark.Johnson@Sun.COM nodev, /* cb_print */
717756SMark.Johnson@Sun.COM nodev, /* cb_dump */
727756SMark.Johnson@Sun.COM nodev, /* cb_read */
737756SMark.Johnson@Sun.COM nodev, /* cb_write */
747756SMark.Johnson@Sun.COM xpvtap_ioctl, /* cb_ioctl */
757756SMark.Johnson@Sun.COM xpvtap_devmap, /* cb_devmap */
767756SMark.Johnson@Sun.COM nodev, /* cb_mmap */
777756SMark.Johnson@Sun.COM xpvtap_segmap, /* cb_segmap */
787756SMark.Johnson@Sun.COM xpvtap_chpoll, /* cb_chpoll */
797756SMark.Johnson@Sun.COM ddi_prop_op, /* cb_prop_op */
807756SMark.Johnson@Sun.COM NULL, /* cb_stream */
817756SMark.Johnson@Sun.COM D_NEW | D_MP | D_64BIT | D_DEVMAP, /* cb_flag */
827756SMark.Johnson@Sun.COM CB_REV
837756SMark.Johnson@Sun.COM };
847756SMark.Johnson@Sun.COM
857756SMark.Johnson@Sun.COM static int xpvtap_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
867756SMark.Johnson@Sun.COM void **result);
877756SMark.Johnson@Sun.COM static int xpvtap_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
887756SMark.Johnson@Sun.COM static int xpvtap_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
897756SMark.Johnson@Sun.COM
907756SMark.Johnson@Sun.COM static struct dev_ops xpvtap_dev_ops = {
917756SMark.Johnson@Sun.COM DEVO_REV, /* devo_rev */
927756SMark.Johnson@Sun.COM 0, /* devo_refcnt */
937756SMark.Johnson@Sun.COM xpvtap_getinfo, /* devo_getinfo */
947756SMark.Johnson@Sun.COM nulldev, /* devo_identify */
957756SMark.Johnson@Sun.COM nulldev, /* devo_probe */
967756SMark.Johnson@Sun.COM xpvtap_attach, /* devo_attach */
977756SMark.Johnson@Sun.COM xpvtap_detach, /* devo_detach */
987756SMark.Johnson@Sun.COM nodev, /* devo_reset */
997756SMark.Johnson@Sun.COM &xpvtap_cb_ops, /* devo_cb_ops */
1007756SMark.Johnson@Sun.COM NULL, /* devo_bus_ops */
1017756SMark.Johnson@Sun.COM NULL /* power */
1027756SMark.Johnson@Sun.COM };
1037756SMark.Johnson@Sun.COM
1047756SMark.Johnson@Sun.COM
1057756SMark.Johnson@Sun.COM static struct modldrv xpvtap_modldrv = {
1067756SMark.Johnson@Sun.COM &mod_driverops, /* Type of module. This one is a driver */
1077756SMark.Johnson@Sun.COM "xpvtap driver", /* Name of the module. */
1087756SMark.Johnson@Sun.COM &xpvtap_dev_ops, /* driver ops */
1097756SMark.Johnson@Sun.COM };
1107756SMark.Johnson@Sun.COM
1117756SMark.Johnson@Sun.COM static struct modlinkage xpvtap_modlinkage = {
1127756SMark.Johnson@Sun.COM MODREV_1,
1137756SMark.Johnson@Sun.COM (void *) &xpvtap_modldrv,
1147756SMark.Johnson@Sun.COM NULL
1157756SMark.Johnson@Sun.COM };
1167756SMark.Johnson@Sun.COM
1177756SMark.Johnson@Sun.COM
1187756SMark.Johnson@Sun.COM void *xpvtap_statep;
1197756SMark.Johnson@Sun.COM
1207756SMark.Johnson@Sun.COM
1217756SMark.Johnson@Sun.COM static xpvtap_state_t *xpvtap_drv_init(int instance);
1227756SMark.Johnson@Sun.COM static void xpvtap_drv_fini(xpvtap_state_t *state);
1237756SMark.Johnson@Sun.COM static uint_t xpvtap_intr(caddr_t arg);
1247756SMark.Johnson@Sun.COM
1257756SMark.Johnson@Sun.COM typedef void (*xpvtap_rs_cleanup_t)(xpvtap_state_t *state, uint_t rs);
1267756SMark.Johnson@Sun.COM static void xpvtap_rs_init(uint_t min_val, uint_t max_val,
1277756SMark.Johnson@Sun.COM xpvtap_rs_hdl_t *handle);
1287756SMark.Johnson@Sun.COM static void xpvtap_rs_fini(xpvtap_rs_hdl_t *handle);
1297756SMark.Johnson@Sun.COM static int xpvtap_rs_alloc(xpvtap_rs_hdl_t handle, uint_t *rs);
1307756SMark.Johnson@Sun.COM static void xpvtap_rs_free(xpvtap_rs_hdl_t handle, uint_t rs);
1317756SMark.Johnson@Sun.COM static void xpvtap_rs_flush(xpvtap_rs_hdl_t handle,
1327756SMark.Johnson@Sun.COM xpvtap_rs_cleanup_t callback, void *arg);
1337756SMark.Johnson@Sun.COM
1347756SMark.Johnson@Sun.COM static int xpvtap_segmf_register(xpvtap_state_t *state);
1357756SMark.Johnson@Sun.COM static void xpvtap_segmf_unregister(struct as *as, void *arg, uint_t event);
1367756SMark.Johnson@Sun.COM
1377756SMark.Johnson@Sun.COM static int xpvtap_user_init(xpvtap_state_t *state);
1387756SMark.Johnson@Sun.COM static void xpvtap_user_fini(xpvtap_state_t *state);
1397756SMark.Johnson@Sun.COM static int xpvtap_user_ring_init(xpvtap_state_t *state);
1407756SMark.Johnson@Sun.COM static void xpvtap_user_ring_fini(xpvtap_state_t *state);
1417756SMark.Johnson@Sun.COM static int xpvtap_user_thread_init(xpvtap_state_t *state);
1427756SMark.Johnson@Sun.COM static void xpvtap_user_thread_fini(xpvtap_state_t *state);
1437756SMark.Johnson@Sun.COM static void xpvtap_user_thread_start(caddr_t arg);
1447756SMark.Johnson@Sun.COM static void xpvtap_user_thread_stop(xpvtap_state_t *state);
1457756SMark.Johnson@Sun.COM static void xpvtap_user_thread(void *arg);
1467756SMark.Johnson@Sun.COM
1477756SMark.Johnson@Sun.COM static void xpvtap_user_app_stop(caddr_t arg);
1487756SMark.Johnson@Sun.COM
1497756SMark.Johnson@Sun.COM static int xpvtap_user_request_map(xpvtap_state_t *state, blkif_request_t *req,
1507756SMark.Johnson@Sun.COM uint_t *uid);
1517756SMark.Johnson@Sun.COM static int xpvtap_user_request_push(xpvtap_state_t *state,
1527756SMark.Johnson@Sun.COM blkif_request_t *req, uint_t uid);
1537756SMark.Johnson@Sun.COM static int xpvtap_user_response_get(xpvtap_state_t *state,
1547756SMark.Johnson@Sun.COM blkif_response_t *resp, uint_t *uid);
1557756SMark.Johnson@Sun.COM static void xpvtap_user_request_unmap(xpvtap_state_t *state, uint_t uid);
1567756SMark.Johnson@Sun.COM
1577756SMark.Johnson@Sun.COM
1587756SMark.Johnson@Sun.COM /*
1597756SMark.Johnson@Sun.COM * _init()
1607756SMark.Johnson@Sun.COM */
1617756SMark.Johnson@Sun.COM int
_init(void)1627756SMark.Johnson@Sun.COM _init(void)
1637756SMark.Johnson@Sun.COM {
1647756SMark.Johnson@Sun.COM int e;
1657756SMark.Johnson@Sun.COM
1667756SMark.Johnson@Sun.COM e = ddi_soft_state_init(&xpvtap_statep, sizeof (xpvtap_state_t), 1);
1677756SMark.Johnson@Sun.COM if (e != 0) {
1687756SMark.Johnson@Sun.COM return (e);
1697756SMark.Johnson@Sun.COM }
1707756SMark.Johnson@Sun.COM
1717756SMark.Johnson@Sun.COM e = mod_install(&xpvtap_modlinkage);
1727756SMark.Johnson@Sun.COM if (e != 0) {
1737756SMark.Johnson@Sun.COM ddi_soft_state_fini(&xpvtap_statep);
1747756SMark.Johnson@Sun.COM return (e);
1757756SMark.Johnson@Sun.COM }
1767756SMark.Johnson@Sun.COM
1777756SMark.Johnson@Sun.COM return (0);
1787756SMark.Johnson@Sun.COM }
1797756SMark.Johnson@Sun.COM
1807756SMark.Johnson@Sun.COM
1817756SMark.Johnson@Sun.COM /*
1827756SMark.Johnson@Sun.COM * _info()
1837756SMark.Johnson@Sun.COM */
1847756SMark.Johnson@Sun.COM int
_info(struct modinfo * modinfop)1857756SMark.Johnson@Sun.COM _info(struct modinfo *modinfop)
1867756SMark.Johnson@Sun.COM {
1877756SMark.Johnson@Sun.COM return (mod_info(&xpvtap_modlinkage, modinfop));
1887756SMark.Johnson@Sun.COM }
1897756SMark.Johnson@Sun.COM
1907756SMark.Johnson@Sun.COM
1917756SMark.Johnson@Sun.COM /*
1927756SMark.Johnson@Sun.COM * _fini()
1937756SMark.Johnson@Sun.COM */
1947756SMark.Johnson@Sun.COM int
_fini(void)1957756SMark.Johnson@Sun.COM _fini(void)
1967756SMark.Johnson@Sun.COM {
1977756SMark.Johnson@Sun.COM int e;
1987756SMark.Johnson@Sun.COM
1997756SMark.Johnson@Sun.COM e = mod_remove(&xpvtap_modlinkage);
2007756SMark.Johnson@Sun.COM if (e != 0) {
2017756SMark.Johnson@Sun.COM return (e);
2027756SMark.Johnson@Sun.COM }
2037756SMark.Johnson@Sun.COM
2047756SMark.Johnson@Sun.COM ddi_soft_state_fini(&xpvtap_statep);
2057756SMark.Johnson@Sun.COM
2067756SMark.Johnson@Sun.COM return (0);
2077756SMark.Johnson@Sun.COM }
2087756SMark.Johnson@Sun.COM
2097756SMark.Johnson@Sun.COM
2107756SMark.Johnson@Sun.COM /*
2117756SMark.Johnson@Sun.COM * xpvtap_attach()
2127756SMark.Johnson@Sun.COM */
2137756SMark.Johnson@Sun.COM static int
xpvtap_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2147756SMark.Johnson@Sun.COM xpvtap_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2157756SMark.Johnson@Sun.COM {
2167756SMark.Johnson@Sun.COM blk_ringinit_args_t args;
2177756SMark.Johnson@Sun.COM xpvtap_state_t *state;
2187756SMark.Johnson@Sun.COM int instance;
2197756SMark.Johnson@Sun.COM int e;
2207756SMark.Johnson@Sun.COM
2217756SMark.Johnson@Sun.COM
2227756SMark.Johnson@Sun.COM switch (cmd) {
2237756SMark.Johnson@Sun.COM case DDI_ATTACH:
2247756SMark.Johnson@Sun.COM break;
2257756SMark.Johnson@Sun.COM
2267756SMark.Johnson@Sun.COM case DDI_RESUME:
2277756SMark.Johnson@Sun.COM return (DDI_SUCCESS);
2287756SMark.Johnson@Sun.COM
2297756SMark.Johnson@Sun.COM default:
2307756SMark.Johnson@Sun.COM return (DDI_FAILURE);
2317756SMark.Johnson@Sun.COM }
2327756SMark.Johnson@Sun.COM
2337756SMark.Johnson@Sun.COM /* initialize our state info */
2347756SMark.Johnson@Sun.COM instance = ddi_get_instance(dip);
2357756SMark.Johnson@Sun.COM state = xpvtap_drv_init(instance);
2367756SMark.Johnson@Sun.COM if (state == NULL) {
2377756SMark.Johnson@Sun.COM return (DDI_FAILURE);
2387756SMark.Johnson@Sun.COM }
2397756SMark.Johnson@Sun.COM state->bt_dip = dip;
2407756SMark.Johnson@Sun.COM
2417756SMark.Johnson@Sun.COM /* Initialize the guest ring */
2427756SMark.Johnson@Sun.COM args.ar_dip = state->bt_dip;
2437756SMark.Johnson@Sun.COM args.ar_intr = xpvtap_intr;
2447756SMark.Johnson@Sun.COM args.ar_intr_arg = (caddr_t)state;
2457756SMark.Johnson@Sun.COM args.ar_ringup = xpvtap_user_thread_start;
2467756SMark.Johnson@Sun.COM args.ar_ringup_arg = (caddr_t)state;
2477756SMark.Johnson@Sun.COM args.ar_ringdown = xpvtap_user_app_stop;
2487756SMark.Johnson@Sun.COM args.ar_ringdown_arg = (caddr_t)state;
2497756SMark.Johnson@Sun.COM e = blk_ring_init(&args, &state->bt_guest_ring);
2507756SMark.Johnson@Sun.COM if (e != DDI_SUCCESS) {
2517756SMark.Johnson@Sun.COM goto attachfail_ringinit;
2527756SMark.Johnson@Sun.COM }
2537756SMark.Johnson@Sun.COM
2547756SMark.Johnson@Sun.COM /* create the minor node (for ioctl/mmap) */
2557756SMark.Johnson@Sun.COM e = ddi_create_minor_node(dip, "xpvtap", S_IFCHR, instance,
2567756SMark.Johnson@Sun.COM DDI_PSEUDO, 0);
2577756SMark.Johnson@Sun.COM if (e != DDI_SUCCESS) {
2587756SMark.Johnson@Sun.COM goto attachfail_minor_node;
2597756SMark.Johnson@Sun.COM }
2607756SMark.Johnson@Sun.COM
2617756SMark.Johnson@Sun.COM /* Report that driver was loaded */
2627756SMark.Johnson@Sun.COM ddi_report_dev(dip);
2637756SMark.Johnson@Sun.COM
2647756SMark.Johnson@Sun.COM return (DDI_SUCCESS);
2657756SMark.Johnson@Sun.COM
2667756SMark.Johnson@Sun.COM attachfail_minor_node:
2677756SMark.Johnson@Sun.COM blk_ring_fini(&state->bt_guest_ring);
2687756SMark.Johnson@Sun.COM attachfail_ringinit:
2697756SMark.Johnson@Sun.COM xpvtap_drv_fini(state);
2707756SMark.Johnson@Sun.COM return (DDI_FAILURE);
2717756SMark.Johnson@Sun.COM }
2727756SMark.Johnson@Sun.COM
2737756SMark.Johnson@Sun.COM
2747756SMark.Johnson@Sun.COM /*
2757756SMark.Johnson@Sun.COM * xpvtap_detach()
2767756SMark.Johnson@Sun.COM */
2777756SMark.Johnson@Sun.COM static int
xpvtap_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2787756SMark.Johnson@Sun.COM xpvtap_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2797756SMark.Johnson@Sun.COM {
2807756SMark.Johnson@Sun.COM xpvtap_state_t *state;
2817756SMark.Johnson@Sun.COM int instance;
2827756SMark.Johnson@Sun.COM
2837756SMark.Johnson@Sun.COM
2847756SMark.Johnson@Sun.COM instance = ddi_get_instance(dip);
2857756SMark.Johnson@Sun.COM state = ddi_get_soft_state(xpvtap_statep, instance);
2867756SMark.Johnson@Sun.COM if (state == NULL) {
2877756SMark.Johnson@Sun.COM return (DDI_FAILURE);
2887756SMark.Johnson@Sun.COM }
2897756SMark.Johnson@Sun.COM
2907756SMark.Johnson@Sun.COM switch (cmd) {
2917756SMark.Johnson@Sun.COM case DDI_DETACH:
2927756SMark.Johnson@Sun.COM break;
2937756SMark.Johnson@Sun.COM
2947756SMark.Johnson@Sun.COM case DDI_SUSPEND:
2957756SMark.Johnson@Sun.COM default:
2967756SMark.Johnson@Sun.COM return (DDI_FAILURE);
2977756SMark.Johnson@Sun.COM }
2987756SMark.Johnson@Sun.COM
2997756SMark.Johnson@Sun.COM xpvtap_user_thread_stop(state);
3007756SMark.Johnson@Sun.COM blk_ring_fini(&state->bt_guest_ring);
3017756SMark.Johnson@Sun.COM xpvtap_drv_fini(state);
3027756SMark.Johnson@Sun.COM ddi_remove_minor_node(dip, NULL);
3037756SMark.Johnson@Sun.COM
3047756SMark.Johnson@Sun.COM return (DDI_SUCCESS);
3057756SMark.Johnson@Sun.COM }
3067756SMark.Johnson@Sun.COM
3077756SMark.Johnson@Sun.COM
3087756SMark.Johnson@Sun.COM /*
3097756SMark.Johnson@Sun.COM * xpvtap_getinfo()
3107756SMark.Johnson@Sun.COM */
3117756SMark.Johnson@Sun.COM /*ARGSUSED*/
3127756SMark.Johnson@Sun.COM static int
xpvtap_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)3137756SMark.Johnson@Sun.COM xpvtap_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
3147756SMark.Johnson@Sun.COM {
3157756SMark.Johnson@Sun.COM xpvtap_state_t *state;
3167756SMark.Johnson@Sun.COM int instance;
3177756SMark.Johnson@Sun.COM dev_t dev;
3187756SMark.Johnson@Sun.COM int e;
3197756SMark.Johnson@Sun.COM
3207756SMark.Johnson@Sun.COM
3217756SMark.Johnson@Sun.COM dev = (dev_t)arg;
3227756SMark.Johnson@Sun.COM instance = getminor(dev);
3237756SMark.Johnson@Sun.COM
3247756SMark.Johnson@Sun.COM switch (cmd) {
3257756SMark.Johnson@Sun.COM case DDI_INFO_DEVT2DEVINFO:
3267756SMark.Johnson@Sun.COM state = ddi_get_soft_state(xpvtap_statep, instance);
3277756SMark.Johnson@Sun.COM if (state == NULL) {
3287756SMark.Johnson@Sun.COM return (DDI_FAILURE);
3297756SMark.Johnson@Sun.COM }
3307756SMark.Johnson@Sun.COM *result = (void *)state->bt_dip;
3317756SMark.Johnson@Sun.COM e = DDI_SUCCESS;
3327756SMark.Johnson@Sun.COM break;
3337756SMark.Johnson@Sun.COM
3347756SMark.Johnson@Sun.COM case DDI_INFO_DEVT2INSTANCE:
3357756SMark.Johnson@Sun.COM *result = (void *)(uintptr_t)instance;
3367756SMark.Johnson@Sun.COM e = DDI_SUCCESS;
3377756SMark.Johnson@Sun.COM break;
3387756SMark.Johnson@Sun.COM
3397756SMark.Johnson@Sun.COM default:
3407756SMark.Johnson@Sun.COM e = DDI_FAILURE;
3417756SMark.Johnson@Sun.COM break;
3427756SMark.Johnson@Sun.COM }
3437756SMark.Johnson@Sun.COM
3447756SMark.Johnson@Sun.COM return (e);
3457756SMark.Johnson@Sun.COM }
3467756SMark.Johnson@Sun.COM
3477756SMark.Johnson@Sun.COM
3487756SMark.Johnson@Sun.COM /*
3497756SMark.Johnson@Sun.COM * xpvtap_open()
3507756SMark.Johnson@Sun.COM */
3517756SMark.Johnson@Sun.COM /*ARGSUSED*/
3527756SMark.Johnson@Sun.COM static int
xpvtap_open(dev_t * devp,int flag,int otyp,cred_t * cred)3537756SMark.Johnson@Sun.COM xpvtap_open(dev_t *devp, int flag, int otyp, cred_t *cred)
3547756SMark.Johnson@Sun.COM {
3557756SMark.Johnson@Sun.COM xpvtap_state_t *state;
3567756SMark.Johnson@Sun.COM int instance;
3577756SMark.Johnson@Sun.COM
3587756SMark.Johnson@Sun.COM
3597756SMark.Johnson@Sun.COM if (secpolicy_xvm_control(cred)) {
3607756SMark.Johnson@Sun.COM return (EPERM);
3617756SMark.Johnson@Sun.COM }
3627756SMark.Johnson@Sun.COM
3637756SMark.Johnson@Sun.COM instance = getminor(*devp);
3647756SMark.Johnson@Sun.COM state = ddi_get_soft_state(xpvtap_statep, instance);
3657756SMark.Johnson@Sun.COM if (state == NULL) {
3667756SMark.Johnson@Sun.COM return (ENXIO);
3677756SMark.Johnson@Sun.COM }
3687756SMark.Johnson@Sun.COM
3697756SMark.Johnson@Sun.COM /* we should only be opened once */
3707756SMark.Johnson@Sun.COM mutex_enter(&state->bt_open.bo_mutex);
3717756SMark.Johnson@Sun.COM if (state->bt_open.bo_opened) {
3727756SMark.Johnson@Sun.COM mutex_exit(&state->bt_open.bo_mutex);
3737756SMark.Johnson@Sun.COM return (EBUSY);
3747756SMark.Johnson@Sun.COM }
3757756SMark.Johnson@Sun.COM state->bt_open.bo_opened = B_TRUE;
3767756SMark.Johnson@Sun.COM mutex_exit(&state->bt_open.bo_mutex);
3777756SMark.Johnson@Sun.COM
3787756SMark.Johnson@Sun.COM /*
3797756SMark.Johnson@Sun.COM * save the apps address space. need it for mapping/unmapping grefs
3807756SMark.Johnson@Sun.COM * since will be doing it in a separate kernel thread.
3817756SMark.Johnson@Sun.COM */
3827756SMark.Johnson@Sun.COM state->bt_map.um_as = curproc->p_as;
3837756SMark.Johnson@Sun.COM
3847756SMark.Johnson@Sun.COM return (0);
3857756SMark.Johnson@Sun.COM }
3867756SMark.Johnson@Sun.COM
3877756SMark.Johnson@Sun.COM
3887756SMark.Johnson@Sun.COM /*
3897756SMark.Johnson@Sun.COM * xpvtap_close()
3907756SMark.Johnson@Sun.COM */
3917756SMark.Johnson@Sun.COM /*ARGSUSED*/
3927756SMark.Johnson@Sun.COM static int
xpvtap_close(dev_t devp,int flag,int otyp,cred_t * cred)3937756SMark.Johnson@Sun.COM xpvtap_close(dev_t devp, int flag, int otyp, cred_t *cred)
3947756SMark.Johnson@Sun.COM {
3957756SMark.Johnson@Sun.COM xpvtap_state_t *state;
3967756SMark.Johnson@Sun.COM int instance;
3977756SMark.Johnson@Sun.COM
3987756SMark.Johnson@Sun.COM
3997756SMark.Johnson@Sun.COM instance = getminor(devp);
4007756SMark.Johnson@Sun.COM state = ddi_get_soft_state(xpvtap_statep, instance);
4017756SMark.Johnson@Sun.COM if (state == NULL) {
4027756SMark.Johnson@Sun.COM return (ENXIO);
4037756SMark.Johnson@Sun.COM }
4047756SMark.Johnson@Sun.COM
4057756SMark.Johnson@Sun.COM /*
4067756SMark.Johnson@Sun.COM * wake thread so it can cleanup and wait for it to exit so we can
4077756SMark.Johnson@Sun.COM * be sure it's not in the middle of processing a request/response.
4087756SMark.Johnson@Sun.COM */
4097756SMark.Johnson@Sun.COM mutex_enter(&state->bt_thread.ut_mutex);
4107756SMark.Johnson@Sun.COM state->bt_thread.ut_wake = B_TRUE;
4117756SMark.Johnson@Sun.COM state->bt_thread.ut_exit = B_TRUE;
4127756SMark.Johnson@Sun.COM cv_signal(&state->bt_thread.ut_wake_cv);
4137756SMark.Johnson@Sun.COM if (!state->bt_thread.ut_exit_done) {
4147756SMark.Johnson@Sun.COM cv_wait(&state->bt_thread.ut_exit_done_cv,
4157756SMark.Johnson@Sun.COM &state->bt_thread.ut_mutex);
4167756SMark.Johnson@Sun.COM }
4177756SMark.Johnson@Sun.COM ASSERT(state->bt_thread.ut_exit_done);
4187756SMark.Johnson@Sun.COM mutex_exit(&state->bt_thread.ut_mutex);
4197756SMark.Johnson@Sun.COM
4207756SMark.Johnson@Sun.COM state->bt_map.um_as = NULL;
4217756SMark.Johnson@Sun.COM state->bt_map.um_guest_pages = NULL;
4227756SMark.Johnson@Sun.COM
4237756SMark.Johnson@Sun.COM /*
4247756SMark.Johnson@Sun.COM * when the ring is brought down, a userland hotplug script is run
4257756SMark.Johnson@Sun.COM * which tries to bring the userland app down. We'll wait for a bit
4267756SMark.Johnson@Sun.COM * for the user app to exit. Notify the thread waiting that the app
4277756SMark.Johnson@Sun.COM * has closed the driver.
4287756SMark.Johnson@Sun.COM */
4297756SMark.Johnson@Sun.COM mutex_enter(&state->bt_open.bo_mutex);
4307756SMark.Johnson@Sun.COM ASSERT(state->bt_open.bo_opened);
4317756SMark.Johnson@Sun.COM state->bt_open.bo_opened = B_FALSE;
4327756SMark.Johnson@Sun.COM cv_signal(&state->bt_open.bo_exit_cv);
4337756SMark.Johnson@Sun.COM mutex_exit(&state->bt_open.bo_mutex);
4347756SMark.Johnson@Sun.COM
4357756SMark.Johnson@Sun.COM return (0);
4367756SMark.Johnson@Sun.COM }
4377756SMark.Johnson@Sun.COM
4387756SMark.Johnson@Sun.COM
4397756SMark.Johnson@Sun.COM /*
4407756SMark.Johnson@Sun.COM * xpvtap_ioctl()
4417756SMark.Johnson@Sun.COM */
4427756SMark.Johnson@Sun.COM /*ARGSUSED*/
4437756SMark.Johnson@Sun.COM static int
xpvtap_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred,int * rval)4447756SMark.Johnson@Sun.COM xpvtap_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred,
4457756SMark.Johnson@Sun.COM int *rval)
4467756SMark.Johnson@Sun.COM {
4477756SMark.Johnson@Sun.COM xpvtap_state_t *state;
4487756SMark.Johnson@Sun.COM int instance;
4497756SMark.Johnson@Sun.COM
4507756SMark.Johnson@Sun.COM
4517756SMark.Johnson@Sun.COM if (secpolicy_xvm_control(cred)) {
4527756SMark.Johnson@Sun.COM return (EPERM);
4537756SMark.Johnson@Sun.COM }
4547756SMark.Johnson@Sun.COM
4557756SMark.Johnson@Sun.COM instance = getminor(dev);
4567756SMark.Johnson@Sun.COM if (instance == -1) {
4577756SMark.Johnson@Sun.COM return (EBADF);
4587756SMark.Johnson@Sun.COM }
4597756SMark.Johnson@Sun.COM
4607756SMark.Johnson@Sun.COM state = ddi_get_soft_state(xpvtap_statep, instance);
4617756SMark.Johnson@Sun.COM if (state == NULL) {
4627756SMark.Johnson@Sun.COM return (EBADF);
4637756SMark.Johnson@Sun.COM }
4647756SMark.Johnson@Sun.COM
4657756SMark.Johnson@Sun.COM switch (cmd) {
4667756SMark.Johnson@Sun.COM case XPVTAP_IOCTL_RESP_PUSH:
4677756SMark.Johnson@Sun.COM /*
4687756SMark.Johnson@Sun.COM * wake thread, thread handles guest requests and user app
4697756SMark.Johnson@Sun.COM * responses.
4707756SMark.Johnson@Sun.COM */
4717756SMark.Johnson@Sun.COM mutex_enter(&state->bt_thread.ut_mutex);
4727756SMark.Johnson@Sun.COM state->bt_thread.ut_wake = B_TRUE;
4737756SMark.Johnson@Sun.COM cv_signal(&state->bt_thread.ut_wake_cv);
4747756SMark.Johnson@Sun.COM mutex_exit(&state->bt_thread.ut_mutex);
4757756SMark.Johnson@Sun.COM break;
4767756SMark.Johnson@Sun.COM
4777756SMark.Johnson@Sun.COM default:
4787756SMark.Johnson@Sun.COM cmn_err(CE_WARN, "ioctl(%d) not supported\n", cmd);
4797756SMark.Johnson@Sun.COM return (ENXIO);
4807756SMark.Johnson@Sun.COM }
4817756SMark.Johnson@Sun.COM
4827756SMark.Johnson@Sun.COM return (0);
4837756SMark.Johnson@Sun.COM }
4847756SMark.Johnson@Sun.COM
4857756SMark.Johnson@Sun.COM
4867756SMark.Johnson@Sun.COM /*
4877756SMark.Johnson@Sun.COM * xpvtap_segmap()
4887756SMark.Johnson@Sun.COM */
4897756SMark.Johnson@Sun.COM /*ARGSUSED*/
4907756SMark.Johnson@Sun.COM static int
xpvtap_segmap(dev_t dev,off_t off,struct as * asp,caddr_t * addrp,off_t len,unsigned int prot,unsigned int maxprot,unsigned int flags,cred_t * cred_p)4917756SMark.Johnson@Sun.COM xpvtap_segmap(dev_t dev, off_t off, struct as *asp, caddr_t *addrp,
4927756SMark.Johnson@Sun.COM off_t len, unsigned int prot, unsigned int maxprot, unsigned int flags,
4937756SMark.Johnson@Sun.COM cred_t *cred_p)
4947756SMark.Johnson@Sun.COM {
4957756SMark.Johnson@Sun.COM struct segmf_crargs a;
4967756SMark.Johnson@Sun.COM xpvtap_state_t *state;
4977756SMark.Johnson@Sun.COM int instance;
4987756SMark.Johnson@Sun.COM int e;
4997756SMark.Johnson@Sun.COM
5007756SMark.Johnson@Sun.COM
5017756SMark.Johnson@Sun.COM if (secpolicy_xvm_control(cred_p)) {
5027756SMark.Johnson@Sun.COM return (EPERM);
5037756SMark.Johnson@Sun.COM }
5047756SMark.Johnson@Sun.COM
5057756SMark.Johnson@Sun.COM instance = getminor(dev);
5067756SMark.Johnson@Sun.COM state = ddi_get_soft_state(xpvtap_statep, instance);
5077756SMark.Johnson@Sun.COM if (state == NULL) {
5087756SMark.Johnson@Sun.COM return (EBADF);
5097756SMark.Johnson@Sun.COM }
5107756SMark.Johnson@Sun.COM
5117756SMark.Johnson@Sun.COM /* the user app should be doing a MAP_SHARED mapping */
5127756SMark.Johnson@Sun.COM if ((flags & MAP_TYPE) != MAP_SHARED) {
5137756SMark.Johnson@Sun.COM return (EINVAL);
5147756SMark.Johnson@Sun.COM }
5157756SMark.Johnson@Sun.COM
5167756SMark.Johnson@Sun.COM /*
5177756SMark.Johnson@Sun.COM * if this is the user ring (offset = 0), devmap it (which ends up in
5187756SMark.Johnson@Sun.COM * xpvtap_devmap). devmap will alloc and map the ring into the
5197756SMark.Johnson@Sun.COM * app's VA space.
5207756SMark.Johnson@Sun.COM */
5217756SMark.Johnson@Sun.COM if (off == 0) {
5227756SMark.Johnson@Sun.COM e = devmap_setup(dev, (offset_t)off, asp, addrp, (size_t)len,
5237756SMark.Johnson@Sun.COM prot, maxprot, flags, cred_p);
5247756SMark.Johnson@Sun.COM return (e);
5257756SMark.Johnson@Sun.COM }
5267756SMark.Johnson@Sun.COM
5277756SMark.Johnson@Sun.COM /* this should be the mmap for the gref pages (offset = PAGESIZE) */
5287756SMark.Johnson@Sun.COM if (off != PAGESIZE) {
5297756SMark.Johnson@Sun.COM return (EINVAL);
5307756SMark.Johnson@Sun.COM }
5317756SMark.Johnson@Sun.COM
5327756SMark.Johnson@Sun.COM /* make sure we get the size we're expecting */
5337756SMark.Johnson@Sun.COM if (len != XPVTAP_GREF_BUFSIZE) {
5347756SMark.Johnson@Sun.COM return (EINVAL);
5357756SMark.Johnson@Sun.COM }
5367756SMark.Johnson@Sun.COM
5377756SMark.Johnson@Sun.COM /*
5387756SMark.Johnson@Sun.COM * reserve user app VA space for the gref pages and use segmf to
5397756SMark.Johnson@Sun.COM * manage the backing store for the physical memory. segmf will
5407756SMark.Johnson@Sun.COM * map in/out the grefs and fault them in/out.
5417756SMark.Johnson@Sun.COM */
5427756SMark.Johnson@Sun.COM ASSERT(asp == state->bt_map.um_as);
5437756SMark.Johnson@Sun.COM as_rangelock(asp);
5447756SMark.Johnson@Sun.COM if ((flags & MAP_FIXED) == 0) {
5457756SMark.Johnson@Sun.COM map_addr(addrp, len, 0, 0, flags);
5467756SMark.Johnson@Sun.COM if (*addrp == NULL) {
5477756SMark.Johnson@Sun.COM as_rangeunlock(asp);
5487756SMark.Johnson@Sun.COM return (ENOMEM);
5497756SMark.Johnson@Sun.COM }
5507756SMark.Johnson@Sun.COM } else {
5517756SMark.Johnson@Sun.COM /* User specified address */
5527756SMark.Johnson@Sun.COM (void) as_unmap(asp, *addrp, len);
5537756SMark.Johnson@Sun.COM }
5547756SMark.Johnson@Sun.COM a.dev = dev;
5557756SMark.Johnson@Sun.COM a.prot = (uchar_t)prot;
5567756SMark.Johnson@Sun.COM a.maxprot = (uchar_t)maxprot;
5577756SMark.Johnson@Sun.COM e = as_map(asp, *addrp, len, segmf_create, &a);
5587756SMark.Johnson@Sun.COM if (e != 0) {
5597756SMark.Johnson@Sun.COM as_rangeunlock(asp);
5607756SMark.Johnson@Sun.COM return (e);
5617756SMark.Johnson@Sun.COM }
5627756SMark.Johnson@Sun.COM as_rangeunlock(asp);
5637756SMark.Johnson@Sun.COM
5647756SMark.Johnson@Sun.COM /*
5657756SMark.Johnson@Sun.COM * Stash user base address, and compute address where the request
5667756SMark.Johnson@Sun.COM * array will end up.
5677756SMark.Johnson@Sun.COM */
5687756SMark.Johnson@Sun.COM state->bt_map.um_guest_pages = (caddr_t)*addrp;
5697756SMark.Johnson@Sun.COM state->bt_map.um_guest_size = (size_t)len;
5707756SMark.Johnson@Sun.COM
5717756SMark.Johnson@Sun.COM /* register an as callback so we can cleanup when the app goes away */
5727756SMark.Johnson@Sun.COM e = as_add_callback(asp, xpvtap_segmf_unregister, state,
5737756SMark.Johnson@Sun.COM AS_UNMAP_EVENT, *addrp, len, KM_SLEEP);
5747756SMark.Johnson@Sun.COM if (e != 0) {
5757756SMark.Johnson@Sun.COM (void) as_unmap(asp, *addrp, len);
5767756SMark.Johnson@Sun.COM return (EINVAL);
5777756SMark.Johnson@Sun.COM }
5787756SMark.Johnson@Sun.COM
5797756SMark.Johnson@Sun.COM /* wake thread to see if there are requests already queued up */
5807756SMark.Johnson@Sun.COM mutex_enter(&state->bt_thread.ut_mutex);
5817756SMark.Johnson@Sun.COM state->bt_thread.ut_wake = B_TRUE;
5827756SMark.Johnson@Sun.COM cv_signal(&state->bt_thread.ut_wake_cv);
5837756SMark.Johnson@Sun.COM mutex_exit(&state->bt_thread.ut_mutex);
5847756SMark.Johnson@Sun.COM
5857756SMark.Johnson@Sun.COM return (0);
5867756SMark.Johnson@Sun.COM }
5877756SMark.Johnson@Sun.COM
5887756SMark.Johnson@Sun.COM
5897756SMark.Johnson@Sun.COM /*
5907756SMark.Johnson@Sun.COM * xpvtap_devmap()
5917756SMark.Johnson@Sun.COM */
5927756SMark.Johnson@Sun.COM /*ARGSUSED*/
5937756SMark.Johnson@Sun.COM static int
xpvtap_devmap(dev_t dev,devmap_cookie_t dhp,offset_t off,size_t len,size_t * maplen,uint_t model)5947756SMark.Johnson@Sun.COM xpvtap_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
5957756SMark.Johnson@Sun.COM size_t *maplen, uint_t model)
5967756SMark.Johnson@Sun.COM {
5977756SMark.Johnson@Sun.COM xpvtap_user_ring_t *usring;
5987756SMark.Johnson@Sun.COM xpvtap_state_t *state;
5997756SMark.Johnson@Sun.COM int instance;
6007756SMark.Johnson@Sun.COM int e;
6017756SMark.Johnson@Sun.COM
6027756SMark.Johnson@Sun.COM
6037756SMark.Johnson@Sun.COM instance = getminor(dev);
6047756SMark.Johnson@Sun.COM state = ddi_get_soft_state(xpvtap_statep, instance);
6057756SMark.Johnson@Sun.COM if (state == NULL) {
6067756SMark.Johnson@Sun.COM return (EBADF);
6077756SMark.Johnson@Sun.COM }
6087756SMark.Johnson@Sun.COM
6097756SMark.Johnson@Sun.COM /* we should only get here if the offset was == 0 */
6107756SMark.Johnson@Sun.COM if (off != 0) {
6117756SMark.Johnson@Sun.COM return (EINVAL);
6127756SMark.Johnson@Sun.COM }
6137756SMark.Johnson@Sun.COM
6147756SMark.Johnson@Sun.COM /* we should only be mapping in one page */
6157756SMark.Johnson@Sun.COM if (len != PAGESIZE) {
6167756SMark.Johnson@Sun.COM return (EINVAL);
6177756SMark.Johnson@Sun.COM }
6187756SMark.Johnson@Sun.COM
6197756SMark.Johnson@Sun.COM /*
6207756SMark.Johnson@Sun.COM * we already allocated the user ring during driver attach, all we
6217756SMark.Johnson@Sun.COM * need to do is map it into the user app's VA.
6227756SMark.Johnson@Sun.COM */
6237756SMark.Johnson@Sun.COM usring = &state->bt_user_ring;
6247756SMark.Johnson@Sun.COM e = devmap_umem_setup(dhp, state->bt_dip, NULL, usring->ur_cookie, 0,
6257756SMark.Johnson@Sun.COM PAGESIZE, PROT_ALL, DEVMAP_DEFAULTS, NULL);
6267756SMark.Johnson@Sun.COM if (e < 0) {
6277756SMark.Johnson@Sun.COM return (e);
6287756SMark.Johnson@Sun.COM }
6297756SMark.Johnson@Sun.COM
6307756SMark.Johnson@Sun.COM /* return the size to compete the devmap */
6317756SMark.Johnson@Sun.COM *maplen = PAGESIZE;
6327756SMark.Johnson@Sun.COM
6337756SMark.Johnson@Sun.COM return (0);
6347756SMark.Johnson@Sun.COM }
6357756SMark.Johnson@Sun.COM
6367756SMark.Johnson@Sun.COM
6377756SMark.Johnson@Sun.COM /*
6387756SMark.Johnson@Sun.COM * xpvtap_chpoll()
6397756SMark.Johnson@Sun.COM */
6407756SMark.Johnson@Sun.COM static int
xpvtap_chpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)6417756SMark.Johnson@Sun.COM xpvtap_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
6427756SMark.Johnson@Sun.COM struct pollhead **phpp)
6437756SMark.Johnson@Sun.COM {
6447756SMark.Johnson@Sun.COM xpvtap_user_ring_t *usring;
6457756SMark.Johnson@Sun.COM xpvtap_state_t *state;
6467756SMark.Johnson@Sun.COM int instance;
6477756SMark.Johnson@Sun.COM
6487756SMark.Johnson@Sun.COM
6497756SMark.Johnson@Sun.COM instance = getminor(dev);
6507756SMark.Johnson@Sun.COM if (instance == -1) {
6517756SMark.Johnson@Sun.COM return (EBADF);
6527756SMark.Johnson@Sun.COM }
6537756SMark.Johnson@Sun.COM state = ddi_get_soft_state(xpvtap_statep, instance);
6547756SMark.Johnson@Sun.COM if (state == NULL) {
6557756SMark.Johnson@Sun.COM return (EBADF);
6567756SMark.Johnson@Sun.COM }
6577756SMark.Johnson@Sun.COM
6587756SMark.Johnson@Sun.COM if (((events & (POLLIN | POLLRDNORM)) == 0) && !anyyet) {
6597756SMark.Johnson@Sun.COM *reventsp = 0;
6607756SMark.Johnson@Sun.COM return (EINVAL);
6617756SMark.Johnson@Sun.COM }
6627756SMark.Johnson@Sun.COM
6637756SMark.Johnson@Sun.COM /*
6647756SMark.Johnson@Sun.COM * if we pushed requests on the user ring since the last poll, wakeup
6657756SMark.Johnson@Sun.COM * the user app
6667756SMark.Johnson@Sun.COM */
6677756SMark.Johnson@Sun.COM usring = &state->bt_user_ring;
6687756SMark.Johnson@Sun.COM if (usring->ur_prod_polled != usring->ur_ring.req_prod_pvt) {
6697756SMark.Johnson@Sun.COM
6707756SMark.Johnson@Sun.COM /*
6717756SMark.Johnson@Sun.COM * XXX - is this faster here or xpvtap_user_request_push??
6727756SMark.Johnson@Sun.COM * prelim data says here. Because less membars or because
6737756SMark.Johnson@Sun.COM * user thread will spin in poll requests before getting to
6747756SMark.Johnson@Sun.COM * responses?
6757756SMark.Johnson@Sun.COM */
6767756SMark.Johnson@Sun.COM RING_PUSH_REQUESTS(&usring->ur_ring);
6777756SMark.Johnson@Sun.COM
6787756SMark.Johnson@Sun.COM usring->ur_prod_polled = usring->ur_ring.sring->req_prod;
6797756SMark.Johnson@Sun.COM *reventsp = POLLIN | POLLRDNORM;
6807756SMark.Johnson@Sun.COM
6817756SMark.Johnson@Sun.COM /* no new requests */
6827756SMark.Johnson@Sun.COM } else {
6837756SMark.Johnson@Sun.COM *reventsp = 0;
6847756SMark.Johnson@Sun.COM if (!anyyet) {
6857756SMark.Johnson@Sun.COM *phpp = &state->bt_pollhead;
6867756SMark.Johnson@Sun.COM }
6877756SMark.Johnson@Sun.COM }
6887756SMark.Johnson@Sun.COM
6897756SMark.Johnson@Sun.COM return (0);
6907756SMark.Johnson@Sun.COM }
6917756SMark.Johnson@Sun.COM
6927756SMark.Johnson@Sun.COM
6937756SMark.Johnson@Sun.COM /*
6947756SMark.Johnson@Sun.COM * xpvtap_drv_init()
6957756SMark.Johnson@Sun.COM */
6967756SMark.Johnson@Sun.COM static xpvtap_state_t *
xpvtap_drv_init(int instance)6977756SMark.Johnson@Sun.COM xpvtap_drv_init(int instance)
6987756SMark.Johnson@Sun.COM {
6997756SMark.Johnson@Sun.COM xpvtap_state_t *state;
7007756SMark.Johnson@Sun.COM int e;
7017756SMark.Johnson@Sun.COM
7027756SMark.Johnson@Sun.COM
7037756SMark.Johnson@Sun.COM e = ddi_soft_state_zalloc(xpvtap_statep, instance);
7047756SMark.Johnson@Sun.COM if (e != DDI_SUCCESS) {
7057756SMark.Johnson@Sun.COM return (NULL);
7067756SMark.Johnson@Sun.COM }
7077756SMark.Johnson@Sun.COM state = ddi_get_soft_state(xpvtap_statep, instance);
7087756SMark.Johnson@Sun.COM if (state == NULL) {
7097756SMark.Johnson@Sun.COM goto drvinitfail_get_soft_state;
7107756SMark.Johnson@Sun.COM }
7117756SMark.Johnson@Sun.COM
7127756SMark.Johnson@Sun.COM state->bt_instance = instance;
7137756SMark.Johnson@Sun.COM mutex_init(&state->bt_open.bo_mutex, NULL, MUTEX_DRIVER, NULL);
7147756SMark.Johnson@Sun.COM cv_init(&state->bt_open.bo_exit_cv, NULL, CV_DRIVER, NULL);
7157756SMark.Johnson@Sun.COM state->bt_open.bo_opened = B_FALSE;
7167756SMark.Johnson@Sun.COM state->bt_map.um_registered = B_FALSE;
7177756SMark.Johnson@Sun.COM
7187756SMark.Johnson@Sun.COM /* initialize user ring, thread, mapping state */
7197756SMark.Johnson@Sun.COM e = xpvtap_user_init(state);
7207756SMark.Johnson@Sun.COM if (e != DDI_SUCCESS) {
7217756SMark.Johnson@Sun.COM goto drvinitfail_userinit;
7227756SMark.Johnson@Sun.COM }
7237756SMark.Johnson@Sun.COM
7247756SMark.Johnson@Sun.COM return (state);
7257756SMark.Johnson@Sun.COM
7267756SMark.Johnson@Sun.COM drvinitfail_userinit:
7277756SMark.Johnson@Sun.COM cv_destroy(&state->bt_open.bo_exit_cv);
7287756SMark.Johnson@Sun.COM mutex_destroy(&state->bt_open.bo_mutex);
7297756SMark.Johnson@Sun.COM drvinitfail_get_soft_state:
7307756SMark.Johnson@Sun.COM (void) ddi_soft_state_free(xpvtap_statep, instance);
7317756SMark.Johnson@Sun.COM return (NULL);
7327756SMark.Johnson@Sun.COM }
7337756SMark.Johnson@Sun.COM
7347756SMark.Johnson@Sun.COM
7357756SMark.Johnson@Sun.COM /*
7367756SMark.Johnson@Sun.COM * xpvtap_drv_fini()
7377756SMark.Johnson@Sun.COM */
7387756SMark.Johnson@Sun.COM static void
xpvtap_drv_fini(xpvtap_state_t * state)7397756SMark.Johnson@Sun.COM xpvtap_drv_fini(xpvtap_state_t *state)
7407756SMark.Johnson@Sun.COM {
7417756SMark.Johnson@Sun.COM xpvtap_user_fini(state);
7427756SMark.Johnson@Sun.COM cv_destroy(&state->bt_open.bo_exit_cv);
7437756SMark.Johnson@Sun.COM mutex_destroy(&state->bt_open.bo_mutex);
7447756SMark.Johnson@Sun.COM (void) ddi_soft_state_free(xpvtap_statep, state->bt_instance);
7457756SMark.Johnson@Sun.COM }
7467756SMark.Johnson@Sun.COM
7477756SMark.Johnson@Sun.COM
7487756SMark.Johnson@Sun.COM /*
7497756SMark.Johnson@Sun.COM * xpvtap_intr()
7507756SMark.Johnson@Sun.COM * this routine will be called when we have a request on the guest ring.
7517756SMark.Johnson@Sun.COM */
7527756SMark.Johnson@Sun.COM static uint_t
xpvtap_intr(caddr_t arg)7537756SMark.Johnson@Sun.COM xpvtap_intr(caddr_t arg)
7547756SMark.Johnson@Sun.COM {
7557756SMark.Johnson@Sun.COM xpvtap_state_t *state;
7567756SMark.Johnson@Sun.COM
7577756SMark.Johnson@Sun.COM
7587756SMark.Johnson@Sun.COM state = (xpvtap_state_t *)arg;
7597756SMark.Johnson@Sun.COM
7607756SMark.Johnson@Sun.COM /* wake thread, thread handles guest requests and user app responses */
7617756SMark.Johnson@Sun.COM mutex_enter(&state->bt_thread.ut_mutex);
7627756SMark.Johnson@Sun.COM state->bt_thread.ut_wake = B_TRUE;
7637756SMark.Johnson@Sun.COM cv_signal(&state->bt_thread.ut_wake_cv);
7647756SMark.Johnson@Sun.COM mutex_exit(&state->bt_thread.ut_mutex);
7657756SMark.Johnson@Sun.COM
7667756SMark.Johnson@Sun.COM return (DDI_INTR_CLAIMED);
7677756SMark.Johnson@Sun.COM }
7687756SMark.Johnson@Sun.COM
7697756SMark.Johnson@Sun.COM
7707756SMark.Johnson@Sun.COM /*
7717756SMark.Johnson@Sun.COM * xpvtap_segmf_register()
7727756SMark.Johnson@Sun.COM */
7737756SMark.Johnson@Sun.COM static int
xpvtap_segmf_register(xpvtap_state_t * state)7747756SMark.Johnson@Sun.COM xpvtap_segmf_register(xpvtap_state_t *state)
7757756SMark.Johnson@Sun.COM {
7767756SMark.Johnson@Sun.COM struct seg *seg;
7777756SMark.Johnson@Sun.COM uint64_t pte_ma;
7787756SMark.Johnson@Sun.COM struct as *as;
7797756SMark.Johnson@Sun.COM caddr_t uaddr;
7807756SMark.Johnson@Sun.COM uint_t pgcnt;
7817756SMark.Johnson@Sun.COM int i;
7827756SMark.Johnson@Sun.COM
7837756SMark.Johnson@Sun.COM
7847756SMark.Johnson@Sun.COM as = state->bt_map.um_as;
7857756SMark.Johnson@Sun.COM pgcnt = btopr(state->bt_map.um_guest_size);
7867756SMark.Johnson@Sun.COM uaddr = state->bt_map.um_guest_pages;
7877756SMark.Johnson@Sun.COM
7887756SMark.Johnson@Sun.COM if (pgcnt == 0) {
7897756SMark.Johnson@Sun.COM return (DDI_FAILURE);
7907756SMark.Johnson@Sun.COM }
7917756SMark.Johnson@Sun.COM
7927756SMark.Johnson@Sun.COM AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
7937756SMark.Johnson@Sun.COM
7947756SMark.Johnson@Sun.COM seg = as_findseg(as, state->bt_map.um_guest_pages, 0);
7957756SMark.Johnson@Sun.COM if ((seg == NULL) || ((uaddr + state->bt_map.um_guest_size) >
7967756SMark.Johnson@Sun.COM (seg->s_base + seg->s_size))) {
7977756SMark.Johnson@Sun.COM AS_LOCK_EXIT(as, &as->a_lock);
7987756SMark.Johnson@Sun.COM return (DDI_FAILURE);
7997756SMark.Johnson@Sun.COM }
8007756SMark.Johnson@Sun.COM
8017756SMark.Johnson@Sun.COM /*
8027756SMark.Johnson@Sun.COM * lock down the htables so the HAT can't steal them. Register the
8037756SMark.Johnson@Sun.COM * PTE MA's for each gref page with seg_mf so we can do user space
8047756SMark.Johnson@Sun.COM * gref mappings.
8057756SMark.Johnson@Sun.COM */
8067756SMark.Johnson@Sun.COM for (i = 0; i < pgcnt; i++) {
8077756SMark.Johnson@Sun.COM hat_prepare_mapping(as->a_hat, uaddr, &pte_ma);
8087756SMark.Johnson@Sun.COM hat_devload(as->a_hat, uaddr, PAGESIZE, (pfn_t)0,
8097756SMark.Johnson@Sun.COM PROT_READ | PROT_WRITE | PROT_USER | HAT_UNORDERED_OK,
8107756SMark.Johnson@Sun.COM HAT_LOAD_NOCONSIST | HAT_LOAD_LOCK);
8117756SMark.Johnson@Sun.COM hat_release_mapping(as->a_hat, uaddr);
8127756SMark.Johnson@Sun.COM segmf_add_gref_pte(seg, uaddr, pte_ma);
8137756SMark.Johnson@Sun.COM uaddr += PAGESIZE;
8147756SMark.Johnson@Sun.COM }
8157756SMark.Johnson@Sun.COM
8167756SMark.Johnson@Sun.COM state->bt_map.um_registered = B_TRUE;
8177756SMark.Johnson@Sun.COM
8187756SMark.Johnson@Sun.COM AS_LOCK_EXIT(as, &as->a_lock);
8197756SMark.Johnson@Sun.COM
8207756SMark.Johnson@Sun.COM return (DDI_SUCCESS);
8217756SMark.Johnson@Sun.COM }
8227756SMark.Johnson@Sun.COM
8237756SMark.Johnson@Sun.COM
8247756SMark.Johnson@Sun.COM /*
8257756SMark.Johnson@Sun.COM * xpvtap_segmf_unregister()
8267756SMark.Johnson@Sun.COM * as_callback routine
8277756SMark.Johnson@Sun.COM */
8287756SMark.Johnson@Sun.COM /*ARGSUSED*/
8297756SMark.Johnson@Sun.COM static void
xpvtap_segmf_unregister(struct as * as,void * arg,uint_t event)8307756SMark.Johnson@Sun.COM xpvtap_segmf_unregister(struct as *as, void *arg, uint_t event)
8317756SMark.Johnson@Sun.COM {
8327756SMark.Johnson@Sun.COM xpvtap_state_t *state;
8337756SMark.Johnson@Sun.COM caddr_t uaddr;
8347756SMark.Johnson@Sun.COM uint_t pgcnt;
8357756SMark.Johnson@Sun.COM int i;
8367756SMark.Johnson@Sun.COM
8377756SMark.Johnson@Sun.COM
8387756SMark.Johnson@Sun.COM state = (xpvtap_state_t *)arg;
8397756SMark.Johnson@Sun.COM if (!state->bt_map.um_registered) {
8407792SMark.Johnson@Sun.COM /* remove the callback (which is this routine) */
8417792SMark.Johnson@Sun.COM (void) as_delete_callback(as, arg);
8427756SMark.Johnson@Sun.COM return;
8437756SMark.Johnson@Sun.COM }
8447756SMark.Johnson@Sun.COM
8457756SMark.Johnson@Sun.COM pgcnt = btopr(state->bt_map.um_guest_size);
8467756SMark.Johnson@Sun.COM uaddr = state->bt_map.um_guest_pages;
8477756SMark.Johnson@Sun.COM
8487756SMark.Johnson@Sun.COM /* unmap any outstanding req's grefs */
8497756SMark.Johnson@Sun.COM xpvtap_rs_flush(state->bt_map.um_rs, xpvtap_user_request_unmap, state);
8507756SMark.Johnson@Sun.COM
8517756SMark.Johnson@Sun.COM /* Unlock the gref pages */
8527756SMark.Johnson@Sun.COM for (i = 0; i < pgcnt; i++) {
8537756SMark.Johnson@Sun.COM AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
8547756SMark.Johnson@Sun.COM hat_prepare_mapping(as->a_hat, uaddr, NULL);
8557756SMark.Johnson@Sun.COM hat_unload(as->a_hat, uaddr, PAGESIZE, HAT_UNLOAD_UNLOCK);
8567756SMark.Johnson@Sun.COM hat_release_mapping(as->a_hat, uaddr);
8577756SMark.Johnson@Sun.COM AS_LOCK_EXIT(as, &as->a_lock);
8587756SMark.Johnson@Sun.COM uaddr += PAGESIZE;
8597756SMark.Johnson@Sun.COM }
8607756SMark.Johnson@Sun.COM
8617756SMark.Johnson@Sun.COM /* remove the callback (which is this routine) */
8627756SMark.Johnson@Sun.COM (void) as_delete_callback(as, arg);
8637756SMark.Johnson@Sun.COM
8647756SMark.Johnson@Sun.COM state->bt_map.um_registered = B_FALSE;
8657756SMark.Johnson@Sun.COM }
8667756SMark.Johnson@Sun.COM
8677756SMark.Johnson@Sun.COM
8687756SMark.Johnson@Sun.COM /*
8697756SMark.Johnson@Sun.COM * xpvtap_user_init()
8707756SMark.Johnson@Sun.COM */
8717756SMark.Johnson@Sun.COM static int
xpvtap_user_init(xpvtap_state_t * state)8727756SMark.Johnson@Sun.COM xpvtap_user_init(xpvtap_state_t *state)
8737756SMark.Johnson@Sun.COM {
8747756SMark.Johnson@Sun.COM xpvtap_user_map_t *map;
8757756SMark.Johnson@Sun.COM int e;
8767756SMark.Johnson@Sun.COM
8777756SMark.Johnson@Sun.COM
8787756SMark.Johnson@Sun.COM map = &state->bt_map;
8797756SMark.Johnson@Sun.COM
8807756SMark.Johnson@Sun.COM /* Setup the ring between the driver and user app */
8817756SMark.Johnson@Sun.COM e = xpvtap_user_ring_init(state);
8827756SMark.Johnson@Sun.COM if (e != DDI_SUCCESS) {
8837756SMark.Johnson@Sun.COM return (DDI_FAILURE);
8847756SMark.Johnson@Sun.COM }
8857756SMark.Johnson@Sun.COM
8867756SMark.Johnson@Sun.COM /*
8877756SMark.Johnson@Sun.COM * the user ring can handle BLKIF_RING_SIZE outstanding requests. This
8887756SMark.Johnson@Sun.COM * is the same number of requests as the guest ring. Initialize the
8897756SMark.Johnson@Sun.COM * state we use to track request IDs to the user app. These IDs will
8907756SMark.Johnson@Sun.COM * also identify which group of gref pages correspond with the
8917756SMark.Johnson@Sun.COM * request.
8927756SMark.Johnson@Sun.COM */
8937756SMark.Johnson@Sun.COM xpvtap_rs_init(0, (BLKIF_RING_SIZE - 1), &map->um_rs);
8947756SMark.Johnson@Sun.COM
8957756SMark.Johnson@Sun.COM /*
8967756SMark.Johnson@Sun.COM * allocate the space to store a copy of each outstanding requests. We
8977756SMark.Johnson@Sun.COM * will need to reference the ID and the number of segments when we
8987756SMark.Johnson@Sun.COM * get the response from the user app.
8997756SMark.Johnson@Sun.COM */
9007756SMark.Johnson@Sun.COM map->um_outstanding_reqs = kmem_zalloc(
9017756SMark.Johnson@Sun.COM sizeof (*map->um_outstanding_reqs) * BLKIF_RING_SIZE,
9027756SMark.Johnson@Sun.COM KM_SLEEP);
9037756SMark.Johnson@Sun.COM
9047756SMark.Johnson@Sun.COM /*
9057756SMark.Johnson@Sun.COM * initialize the thread we use to process guest requests and user
9067756SMark.Johnson@Sun.COM * responses.
9077756SMark.Johnson@Sun.COM */
9087756SMark.Johnson@Sun.COM e = xpvtap_user_thread_init(state);
9097756SMark.Johnson@Sun.COM if (e != DDI_SUCCESS) {
9107756SMark.Johnson@Sun.COM goto userinitfail_user_thread_init;
9117756SMark.Johnson@Sun.COM }
9127756SMark.Johnson@Sun.COM
9137756SMark.Johnson@Sun.COM return (DDI_SUCCESS);
9147756SMark.Johnson@Sun.COM
9157756SMark.Johnson@Sun.COM userinitfail_user_thread_init:
9167756SMark.Johnson@Sun.COM xpvtap_rs_fini(&map->um_rs);
9177756SMark.Johnson@Sun.COM kmem_free(map->um_outstanding_reqs,
9187756SMark.Johnson@Sun.COM sizeof (*map->um_outstanding_reqs) * BLKIF_RING_SIZE);
9197756SMark.Johnson@Sun.COM xpvtap_user_ring_fini(state);
9207756SMark.Johnson@Sun.COM return (DDI_FAILURE);
9217756SMark.Johnson@Sun.COM }
9227756SMark.Johnson@Sun.COM
9237756SMark.Johnson@Sun.COM
9247756SMark.Johnson@Sun.COM /*
9257756SMark.Johnson@Sun.COM * xpvtap_user_ring_init()
9267756SMark.Johnson@Sun.COM */
9277756SMark.Johnson@Sun.COM static int
xpvtap_user_ring_init(xpvtap_state_t * state)9287756SMark.Johnson@Sun.COM xpvtap_user_ring_init(xpvtap_state_t *state)
9297756SMark.Johnson@Sun.COM {
9307756SMark.Johnson@Sun.COM xpvtap_user_ring_t *usring;
9317756SMark.Johnson@Sun.COM
9327756SMark.Johnson@Sun.COM
9337756SMark.Johnson@Sun.COM usring = &state->bt_user_ring;
9347756SMark.Johnson@Sun.COM
9357756SMark.Johnson@Sun.COM /* alocate and initialize the page for the shared user ring */
9367756SMark.Johnson@Sun.COM usring->ur_sring = (blkif_sring_t *)ddi_umem_alloc(PAGESIZE,
9377756SMark.Johnson@Sun.COM DDI_UMEM_SLEEP, &usring->ur_cookie);
9387756SMark.Johnson@Sun.COM SHARED_RING_INIT(usring->ur_sring);
9397756SMark.Johnson@Sun.COM FRONT_RING_INIT(&usring->ur_ring, usring->ur_sring, PAGESIZE);
9407756SMark.Johnson@Sun.COM usring->ur_prod_polled = 0;
9417756SMark.Johnson@Sun.COM
9427756SMark.Johnson@Sun.COM return (DDI_SUCCESS);
9437756SMark.Johnson@Sun.COM }
9447756SMark.Johnson@Sun.COM
9457756SMark.Johnson@Sun.COM
9467756SMark.Johnson@Sun.COM /*
9477756SMark.Johnson@Sun.COM * xpvtap_user_thread_init()
9487756SMark.Johnson@Sun.COM */
9497756SMark.Johnson@Sun.COM static int
xpvtap_user_thread_init(xpvtap_state_t * state)9507756SMark.Johnson@Sun.COM xpvtap_user_thread_init(xpvtap_state_t *state)
9517756SMark.Johnson@Sun.COM {
9527756SMark.Johnson@Sun.COM xpvtap_user_thread_t *thread;
9537756SMark.Johnson@Sun.COM char taskqname[32];
9547756SMark.Johnson@Sun.COM
9557756SMark.Johnson@Sun.COM
9567756SMark.Johnson@Sun.COM thread = &state->bt_thread;
9577756SMark.Johnson@Sun.COM
9587756SMark.Johnson@Sun.COM mutex_init(&thread->ut_mutex, NULL, MUTEX_DRIVER, NULL);
9597756SMark.Johnson@Sun.COM cv_init(&thread->ut_wake_cv, NULL, CV_DRIVER, NULL);
9607756SMark.Johnson@Sun.COM cv_init(&thread->ut_exit_done_cv, NULL, CV_DRIVER, NULL);
9617756SMark.Johnson@Sun.COM thread->ut_wake = B_FALSE;
9627756SMark.Johnson@Sun.COM thread->ut_exit = B_FALSE;
9637756SMark.Johnson@Sun.COM thread->ut_exit_done = B_TRUE;
9647756SMark.Johnson@Sun.COM
9657756SMark.Johnson@Sun.COM /* create but don't start the user thread */
9667756SMark.Johnson@Sun.COM (void) sprintf(taskqname, "xvptap_%d", state->bt_instance);
9677756SMark.Johnson@Sun.COM thread->ut_taskq = ddi_taskq_create(state->bt_dip, taskqname, 1,
9687756SMark.Johnson@Sun.COM TASKQ_DEFAULTPRI, 0);
9697756SMark.Johnson@Sun.COM if (thread->ut_taskq == NULL) {
9707756SMark.Johnson@Sun.COM goto userinitthrfail_taskq_create;
9717756SMark.Johnson@Sun.COM }
9727756SMark.Johnson@Sun.COM
9737756SMark.Johnson@Sun.COM return (DDI_SUCCESS);
9747756SMark.Johnson@Sun.COM
9757756SMark.Johnson@Sun.COM userinitthrfail_taskq_dispatch:
9767756SMark.Johnson@Sun.COM ddi_taskq_destroy(thread->ut_taskq);
9777756SMark.Johnson@Sun.COM userinitthrfail_taskq_create:
9787756SMark.Johnson@Sun.COM cv_destroy(&thread->ut_exit_done_cv);
9797756SMark.Johnson@Sun.COM cv_destroy(&thread->ut_wake_cv);
9807756SMark.Johnson@Sun.COM mutex_destroy(&thread->ut_mutex);
9817756SMark.Johnson@Sun.COM
9827756SMark.Johnson@Sun.COM return (DDI_FAILURE);
9837756SMark.Johnson@Sun.COM }
9847756SMark.Johnson@Sun.COM
9857756SMark.Johnson@Sun.COM
9867756SMark.Johnson@Sun.COM /*
9877756SMark.Johnson@Sun.COM * xpvtap_user_thread_start()
9887756SMark.Johnson@Sun.COM */
9897756SMark.Johnson@Sun.COM static void
xpvtap_user_thread_start(caddr_t arg)9907756SMark.Johnson@Sun.COM xpvtap_user_thread_start(caddr_t arg)
9917756SMark.Johnson@Sun.COM {
9927756SMark.Johnson@Sun.COM xpvtap_user_thread_t *thread;
9937756SMark.Johnson@Sun.COM xpvtap_state_t *state;
9947756SMark.Johnson@Sun.COM int e;
9957756SMark.Johnson@Sun.COM
9967756SMark.Johnson@Sun.COM
9977756SMark.Johnson@Sun.COM state = (xpvtap_state_t *)arg;
9987756SMark.Johnson@Sun.COM thread = &state->bt_thread;
9997756SMark.Johnson@Sun.COM
10007756SMark.Johnson@Sun.COM /* start the user thread */
10017756SMark.Johnson@Sun.COM thread->ut_exit_done = B_FALSE;
10027756SMark.Johnson@Sun.COM e = ddi_taskq_dispatch(thread->ut_taskq, xpvtap_user_thread, state,
10037756SMark.Johnson@Sun.COM DDI_SLEEP);
10047756SMark.Johnson@Sun.COM if (e != DDI_SUCCESS) {
10057756SMark.Johnson@Sun.COM thread->ut_exit_done = B_TRUE;
10067756SMark.Johnson@Sun.COM cmn_err(CE_WARN, "Unable to start user thread\n");
10077756SMark.Johnson@Sun.COM }
10087756SMark.Johnson@Sun.COM }
10097756SMark.Johnson@Sun.COM
10107756SMark.Johnson@Sun.COM
10117756SMark.Johnson@Sun.COM /*
10127756SMark.Johnson@Sun.COM * xpvtap_user_thread_stop()
10137756SMark.Johnson@Sun.COM */
10147756SMark.Johnson@Sun.COM static void
xpvtap_user_thread_stop(xpvtap_state_t * state)10157756SMark.Johnson@Sun.COM xpvtap_user_thread_stop(xpvtap_state_t *state)
10167756SMark.Johnson@Sun.COM {
10177756SMark.Johnson@Sun.COM /* wake thread so it can exit */
10187756SMark.Johnson@Sun.COM mutex_enter(&state->bt_thread.ut_mutex);
10197756SMark.Johnson@Sun.COM state->bt_thread.ut_wake = B_TRUE;
10207756SMark.Johnson@Sun.COM state->bt_thread.ut_exit = B_TRUE;
10217756SMark.Johnson@Sun.COM cv_signal(&state->bt_thread.ut_wake_cv);
10227756SMark.Johnson@Sun.COM if (!state->bt_thread.ut_exit_done) {
10237756SMark.Johnson@Sun.COM cv_wait(&state->bt_thread.ut_exit_done_cv,
10247756SMark.Johnson@Sun.COM &state->bt_thread.ut_mutex);
10257756SMark.Johnson@Sun.COM }
10267756SMark.Johnson@Sun.COM mutex_exit(&state->bt_thread.ut_mutex);
10277756SMark.Johnson@Sun.COM ASSERT(state->bt_thread.ut_exit_done);
10287756SMark.Johnson@Sun.COM }
10297756SMark.Johnson@Sun.COM
10307756SMark.Johnson@Sun.COM
10317756SMark.Johnson@Sun.COM /*
10327756SMark.Johnson@Sun.COM * xpvtap_user_fini()
10337756SMark.Johnson@Sun.COM */
10347756SMark.Johnson@Sun.COM static void
xpvtap_user_fini(xpvtap_state_t * state)10357756SMark.Johnson@Sun.COM xpvtap_user_fini(xpvtap_state_t *state)
10367756SMark.Johnson@Sun.COM {
10377756SMark.Johnson@Sun.COM xpvtap_user_map_t *map;
10387756SMark.Johnson@Sun.COM
10397756SMark.Johnson@Sun.COM
10407756SMark.Johnson@Sun.COM map = &state->bt_map;
10417756SMark.Johnson@Sun.COM
10427756SMark.Johnson@Sun.COM xpvtap_user_thread_fini(state);
10437756SMark.Johnson@Sun.COM xpvtap_rs_fini(&map->um_rs);
10447756SMark.Johnson@Sun.COM kmem_free(map->um_outstanding_reqs,
10457756SMark.Johnson@Sun.COM sizeof (*map->um_outstanding_reqs) * BLKIF_RING_SIZE);
10467756SMark.Johnson@Sun.COM xpvtap_user_ring_fini(state);
10477756SMark.Johnson@Sun.COM }
10487756SMark.Johnson@Sun.COM
10497756SMark.Johnson@Sun.COM
10507756SMark.Johnson@Sun.COM /*
10517756SMark.Johnson@Sun.COM * xpvtap_user_ring_fini()
10527756SMark.Johnson@Sun.COM */
10537756SMark.Johnson@Sun.COM static void
xpvtap_user_ring_fini(xpvtap_state_t * state)10547756SMark.Johnson@Sun.COM xpvtap_user_ring_fini(xpvtap_state_t *state)
10557756SMark.Johnson@Sun.COM {
10567756SMark.Johnson@Sun.COM ddi_umem_free(state->bt_user_ring.ur_cookie);
10577756SMark.Johnson@Sun.COM }
10587756SMark.Johnson@Sun.COM
10597756SMark.Johnson@Sun.COM
10607756SMark.Johnson@Sun.COM /*
10617756SMark.Johnson@Sun.COM * xpvtap_user_thread_fini()
10627756SMark.Johnson@Sun.COM */
10637756SMark.Johnson@Sun.COM static void
xpvtap_user_thread_fini(xpvtap_state_t * state)10647756SMark.Johnson@Sun.COM xpvtap_user_thread_fini(xpvtap_state_t *state)
10657756SMark.Johnson@Sun.COM {
10667756SMark.Johnson@Sun.COM ddi_taskq_destroy(state->bt_thread.ut_taskq);
10677756SMark.Johnson@Sun.COM cv_destroy(&state->bt_thread.ut_exit_done_cv);
10687756SMark.Johnson@Sun.COM cv_destroy(&state->bt_thread.ut_wake_cv);
10697756SMark.Johnson@Sun.COM mutex_destroy(&state->bt_thread.ut_mutex);
10707756SMark.Johnson@Sun.COM }
10717756SMark.Johnson@Sun.COM
10727756SMark.Johnson@Sun.COM
10737756SMark.Johnson@Sun.COM /*
10747756SMark.Johnson@Sun.COM * xpvtap_user_thread()
10757756SMark.Johnson@Sun.COM */
10767756SMark.Johnson@Sun.COM static void
xpvtap_user_thread(void * arg)10777756SMark.Johnson@Sun.COM xpvtap_user_thread(void *arg)
10787756SMark.Johnson@Sun.COM {
10797756SMark.Johnson@Sun.COM xpvtap_user_thread_t *thread;
10807756SMark.Johnson@Sun.COM blkif_response_t resp;
10817756SMark.Johnson@Sun.COM xpvtap_state_t *state;
10827756SMark.Johnson@Sun.COM blkif_request_t req;
10837756SMark.Johnson@Sun.COM boolean_t b;
10847756SMark.Johnson@Sun.COM uint_t uid;
10857756SMark.Johnson@Sun.COM int e;
10867756SMark.Johnson@Sun.COM
10877756SMark.Johnson@Sun.COM
10887756SMark.Johnson@Sun.COM state = (xpvtap_state_t *)arg;
10897756SMark.Johnson@Sun.COM thread = &state->bt_thread;
10907756SMark.Johnson@Sun.COM
10917756SMark.Johnson@Sun.COM xpvtap_thread_start:
10927756SMark.Johnson@Sun.COM /* See if we are supposed to exit */
10937756SMark.Johnson@Sun.COM mutex_enter(&thread->ut_mutex);
10947756SMark.Johnson@Sun.COM if (thread->ut_exit) {
10957756SMark.Johnson@Sun.COM thread->ut_exit_done = B_TRUE;
10967756SMark.Johnson@Sun.COM cv_signal(&state->bt_thread.ut_exit_done_cv);
10977756SMark.Johnson@Sun.COM mutex_exit(&thread->ut_mutex);
10987756SMark.Johnson@Sun.COM return;
10997756SMark.Johnson@Sun.COM }
11007756SMark.Johnson@Sun.COM
11017756SMark.Johnson@Sun.COM /*
11027756SMark.Johnson@Sun.COM * if we aren't supposed to be awake, wait until someone wakes us.
11037756SMark.Johnson@Sun.COM * when we wake up, check for a kill or someone telling us to exit.
11047756SMark.Johnson@Sun.COM */
11057756SMark.Johnson@Sun.COM if (!thread->ut_wake) {
11067756SMark.Johnson@Sun.COM e = cv_wait_sig(&thread->ut_wake_cv, &thread->ut_mutex);
11077756SMark.Johnson@Sun.COM if ((e == 0) || (thread->ut_exit)) {
11087756SMark.Johnson@Sun.COM thread->ut_exit = B_TRUE;
11097756SMark.Johnson@Sun.COM mutex_exit(&thread->ut_mutex);
11107756SMark.Johnson@Sun.COM goto xpvtap_thread_start;
11117756SMark.Johnson@Sun.COM }
11127756SMark.Johnson@Sun.COM }
11137756SMark.Johnson@Sun.COM
11147756SMark.Johnson@Sun.COM /* if someone didn't wake us, go back to the start of the thread */
11157756SMark.Johnson@Sun.COM if (!thread->ut_wake) {
11167756SMark.Johnson@Sun.COM mutex_exit(&thread->ut_mutex);
11177756SMark.Johnson@Sun.COM goto xpvtap_thread_start;
11187756SMark.Johnson@Sun.COM }
11197756SMark.Johnson@Sun.COM
11207756SMark.Johnson@Sun.COM /* we are awake */
11217756SMark.Johnson@Sun.COM thread->ut_wake = B_FALSE;
11227756SMark.Johnson@Sun.COM mutex_exit(&thread->ut_mutex);
11237756SMark.Johnson@Sun.COM
11247756SMark.Johnson@Sun.COM /* process requests from the guest */
11257756SMark.Johnson@Sun.COM do {
11267756SMark.Johnson@Sun.COM /*
11277756SMark.Johnson@Sun.COM * check for requests from the guest. if we don't have any,
11287756SMark.Johnson@Sun.COM * break out of the loop.
11297756SMark.Johnson@Sun.COM */
11307756SMark.Johnson@Sun.COM e = blk_ring_request_get(state->bt_guest_ring, &req);
11317756SMark.Johnson@Sun.COM if (e == B_FALSE) {
11327756SMark.Johnson@Sun.COM break;
11337756SMark.Johnson@Sun.COM }
11347756SMark.Johnson@Sun.COM
11357756SMark.Johnson@Sun.COM /* we got a request, map the grefs into the user app's VA */
11367756SMark.Johnson@Sun.COM e = xpvtap_user_request_map(state, &req, &uid);
11377756SMark.Johnson@Sun.COM if (e != DDI_SUCCESS) {
11387756SMark.Johnson@Sun.COM /*
11397756SMark.Johnson@Sun.COM * If we couldn't map the request (e.g. user app hasn't
11407756SMark.Johnson@Sun.COM * opened the device yet), requeue it and try again
11417756SMark.Johnson@Sun.COM * later
11427756SMark.Johnson@Sun.COM */
11437756SMark.Johnson@Sun.COM blk_ring_request_requeue(state->bt_guest_ring);
11447756SMark.Johnson@Sun.COM break;
11457756SMark.Johnson@Sun.COM }
11467756SMark.Johnson@Sun.COM
11477756SMark.Johnson@Sun.COM /* push the request to the user app */
11487756SMark.Johnson@Sun.COM e = xpvtap_user_request_push(state, &req, uid);
11497756SMark.Johnson@Sun.COM if (e != DDI_SUCCESS) {
11507756SMark.Johnson@Sun.COM resp.id = req.id;
11517756SMark.Johnson@Sun.COM resp.operation = req.operation;
11527756SMark.Johnson@Sun.COM resp.status = BLKIF_RSP_ERROR;
11537756SMark.Johnson@Sun.COM blk_ring_response_put(state->bt_guest_ring, &resp);
11547756SMark.Johnson@Sun.COM }
11557756SMark.Johnson@Sun.COM } while (!thread->ut_exit);
11567756SMark.Johnson@Sun.COM
11577756SMark.Johnson@Sun.COM /* process reponses from the user app */
11587756SMark.Johnson@Sun.COM do {
11597756SMark.Johnson@Sun.COM /*
11607756SMark.Johnson@Sun.COM * check for responses from the user app. if we don't have any,
11617756SMark.Johnson@Sun.COM * break out of the loop.
11627756SMark.Johnson@Sun.COM */
11637756SMark.Johnson@Sun.COM b = xpvtap_user_response_get(state, &resp, &uid);
11647756SMark.Johnson@Sun.COM if (b != B_TRUE) {
11657756SMark.Johnson@Sun.COM break;
11667756SMark.Johnson@Sun.COM }
11677756SMark.Johnson@Sun.COM
11687756SMark.Johnson@Sun.COM /*
11697756SMark.Johnson@Sun.COM * if we got a response, unmap the grefs from the matching
11707756SMark.Johnson@Sun.COM * request.
11717756SMark.Johnson@Sun.COM */
11727756SMark.Johnson@Sun.COM xpvtap_user_request_unmap(state, uid);
11737756SMark.Johnson@Sun.COM
11747756SMark.Johnson@Sun.COM /* push the response to the guest */
11757756SMark.Johnson@Sun.COM blk_ring_response_put(state->bt_guest_ring, &resp);
11767756SMark.Johnson@Sun.COM } while (!thread->ut_exit);
11777756SMark.Johnson@Sun.COM
11787756SMark.Johnson@Sun.COM goto xpvtap_thread_start;
11797756SMark.Johnson@Sun.COM }
11807756SMark.Johnson@Sun.COM
11817756SMark.Johnson@Sun.COM
11827756SMark.Johnson@Sun.COM /*
11837756SMark.Johnson@Sun.COM * xpvtap_user_request_map()
11847756SMark.Johnson@Sun.COM */
11857756SMark.Johnson@Sun.COM static int
xpvtap_user_request_map(xpvtap_state_t * state,blkif_request_t * req,uint_t * uid)11867756SMark.Johnson@Sun.COM xpvtap_user_request_map(xpvtap_state_t *state, blkif_request_t *req,
11877756SMark.Johnson@Sun.COM uint_t *uid)
11887756SMark.Johnson@Sun.COM {
11897756SMark.Johnson@Sun.COM grant_ref_t gref[BLKIF_MAX_SEGMENTS_PER_REQUEST];
11907756SMark.Johnson@Sun.COM struct seg *seg;
11917756SMark.Johnson@Sun.COM struct as *as;
11927756SMark.Johnson@Sun.COM domid_t domid;
11937756SMark.Johnson@Sun.COM caddr_t uaddr;
11947756SMark.Johnson@Sun.COM uint_t flags;
11957756SMark.Johnson@Sun.COM int i;
11967756SMark.Johnson@Sun.COM int e;
11977756SMark.Johnson@Sun.COM
11987756SMark.Johnson@Sun.COM
11997756SMark.Johnson@Sun.COM domid = xvdi_get_oeid(state->bt_dip);
12007756SMark.Johnson@Sun.COM
12017756SMark.Johnson@Sun.COM as = state->bt_map.um_as;
12027756SMark.Johnson@Sun.COM if ((as == NULL) || (state->bt_map.um_guest_pages == NULL)) {
12037756SMark.Johnson@Sun.COM return (DDI_FAILURE);
12047756SMark.Johnson@Sun.COM }
12057756SMark.Johnson@Sun.COM
12067756SMark.Johnson@Sun.COM /* has to happen after segmap returns */
12077756SMark.Johnson@Sun.COM if (!state->bt_map.um_registered) {
12087756SMark.Johnson@Sun.COM /* register the pte's with segmf */
12097756SMark.Johnson@Sun.COM e = xpvtap_segmf_register(state);
12107756SMark.Johnson@Sun.COM if (e != DDI_SUCCESS) {
12117756SMark.Johnson@Sun.COM return (DDI_FAILURE);
12127756SMark.Johnson@Sun.COM }
12137756SMark.Johnson@Sun.COM }
12147756SMark.Johnson@Sun.COM
12157756SMark.Johnson@Sun.COM /* alloc an ID for the user ring */
12167756SMark.Johnson@Sun.COM e = xpvtap_rs_alloc(state->bt_map.um_rs, uid);
12177756SMark.Johnson@Sun.COM if (e != DDI_SUCCESS) {
12187756SMark.Johnson@Sun.COM return (DDI_FAILURE);
12197756SMark.Johnson@Sun.COM }
12207756SMark.Johnson@Sun.COM
12217756SMark.Johnson@Sun.COM /* if we don't have any segments to map, we're done */
12227756SMark.Johnson@Sun.COM if ((req->operation == BLKIF_OP_WRITE_BARRIER) ||
12237756SMark.Johnson@Sun.COM (req->operation == BLKIF_OP_FLUSH_DISKCACHE) ||
12247756SMark.Johnson@Sun.COM (req->nr_segments == 0)) {
12257756SMark.Johnson@Sun.COM return (DDI_SUCCESS);
12267756SMark.Johnson@Sun.COM }
12277756SMark.Johnson@Sun.COM
12287756SMark.Johnson@Sun.COM /* get the apps gref address */
12297756SMark.Johnson@Sun.COM uaddr = XPVTAP_GREF_REQADDR(state->bt_map.um_guest_pages, *uid);
12307756SMark.Johnson@Sun.COM
12317756SMark.Johnson@Sun.COM AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
12327756SMark.Johnson@Sun.COM seg = as_findseg(as, state->bt_map.um_guest_pages, 0);
12337756SMark.Johnson@Sun.COM if ((seg == NULL) || ((uaddr + mmu_ptob(req->nr_segments)) >
12347756SMark.Johnson@Sun.COM (seg->s_base + seg->s_size))) {
12357756SMark.Johnson@Sun.COM AS_LOCK_EXIT(as, &as->a_lock);
12367756SMark.Johnson@Sun.COM return (DDI_FAILURE);
12377756SMark.Johnson@Sun.COM }
12387756SMark.Johnson@Sun.COM
12397756SMark.Johnson@Sun.COM /* if we are reading from disk, we are writing into memory */
12407756SMark.Johnson@Sun.COM flags = 0;
12417756SMark.Johnson@Sun.COM if (req->operation == BLKIF_OP_READ) {
12427756SMark.Johnson@Sun.COM flags |= SEGMF_GREF_WR;
12437756SMark.Johnson@Sun.COM }
12447756SMark.Johnson@Sun.COM
12457756SMark.Johnson@Sun.COM /* Load the grefs into seg_mf */
12467756SMark.Johnson@Sun.COM for (i = 0; i < req->nr_segments; i++) {
12477756SMark.Johnson@Sun.COM gref[i] = req->seg[i].gref;
12487756SMark.Johnson@Sun.COM }
12497756SMark.Johnson@Sun.COM (void) segmf_add_grefs(seg, uaddr, flags, gref, req->nr_segments,
12507756SMark.Johnson@Sun.COM domid);
12517756SMark.Johnson@Sun.COM
12527756SMark.Johnson@Sun.COM AS_LOCK_EXIT(as, &as->a_lock);
12537756SMark.Johnson@Sun.COM
12547756SMark.Johnson@Sun.COM return (DDI_SUCCESS);
12557756SMark.Johnson@Sun.COM }
12567756SMark.Johnson@Sun.COM
12577756SMark.Johnson@Sun.COM
12587756SMark.Johnson@Sun.COM /*
12597756SMark.Johnson@Sun.COM * xpvtap_user_request_push()
12607756SMark.Johnson@Sun.COM */
12617756SMark.Johnson@Sun.COM static int
xpvtap_user_request_push(xpvtap_state_t * state,blkif_request_t * req,uint_t uid)12627756SMark.Johnson@Sun.COM xpvtap_user_request_push(xpvtap_state_t *state, blkif_request_t *req,
12637756SMark.Johnson@Sun.COM uint_t uid)
12647756SMark.Johnson@Sun.COM {
12657756SMark.Johnson@Sun.COM blkif_request_t *outstanding_req;
12667756SMark.Johnson@Sun.COM blkif_front_ring_t *uring;
12677756SMark.Johnson@Sun.COM blkif_request_t *target;
12687756SMark.Johnson@Sun.COM xpvtap_user_map_t *map;
12697756SMark.Johnson@Sun.COM
12707756SMark.Johnson@Sun.COM
12717756SMark.Johnson@Sun.COM uring = &state->bt_user_ring.ur_ring;
12727756SMark.Johnson@Sun.COM map = &state->bt_map;
12737756SMark.Johnson@Sun.COM
12747756SMark.Johnson@Sun.COM target = RING_GET_REQUEST(uring, uring->req_prod_pvt);
12757756SMark.Johnson@Sun.COM
12767756SMark.Johnson@Sun.COM /*
12777756SMark.Johnson@Sun.COM * Save request from the frontend. used for ID mapping and unmap
12787756SMark.Johnson@Sun.COM * on response/cleanup
12797756SMark.Johnson@Sun.COM */
12807756SMark.Johnson@Sun.COM outstanding_req = &map->um_outstanding_reqs[uid];
12817756SMark.Johnson@Sun.COM bcopy(req, outstanding_req, sizeof (*outstanding_req));
12827756SMark.Johnson@Sun.COM
12837756SMark.Johnson@Sun.COM /* put the request on the user ring */
12847756SMark.Johnson@Sun.COM bcopy(req, target, sizeof (*req));
12857756SMark.Johnson@Sun.COM target->id = (uint64_t)uid;
12867756SMark.Johnson@Sun.COM uring->req_prod_pvt++;
12877756SMark.Johnson@Sun.COM
12887756SMark.Johnson@Sun.COM pollwakeup(&state->bt_pollhead, POLLIN | POLLRDNORM);
12897756SMark.Johnson@Sun.COM
12907756SMark.Johnson@Sun.COM return (DDI_SUCCESS);
12917756SMark.Johnson@Sun.COM }
12927756SMark.Johnson@Sun.COM
12937756SMark.Johnson@Sun.COM
12947756SMark.Johnson@Sun.COM static void
xpvtap_user_request_unmap(xpvtap_state_t * state,uint_t uid)12957756SMark.Johnson@Sun.COM xpvtap_user_request_unmap(xpvtap_state_t *state, uint_t uid)
12967756SMark.Johnson@Sun.COM {
12977756SMark.Johnson@Sun.COM blkif_request_t *req;
12987756SMark.Johnson@Sun.COM struct seg *seg;
12997756SMark.Johnson@Sun.COM struct as *as;
13007756SMark.Johnson@Sun.COM caddr_t uaddr;
13017756SMark.Johnson@Sun.COM int e;
13027756SMark.Johnson@Sun.COM
13037756SMark.Johnson@Sun.COM
13047756SMark.Johnson@Sun.COM as = state->bt_map.um_as;
13057756SMark.Johnson@Sun.COM if (as == NULL) {
13067756SMark.Johnson@Sun.COM return;
13077756SMark.Johnson@Sun.COM }
13087756SMark.Johnson@Sun.COM
13097756SMark.Johnson@Sun.COM /* get a copy of the original request */
13107756SMark.Johnson@Sun.COM req = &state->bt_map.um_outstanding_reqs[uid];
13117756SMark.Johnson@Sun.COM
13127756SMark.Johnson@Sun.COM /* unmap the grefs for this request */
13137756SMark.Johnson@Sun.COM if ((req->operation != BLKIF_OP_WRITE_BARRIER) &&
13147756SMark.Johnson@Sun.COM (req->operation != BLKIF_OP_FLUSH_DISKCACHE) &&
13157756SMark.Johnson@Sun.COM (req->nr_segments != 0)) {
13167756SMark.Johnson@Sun.COM uaddr = XPVTAP_GREF_REQADDR(state->bt_map.um_guest_pages, uid);
13177756SMark.Johnson@Sun.COM AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
13187756SMark.Johnson@Sun.COM seg = as_findseg(as, state->bt_map.um_guest_pages, 0);
13197756SMark.Johnson@Sun.COM if ((seg == NULL) || ((uaddr + mmu_ptob(req->nr_segments)) >
13207756SMark.Johnson@Sun.COM (seg->s_base + seg->s_size))) {
13217756SMark.Johnson@Sun.COM AS_LOCK_EXIT(as, &as->a_lock);
13227756SMark.Johnson@Sun.COM xpvtap_rs_free(state->bt_map.um_rs, uid);
13237756SMark.Johnson@Sun.COM return;
13247756SMark.Johnson@Sun.COM }
13257756SMark.Johnson@Sun.COM
13267756SMark.Johnson@Sun.COM e = segmf_release_grefs(seg, uaddr, req->nr_segments);
13277756SMark.Johnson@Sun.COM if (e != 0) {
13287756SMark.Johnson@Sun.COM cmn_err(CE_WARN, "unable to release grefs");
13297756SMark.Johnson@Sun.COM }
13307756SMark.Johnson@Sun.COM
13317756SMark.Johnson@Sun.COM AS_LOCK_EXIT(as, &as->a_lock);
13327756SMark.Johnson@Sun.COM }
13337756SMark.Johnson@Sun.COM
13347756SMark.Johnson@Sun.COM /* free up the user ring id */
13357756SMark.Johnson@Sun.COM xpvtap_rs_free(state->bt_map.um_rs, uid);
13367756SMark.Johnson@Sun.COM }
13377756SMark.Johnson@Sun.COM
13387756SMark.Johnson@Sun.COM
13397756SMark.Johnson@Sun.COM static int
xpvtap_user_response_get(xpvtap_state_t * state,blkif_response_t * resp,uint_t * uid)13407756SMark.Johnson@Sun.COM xpvtap_user_response_get(xpvtap_state_t *state, blkif_response_t *resp,
13417756SMark.Johnson@Sun.COM uint_t *uid)
13427756SMark.Johnson@Sun.COM {
13437756SMark.Johnson@Sun.COM blkif_front_ring_t *uring;
13447756SMark.Johnson@Sun.COM blkif_response_t *target;
13457756SMark.Johnson@Sun.COM
13467756SMark.Johnson@Sun.COM
13477756SMark.Johnson@Sun.COM uring = &state->bt_user_ring.ur_ring;
13487756SMark.Johnson@Sun.COM
13497756SMark.Johnson@Sun.COM if (!RING_HAS_UNCONSUMED_RESPONSES(uring)) {
13507756SMark.Johnson@Sun.COM return (B_FALSE);
13517756SMark.Johnson@Sun.COM }
13527756SMark.Johnson@Sun.COM
13537756SMark.Johnson@Sun.COM target = NULL;
13547756SMark.Johnson@Sun.COM target = RING_GET_RESPONSE(uring, uring->rsp_cons);
13557756SMark.Johnson@Sun.COM if (target == NULL) {
13567756SMark.Johnson@Sun.COM return (B_FALSE);
13577756SMark.Johnson@Sun.COM }
13587756SMark.Johnson@Sun.COM
13597756SMark.Johnson@Sun.COM /* copy out the user app response */
13607756SMark.Johnson@Sun.COM bcopy(target, resp, sizeof (*resp));
13617756SMark.Johnson@Sun.COM uring->rsp_cons++;
13627756SMark.Johnson@Sun.COM
13637756SMark.Johnson@Sun.COM /* restore the quests id from the original request */
13647756SMark.Johnson@Sun.COM *uid = (uint_t)resp->id;
13657756SMark.Johnson@Sun.COM resp->id = state->bt_map.um_outstanding_reqs[*uid].id;
13667756SMark.Johnson@Sun.COM
13677756SMark.Johnson@Sun.COM return (B_TRUE);
13687756SMark.Johnson@Sun.COM }
13697756SMark.Johnson@Sun.COM
13707756SMark.Johnson@Sun.COM
13717756SMark.Johnson@Sun.COM /*
13727756SMark.Johnson@Sun.COM * xpvtap_user_app_stop()
13737756SMark.Johnson@Sun.COM */
xpvtap_user_app_stop(caddr_t arg)13747756SMark.Johnson@Sun.COM static void xpvtap_user_app_stop(caddr_t arg)
13757756SMark.Johnson@Sun.COM {
13767756SMark.Johnson@Sun.COM xpvtap_state_t *state;
13777756SMark.Johnson@Sun.COM clock_t rc;
13787756SMark.Johnson@Sun.COM
13797756SMark.Johnson@Sun.COM state = (xpvtap_state_t *)arg;
13807756SMark.Johnson@Sun.COM
13817756SMark.Johnson@Sun.COM /*
13827756SMark.Johnson@Sun.COM * Give the app 10 secs to exit. If it doesn't exit, it's not a serious
13837756SMark.Johnson@Sun.COM * problem, we just won't auto-detach the driver.
13847756SMark.Johnson@Sun.COM */
13857756SMark.Johnson@Sun.COM mutex_enter(&state->bt_open.bo_mutex);
13867756SMark.Johnson@Sun.COM if (state->bt_open.bo_opened) {
1387*11066Srafael.vanoni@sun.com rc = cv_reltimedwait(&state->bt_open.bo_exit_cv,
1388*11066Srafael.vanoni@sun.com &state->bt_open.bo_mutex, drv_usectohz(10000000),
1389*11066Srafael.vanoni@sun.com TR_CLOCK_TICK);
13907756SMark.Johnson@Sun.COM if (rc <= 0) {
13917756SMark.Johnson@Sun.COM cmn_err(CE_NOTE, "!user process still has driver open, "
13927756SMark.Johnson@Sun.COM "deferring detach\n");
13937756SMark.Johnson@Sun.COM }
13947756SMark.Johnson@Sun.COM }
13957756SMark.Johnson@Sun.COM mutex_exit(&state->bt_open.bo_mutex);
13967756SMark.Johnson@Sun.COM }
13977756SMark.Johnson@Sun.COM
13987756SMark.Johnson@Sun.COM
13997756SMark.Johnson@Sun.COM /*
14007756SMark.Johnson@Sun.COM * xpvtap_rs_init()
14017756SMark.Johnson@Sun.COM * Initialize the resource structure. init() returns a handle to be used
14027756SMark.Johnson@Sun.COM * for the rest of the resource functions. This code is written assuming
14037756SMark.Johnson@Sun.COM * that min_val will be close to 0. Therefore, we will allocate the free
14047756SMark.Johnson@Sun.COM * buffer only taking max_val into account.
14057756SMark.Johnson@Sun.COM */
14067756SMark.Johnson@Sun.COM static void
xpvtap_rs_init(uint_t min_val,uint_t max_val,xpvtap_rs_hdl_t * handle)14077756SMark.Johnson@Sun.COM xpvtap_rs_init(uint_t min_val, uint_t max_val, xpvtap_rs_hdl_t *handle)
14087756SMark.Johnson@Sun.COM {
14097756SMark.Johnson@Sun.COM xpvtap_rs_t *rstruct;
14107756SMark.Johnson@Sun.COM uint_t array_size;
14117756SMark.Johnson@Sun.COM uint_t index;
14127756SMark.Johnson@Sun.COM
14137756SMark.Johnson@Sun.COM
14147756SMark.Johnson@Sun.COM ASSERT(handle != NULL);
14157756SMark.Johnson@Sun.COM ASSERT(min_val < max_val);
14167756SMark.Johnson@Sun.COM
14177756SMark.Johnson@Sun.COM /* alloc space for resource structure */
14187756SMark.Johnson@Sun.COM rstruct = kmem_alloc(sizeof (xpvtap_rs_t), KM_SLEEP);
14197756SMark.Johnson@Sun.COM
14207756SMark.Johnson@Sun.COM /*
14217756SMark.Johnson@Sun.COM * Test to see if the max value is 64-bit aligned. If so, we don't need
14227756SMark.Johnson@Sun.COM * to allocate an extra 64-bit word. alloc space for free buffer
14237756SMark.Johnson@Sun.COM * (8 bytes per uint64_t).
14247756SMark.Johnson@Sun.COM */
14257756SMark.Johnson@Sun.COM if ((max_val & 0x3F) == 0) {
14267756SMark.Johnson@Sun.COM rstruct->rs_free_size = (max_val >> 6) * 8;
14277756SMark.Johnson@Sun.COM } else {
14287756SMark.Johnson@Sun.COM rstruct->rs_free_size = ((max_val >> 6) + 1) * 8;
14297756SMark.Johnson@Sun.COM }
14307756SMark.Johnson@Sun.COM rstruct->rs_free = kmem_alloc(rstruct->rs_free_size, KM_SLEEP);
14317756SMark.Johnson@Sun.COM
14327756SMark.Johnson@Sun.COM /* Initialize resource structure */
14337756SMark.Johnson@Sun.COM rstruct->rs_min = min_val;
14347756SMark.Johnson@Sun.COM rstruct->rs_last = min_val;
14357756SMark.Johnson@Sun.COM rstruct->rs_max = max_val;
14367756SMark.Johnson@Sun.COM mutex_init(&rstruct->rs_mutex, NULL, MUTEX_DRIVER, NULL);
14377756SMark.Johnson@Sun.COM rstruct->rs_flushing = B_FALSE;
14387756SMark.Johnson@Sun.COM
14397756SMark.Johnson@Sun.COM /* Mark all resources as free */
14407756SMark.Johnson@Sun.COM array_size = rstruct->rs_free_size >> 3;
14417756SMark.Johnson@Sun.COM for (index = 0; index < array_size; index++) {
14427756SMark.Johnson@Sun.COM rstruct->rs_free[index] = (uint64_t)0xFFFFFFFFFFFFFFFF;
14437756SMark.Johnson@Sun.COM }
14447756SMark.Johnson@Sun.COM
14457756SMark.Johnson@Sun.COM /* setup handle which is returned from this function */
14467756SMark.Johnson@Sun.COM *handle = rstruct;
14477756SMark.Johnson@Sun.COM }
14487756SMark.Johnson@Sun.COM
14497756SMark.Johnson@Sun.COM
14507756SMark.Johnson@Sun.COM /*
14517756SMark.Johnson@Sun.COM * xpvtap_rs_fini()
14527756SMark.Johnson@Sun.COM * Frees up the space allocated in init(). Notice that a pointer to the
14537756SMark.Johnson@Sun.COM * handle is used for the parameter. fini() will set the handle to NULL
14547756SMark.Johnson@Sun.COM * before returning.
14557756SMark.Johnson@Sun.COM */
14567756SMark.Johnson@Sun.COM static void
xpvtap_rs_fini(xpvtap_rs_hdl_t * handle)14577756SMark.Johnson@Sun.COM xpvtap_rs_fini(xpvtap_rs_hdl_t *handle)
14587756SMark.Johnson@Sun.COM {
14597756SMark.Johnson@Sun.COM xpvtap_rs_t *rstruct;
14607756SMark.Johnson@Sun.COM
14617756SMark.Johnson@Sun.COM
14627756SMark.Johnson@Sun.COM ASSERT(handle != NULL);
14637756SMark.Johnson@Sun.COM
14647756SMark.Johnson@Sun.COM rstruct = (xpvtap_rs_t *)*handle;
14657756SMark.Johnson@Sun.COM
14667756SMark.Johnson@Sun.COM mutex_destroy(&rstruct->rs_mutex);
14677756SMark.Johnson@Sun.COM kmem_free(rstruct->rs_free, rstruct->rs_free_size);
14687756SMark.Johnson@Sun.COM kmem_free(rstruct, sizeof (xpvtap_rs_t));
14697756SMark.Johnson@Sun.COM
14707756SMark.Johnson@Sun.COM /* set handle to null. This helps catch bugs. */
14717756SMark.Johnson@Sun.COM *handle = NULL;
14727756SMark.Johnson@Sun.COM }
14737756SMark.Johnson@Sun.COM
14747756SMark.Johnson@Sun.COM
14757756SMark.Johnson@Sun.COM /*
14767756SMark.Johnson@Sun.COM * xpvtap_rs_alloc()
14777756SMark.Johnson@Sun.COM * alloc a resource. If alloc fails, we are out of resources.
14787756SMark.Johnson@Sun.COM */
14797756SMark.Johnson@Sun.COM static int
xpvtap_rs_alloc(xpvtap_rs_hdl_t handle,uint_t * resource)14807756SMark.Johnson@Sun.COM xpvtap_rs_alloc(xpvtap_rs_hdl_t handle, uint_t *resource)
14817756SMark.Johnson@Sun.COM {
14827756SMark.Johnson@Sun.COM xpvtap_rs_t *rstruct;
14837756SMark.Johnson@Sun.COM uint_t array_idx;
14847756SMark.Johnson@Sun.COM uint64_t free;
14857756SMark.Johnson@Sun.COM uint_t index;
14867756SMark.Johnson@Sun.COM uint_t last;
14877756SMark.Johnson@Sun.COM uint_t min;
14887756SMark.Johnson@Sun.COM uint_t max;
14897756SMark.Johnson@Sun.COM
14907756SMark.Johnson@Sun.COM
14917756SMark.Johnson@Sun.COM ASSERT(handle != NULL);
14927756SMark.Johnson@Sun.COM ASSERT(resource != NULL);
14937756SMark.Johnson@Sun.COM
14947756SMark.Johnson@Sun.COM rstruct = (xpvtap_rs_t *)handle;
14957756SMark.Johnson@Sun.COM
14967756SMark.Johnson@Sun.COM mutex_enter(&rstruct->rs_mutex);
14977756SMark.Johnson@Sun.COM min = rstruct->rs_min;
14987756SMark.Johnson@Sun.COM max = rstruct->rs_max;
14997756SMark.Johnson@Sun.COM
15007756SMark.Johnson@Sun.COM /*
15017756SMark.Johnson@Sun.COM * Find a free resource. This will return out of the loop once it finds
15027756SMark.Johnson@Sun.COM * a free resource. There are a total of 'max'-'min'+1 resources.
15037756SMark.Johnson@Sun.COM * Performs a round robin allocation.
15047756SMark.Johnson@Sun.COM */
15057756SMark.Johnson@Sun.COM for (index = min; index <= max; index++) {
15067756SMark.Johnson@Sun.COM
15077756SMark.Johnson@Sun.COM array_idx = rstruct->rs_last >> 6;
15087756SMark.Johnson@Sun.COM free = rstruct->rs_free[array_idx];
15097756SMark.Johnson@Sun.COM last = rstruct->rs_last & 0x3F;
15107756SMark.Johnson@Sun.COM
15117756SMark.Johnson@Sun.COM /* if the next resource to check is free */
15127756SMark.Johnson@Sun.COM if ((free & ((uint64_t)1 << last)) != 0) {
15137756SMark.Johnson@Sun.COM /* we are using this resource */
15147756SMark.Johnson@Sun.COM *resource = rstruct->rs_last;
15157756SMark.Johnson@Sun.COM
15167756SMark.Johnson@Sun.COM /* take it out of the free list */
15177756SMark.Johnson@Sun.COM rstruct->rs_free[array_idx] &= ~((uint64_t)1 << last);
15187756SMark.Johnson@Sun.COM
15197756SMark.Johnson@Sun.COM /*
15207756SMark.Johnson@Sun.COM * increment the last count so we start checking the
15217756SMark.Johnson@Sun.COM * next resource on the next alloc(). Note the rollover
15227756SMark.Johnson@Sun.COM * at 'max'+1.
15237756SMark.Johnson@Sun.COM */
15247756SMark.Johnson@Sun.COM rstruct->rs_last++;
15257756SMark.Johnson@Sun.COM if (rstruct->rs_last > max) {
15267756SMark.Johnson@Sun.COM rstruct->rs_last = rstruct->rs_min;
15277756SMark.Johnson@Sun.COM }
15287756SMark.Johnson@Sun.COM
15297756SMark.Johnson@Sun.COM /* unlock the resource structure */
15307756SMark.Johnson@Sun.COM mutex_exit(&rstruct->rs_mutex);
15317756SMark.Johnson@Sun.COM
15327756SMark.Johnson@Sun.COM return (DDI_SUCCESS);
15337756SMark.Johnson@Sun.COM }
15347756SMark.Johnson@Sun.COM
15357756SMark.Johnson@Sun.COM /*
15367756SMark.Johnson@Sun.COM * This resource is not free, lets go to the next one. Note the
15377756SMark.Johnson@Sun.COM * rollover at 'max'.
15387756SMark.Johnson@Sun.COM */
15397756SMark.Johnson@Sun.COM rstruct->rs_last++;
15407756SMark.Johnson@Sun.COM if (rstruct->rs_last > max) {
15417756SMark.Johnson@Sun.COM rstruct->rs_last = rstruct->rs_min;
15427756SMark.Johnson@Sun.COM }
15437756SMark.Johnson@Sun.COM }
15447756SMark.Johnson@Sun.COM
15457756SMark.Johnson@Sun.COM mutex_exit(&rstruct->rs_mutex);
15467756SMark.Johnson@Sun.COM
15477756SMark.Johnson@Sun.COM return (DDI_FAILURE);
15487756SMark.Johnson@Sun.COM }
15497756SMark.Johnson@Sun.COM
15507756SMark.Johnson@Sun.COM
15517756SMark.Johnson@Sun.COM /*
15527756SMark.Johnson@Sun.COM * xpvtap_rs_free()
15537756SMark.Johnson@Sun.COM * Free the previously alloc'd resource. Once a resource has been free'd,
15547756SMark.Johnson@Sun.COM * it can be used again when alloc is called.
15557756SMark.Johnson@Sun.COM */
15567756SMark.Johnson@Sun.COM static void
xpvtap_rs_free(xpvtap_rs_hdl_t handle,uint_t resource)15577756SMark.Johnson@Sun.COM xpvtap_rs_free(xpvtap_rs_hdl_t handle, uint_t resource)
15587756SMark.Johnson@Sun.COM {
15597756SMark.Johnson@Sun.COM xpvtap_rs_t *rstruct;
15607756SMark.Johnson@Sun.COM uint_t array_idx;
15617756SMark.Johnson@Sun.COM uint_t offset;
15627756SMark.Johnson@Sun.COM
15637756SMark.Johnson@Sun.COM
15647756SMark.Johnson@Sun.COM ASSERT(handle != NULL);
15657756SMark.Johnson@Sun.COM
15667756SMark.Johnson@Sun.COM rstruct = (xpvtap_rs_t *)handle;
15677756SMark.Johnson@Sun.COM ASSERT(resource >= rstruct->rs_min);
15687756SMark.Johnson@Sun.COM ASSERT(resource <= rstruct->rs_max);
15697756SMark.Johnson@Sun.COM
15707756SMark.Johnson@Sun.COM if (!rstruct->rs_flushing) {
15717756SMark.Johnson@Sun.COM mutex_enter(&rstruct->rs_mutex);
15727756SMark.Johnson@Sun.COM }
15737756SMark.Johnson@Sun.COM
15747756SMark.Johnson@Sun.COM /* Put the resource back in the free list */
15757756SMark.Johnson@Sun.COM array_idx = resource >> 6;
15767756SMark.Johnson@Sun.COM offset = resource & 0x3F;
15777756SMark.Johnson@Sun.COM rstruct->rs_free[array_idx] |= ((uint64_t)1 << offset);
15787756SMark.Johnson@Sun.COM
15797756SMark.Johnson@Sun.COM if (!rstruct->rs_flushing) {
15807756SMark.Johnson@Sun.COM mutex_exit(&rstruct->rs_mutex);
15817756SMark.Johnson@Sun.COM }
15827756SMark.Johnson@Sun.COM }
15837756SMark.Johnson@Sun.COM
15847756SMark.Johnson@Sun.COM
15857756SMark.Johnson@Sun.COM /*
15867756SMark.Johnson@Sun.COM * xpvtap_rs_flush()
15877756SMark.Johnson@Sun.COM */
15887756SMark.Johnson@Sun.COM static void
xpvtap_rs_flush(xpvtap_rs_hdl_t handle,xpvtap_rs_cleanup_t callback,void * arg)15897756SMark.Johnson@Sun.COM xpvtap_rs_flush(xpvtap_rs_hdl_t handle, xpvtap_rs_cleanup_t callback,
15907756SMark.Johnson@Sun.COM void *arg)
15917756SMark.Johnson@Sun.COM {
15927756SMark.Johnson@Sun.COM xpvtap_rs_t *rstruct;
15937756SMark.Johnson@Sun.COM uint_t array_idx;
15947756SMark.Johnson@Sun.COM uint64_t free;
15957756SMark.Johnson@Sun.COM uint_t index;
15967756SMark.Johnson@Sun.COM uint_t last;
15977756SMark.Johnson@Sun.COM uint_t min;
15987756SMark.Johnson@Sun.COM uint_t max;
15997756SMark.Johnson@Sun.COM
16007756SMark.Johnson@Sun.COM
16017756SMark.Johnson@Sun.COM ASSERT(handle != NULL);
16027756SMark.Johnson@Sun.COM
16037756SMark.Johnson@Sun.COM rstruct = (xpvtap_rs_t *)handle;
16047756SMark.Johnson@Sun.COM
16057756SMark.Johnson@Sun.COM mutex_enter(&rstruct->rs_mutex);
16067756SMark.Johnson@Sun.COM min = rstruct->rs_min;
16077756SMark.Johnson@Sun.COM max = rstruct->rs_max;
16087756SMark.Johnson@Sun.COM
16097756SMark.Johnson@Sun.COM rstruct->rs_flushing = B_TRUE;
16107756SMark.Johnson@Sun.COM
16117756SMark.Johnson@Sun.COM /*
16127756SMark.Johnson@Sun.COM * for all resources not free, call the callback routine to clean it
16137756SMark.Johnson@Sun.COM * up.
16147756SMark.Johnson@Sun.COM */
16157756SMark.Johnson@Sun.COM for (index = min; index <= max; index++) {
16167756SMark.Johnson@Sun.COM
16177756SMark.Johnson@Sun.COM array_idx = rstruct->rs_last >> 6;
16187756SMark.Johnson@Sun.COM free = rstruct->rs_free[array_idx];
16197756SMark.Johnson@Sun.COM last = rstruct->rs_last & 0x3F;
16207756SMark.Johnson@Sun.COM
16217756SMark.Johnson@Sun.COM /* if the next resource to check is not free */
16227756SMark.Johnson@Sun.COM if ((free & ((uint64_t)1 << last)) == 0) {
16237756SMark.Johnson@Sun.COM /* call the callback to cleanup */
16247756SMark.Johnson@Sun.COM (*callback)(arg, rstruct->rs_last);
16257756SMark.Johnson@Sun.COM
16267756SMark.Johnson@Sun.COM /* put it back in the free list */
16277756SMark.Johnson@Sun.COM rstruct->rs_free[array_idx] |= ((uint64_t)1 << last);
16287756SMark.Johnson@Sun.COM }
16297756SMark.Johnson@Sun.COM
16307756SMark.Johnson@Sun.COM /* go to the next one. Note the rollover at 'max' */
16317756SMark.Johnson@Sun.COM rstruct->rs_last++;
16327756SMark.Johnson@Sun.COM if (rstruct->rs_last > max) {
16337756SMark.Johnson@Sun.COM rstruct->rs_last = rstruct->rs_min;
16347756SMark.Johnson@Sun.COM }
16357756SMark.Johnson@Sun.COM }
16367756SMark.Johnson@Sun.COM
16377756SMark.Johnson@Sun.COM mutex_exit(&rstruct->rs_mutex);
16387756SMark.Johnson@Sun.COM }
1639