xref: /illumos-gate/usr/src/uts/common/xen/io/blk_common.c (revision 62dcc6f3)
17eea693dSMark Johnson /*
27eea693dSMark Johnson  * CDDL HEADER START
37eea693dSMark Johnson  *
47eea693dSMark Johnson  * The contents of this file are subject to the terms of the
57eea693dSMark Johnson  * Common Development and Distribution License (the "License").
67eea693dSMark Johnson  * You may not use this file except in compliance with the License.
77eea693dSMark Johnson  *
87eea693dSMark Johnson  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97eea693dSMark Johnson  * or http://www.opensolaris.org/os/licensing.
107eea693dSMark Johnson  * See the License for the specific language governing permissions
117eea693dSMark Johnson  * and limitations under the License.
127eea693dSMark Johnson  *
137eea693dSMark Johnson  * When distributing Covered Code, include this CDDL HEADER in each
147eea693dSMark Johnson  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157eea693dSMark Johnson  * If applicable, add the following below this CDDL HEADER, with the
167eea693dSMark Johnson  * fields enclosed by brackets "[]" replaced with your own identifying
177eea693dSMark Johnson  * information: Portions Copyright [yyyy] [name of copyright owner]
187eea693dSMark Johnson  *
197eea693dSMark Johnson  * CDDL HEADER END
207eea693dSMark Johnson  */
217eea693dSMark Johnson 
227eea693dSMark Johnson /*
23349b53ddSStuart Maybee  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247eea693dSMark Johnson  * Use is subject to license terms.
257eea693dSMark Johnson  */
267eea693dSMark Johnson 
277eea693dSMark Johnson 
287eea693dSMark Johnson #include <sys/errno.h>
297eea693dSMark Johnson #include <sys/types.h>
307eea693dSMark Johnson #include <sys/conf.h>
317eea693dSMark Johnson #include <sys/kmem.h>
327eea693dSMark Johnson #include <sys/ddi.h>
337eea693dSMark Johnson #include <sys/stat.h>
347eea693dSMark Johnson #include <sys/sunddi.h>
357eea693dSMark Johnson #include <sys/file.h>
367eea693dSMark Johnson #include <sys/open.h>
377eea693dSMark Johnson #include <sys/modctl.h>
387eea693dSMark Johnson #include <sys/ddi_impldefs.h>
397eea693dSMark Johnson #include <sys/sysmacros.h>
407eea693dSMark Johnson #include <sys/ddidevmap.h>
417eea693dSMark Johnson #include <sys/xendev.h>
427eea693dSMark Johnson #include <public/io/protocols.h>
437eea693dSMark Johnson #include <xen/io/blkif_impl.h>
447eea693dSMark Johnson 
457eea693dSMark Johnson #include "blk_common.h"
467eea693dSMark Johnson 
477eea693dSMark Johnson 
487eea693dSMark Johnson /* blk interface status */
497eea693dSMark Johnson enum blk_if_state {
507eea693dSMark Johnson 	/*
517eea693dSMark Johnson 	 * initial state
527eea693dSMark Johnson 	 */
537eea693dSMark Johnson 	BLK_IF_UNKNOWN = 0,
547eea693dSMark Johnson 	/*
557eea693dSMark Johnson 	 * frontend xenbus state changed to XenbusStateConnected,
567eea693dSMark Johnson 	 * we finally connect
577eea693dSMark Johnson 	 */
587eea693dSMark Johnson 	BLK_IF_CONNECTED,
597eea693dSMark Johnson 	/*
607eea693dSMark Johnson 	 * frontend xenbus state changed to XenbusStateClosed,
617eea693dSMark Johnson 	 * interface disconnected
627eea693dSMark Johnson 	 */
637eea693dSMark Johnson 	BLK_IF_DISCONNECTED
647eea693dSMark Johnson };
657eea693dSMark Johnson 
667eea693dSMark Johnson /* backend device status */
677eea693dSMark Johnson enum blk_be_state {
687eea693dSMark Johnson 	/* initial state */
697eea693dSMark Johnson 	BLK_BE_UNKNOWN = 0,
707eea693dSMark Johnson 	/* backend device is ready (hotplug script finishes successfully) */
717eea693dSMark Johnson 	BLK_BE_READY
727eea693dSMark Johnson };
737eea693dSMark Johnson 
747eea693dSMark Johnson /* frontend status */
757eea693dSMark Johnson enum blk_fe_state {
767eea693dSMark Johnson 	/* initial state */
777eea693dSMark Johnson 	BLK_FE_UNKNOWN = 0,
787eea693dSMark Johnson 	/*
797eea693dSMark Johnson 	 * frontend's xenbus state has changed to
807eea693dSMark Johnson 	 * XenbusStateInitialised, is ready for connecting
817eea693dSMark Johnson 	 */
827eea693dSMark Johnson 	BLK_FE_READY
837eea693dSMark Johnson };
847eea693dSMark Johnson 
857eea693dSMark Johnson typedef struct blk_ring_state_s {
867eea693dSMark Johnson 	kmutex_t		rs_mutex;
877eea693dSMark Johnson 	boolean_t		rs_sleeping_on_ring;
887eea693dSMark Johnson 	boolean_t		rs_ring_up;
897eea693dSMark Johnson 	kcondvar_t		rs_cv;
907eea693dSMark Johnson } blk_ring_state_t;
917eea693dSMark Johnson 
927eea693dSMark Johnson /* Disk Statistics */
937eea693dSMark Johnson static char *blk_stats[] = {
947eea693dSMark Johnson 	"rd_reqs",
957eea693dSMark Johnson 	"wr_reqs",
967eea693dSMark Johnson 	"br_reqs",
977eea693dSMark Johnson 	"fl_reqs",
987eea693dSMark Johnson 	"oo_reqs"
997eea693dSMark Johnson };
1007eea693dSMark Johnson 
1017eea693dSMark Johnson typedef struct blk_stats_s {
1027eea693dSMark Johnson 	uint64_t bs_req_reads;
1037eea693dSMark Johnson 	uint64_t bs_req_writes;
1047eea693dSMark Johnson 	uint64_t bs_req_barriers;
1057eea693dSMark Johnson 	uint64_t bs_req_flushes;
1067eea693dSMark Johnson } blk_stats_t;
1077eea693dSMark Johnson 
1087eea693dSMark Johnson struct blk_ring_s {
1097eea693dSMark Johnson 	kmutex_t		ri_mutex;
1107eea693dSMark Johnson 	dev_info_t		*ri_dip;
1117eea693dSMark Johnson 
1127eea693dSMark Johnson 	kstat_t			*ri_kstats;
1137eea693dSMark Johnson 	blk_stats_t		ri_stats;
1147eea693dSMark Johnson 
1157eea693dSMark Johnson 	blk_intr_t		ri_intr;
1167eea693dSMark Johnson 	caddr_t			ri_intr_arg;
1177eea693dSMark Johnson 	blk_ring_cb_t		ri_ringup;
1187eea693dSMark Johnson 	caddr_t			ri_ringup_arg;
1197eea693dSMark Johnson 	blk_ring_cb_t		ri_ringdown;
1207eea693dSMark Johnson 	caddr_t			ri_ringdown_arg;
1217eea693dSMark Johnson 
1227eea693dSMark Johnson 	/* blk interface, backend, and frontend status */
1237eea693dSMark Johnson 	enum blk_if_state	ri_if_status;
1247eea693dSMark Johnson 	enum blk_be_state	ri_be_status;
1257eea693dSMark Johnson 	enum blk_fe_state	ri_fe_status;
1267eea693dSMark Johnson 
1277eea693dSMark Johnson 	domid_t			ri_fe;
1287eea693dSMark Johnson 
1297eea693dSMark Johnson 	enum blkif_protocol	ri_protocol;
1307eea693dSMark Johnson 	size_t			ri_nentry;
1317eea693dSMark Johnson 	size_t			ri_entrysize;
1327eea693dSMark Johnson 
1337eea693dSMark Johnson 	xendev_ring_t		*ri_ring;
1347eea693dSMark Johnson 	blk_ring_state_t	ri_state;
1357eea693dSMark Johnson };
1367eea693dSMark Johnson 
1377eea693dSMark Johnson 
1387eea693dSMark Johnson static void blk_oe_state_change(dev_info_t *dip, ddi_eventcookie_t id,
1397eea693dSMark Johnson     void *arg, void *impl_data);
1407eea693dSMark Johnson static void blk_hp_state_change(dev_info_t *dip, ddi_eventcookie_t id,
1417eea693dSMark Johnson     void *arg, void *impl_data);
1427eea693dSMark Johnson static int blk_check_state_transition(blk_ring_t ring, XenbusState oestate);
1437eea693dSMark Johnson static int blk_start_connect(blk_ring_t ring);
1447eea693dSMark Johnson static void blk_start_disconnect(blk_ring_t ring);
1457eea693dSMark Johnson static void blk_ring_close(blk_ring_t ring);
1467eea693dSMark Johnson static int blk_bindto_frontend(blk_ring_t ring);
1477eea693dSMark Johnson static void blk_unbindfrom_frontend(blk_ring_t ring);
1487eea693dSMark Johnson static uint_t blk_intr(caddr_t arg);
1497eea693dSMark Johnson 
1507eea693dSMark Johnson static int blk_kstat_init(blk_ring_t ring);
1517eea693dSMark Johnson static void blk_kstat_fini(blk_ring_t ring);
1527eea693dSMark Johnson static int blk_kstat_update(kstat_t *ksp, int flag);
1537eea693dSMark Johnson 
1547eea693dSMark Johnson static void blk_ring_request_32(blkif_request_t *dst,
1557eea693dSMark Johnson     blkif_x86_32_request_t *src);
1567eea693dSMark Johnson static void blk_ring_request_64(blkif_request_t *dst,
1577eea693dSMark Johnson     blkif_x86_64_request_t *src);
1587eea693dSMark Johnson 
1597eea693dSMark Johnson static void blk_ring_response_32(blkif_x86_32_response_t *dst,
1607eea693dSMark Johnson     blkif_response_t *src);
1617eea693dSMark Johnson static void blk_ring_response_64(blkif_x86_64_response_t *dst,
1627eea693dSMark Johnson     blkif_response_t *src);
1637eea693dSMark Johnson 
1647eea693dSMark Johnson 
1657eea693dSMark Johnson /*
1667eea693dSMark Johnson  * blk_ring_init()
1677eea693dSMark Johnson  */
1687eea693dSMark Johnson int
blk_ring_init(blk_ringinit_args_t * args,blk_ring_t * ringp)1697eea693dSMark Johnson blk_ring_init(blk_ringinit_args_t *args, blk_ring_t *ringp)
1707eea693dSMark Johnson {
1717eea693dSMark Johnson 	blk_ring_t ring;
1727eea693dSMark Johnson 	int e;
1737eea693dSMark Johnson 
1747eea693dSMark Johnson 
1757eea693dSMark Johnson 	ring = kmem_zalloc(sizeof (struct blk_ring_s), KM_SLEEP);
1767eea693dSMark Johnson 	mutex_init(&ring->ri_mutex, NULL, MUTEX_DRIVER, NULL);
1777eea693dSMark Johnson 	ring->ri_dip = args->ar_dip;
1787eea693dSMark Johnson 	ring->ri_intr = args->ar_intr;
1797eea693dSMark Johnson 	ring->ri_intr_arg = args->ar_intr_arg;
1807eea693dSMark Johnson 	ring->ri_ringup = args->ar_ringup;
1817eea693dSMark Johnson 	ring->ri_ringup_arg = args->ar_ringup_arg;
1827eea693dSMark Johnson 	ring->ri_ringdown = args->ar_ringdown;
1837eea693dSMark Johnson 	ring->ri_ringdown_arg = args->ar_ringdown_arg;
1847eea693dSMark Johnson 
1857eea693dSMark Johnson 	ring->ri_if_status = BLK_IF_UNKNOWN;
1867eea693dSMark Johnson 	ring->ri_be_status = BLK_BE_UNKNOWN;
1877eea693dSMark Johnson 	ring->ri_fe_status = BLK_FE_UNKNOWN;
1887eea693dSMark Johnson 	ring->ri_state.rs_sleeping_on_ring = B_FALSE;
1897eea693dSMark Johnson 	ring->ri_state.rs_ring_up = B_FALSE;
1907eea693dSMark Johnson 
1917eea693dSMark Johnson 	mutex_init(&ring->ri_state.rs_mutex, NULL, MUTEX_DRIVER, NULL);
1927eea693dSMark Johnson 	cv_init(&ring->ri_state.rs_cv, NULL, CV_DRIVER, NULL);
1937eea693dSMark Johnson 
1947eea693dSMark Johnson 	e = blk_kstat_init(ring);
1957eea693dSMark Johnson 	if (e != DDI_SUCCESS) {
1967eea693dSMark Johnson 		goto ringinitfail_kstat;
1977eea693dSMark Johnson 	}
1987eea693dSMark Johnson 
1997eea693dSMark Johnson 	/* Watch frontend and hotplug state change */
2007eea693dSMark Johnson 	if (xvdi_add_event_handler(ring->ri_dip, XS_OE_STATE,
2017eea693dSMark Johnson 	    blk_oe_state_change, ring) != DDI_SUCCESS) {
2027eea693dSMark Johnson 		goto ringinitfail_oestate;
2037eea693dSMark Johnson 	}
2047eea693dSMark Johnson 	if (xvdi_add_event_handler(ring->ri_dip, XS_HP_STATE,
2057eea693dSMark Johnson 	    blk_hp_state_change, ring) != DDI_SUCCESS) {
2067eea693dSMark Johnson 		goto ringinitfail_hpstate;
2077eea693dSMark Johnson 	}
2087eea693dSMark Johnson 
2097eea693dSMark Johnson 	/*
2107eea693dSMark Johnson 	 * Kick-off hotplug script
2117eea693dSMark Johnson 	 */
2127eea693dSMark Johnson 	if (xvdi_post_event(ring->ri_dip, XEN_HP_ADD) != DDI_SUCCESS) {
2137eea693dSMark Johnson 		cmn_err(CE_WARN, "blk@%s: failed to start hotplug script",
2147eea693dSMark Johnson 		    ddi_get_name_addr(ring->ri_dip));
2157eea693dSMark Johnson 		goto ringinitfail_postevent;
2167eea693dSMark Johnson 	}
2177eea693dSMark Johnson 
2187eea693dSMark Johnson 	/*
2197eea693dSMark Johnson 	 * start waiting for hotplug event and otherend state event
2207eea693dSMark Johnson 	 * mainly for debugging, frontend will not take any op seeing this
2217eea693dSMark Johnson 	 */
2227eea693dSMark Johnson 	(void) xvdi_switch_state(ring->ri_dip, XBT_NULL, XenbusStateInitWait);
2237eea693dSMark Johnson 
2247eea693dSMark Johnson 	*ringp = ring;
2257eea693dSMark Johnson 	return (DDI_SUCCESS);
2267eea693dSMark Johnson 
2277eea693dSMark Johnson ringinitfail_postevent:
2287eea693dSMark Johnson 	xvdi_remove_event_handler(ring->ri_dip, XS_HP_STATE);
2297eea693dSMark Johnson ringinitfail_hpstate:
2307eea693dSMark Johnson 	xvdi_remove_event_handler(ring->ri_dip, XS_OE_STATE);
2317eea693dSMark Johnson ringinitfail_oestate:
2327eea693dSMark Johnson 	blk_kstat_fini(ring);
2337eea693dSMark Johnson ringinitfail_kstat:
2347eea693dSMark Johnson 	cv_destroy(&ring->ri_state.rs_cv);
2357eea693dSMark Johnson 	mutex_destroy(&ring->ri_state.rs_mutex);
2367eea693dSMark Johnson 	mutex_destroy(&ring->ri_mutex);
2377eea693dSMark Johnson 	kmem_free(ring, sizeof (struct blk_ring_s));
2387eea693dSMark Johnson 	return (DDI_FAILURE);
2397eea693dSMark Johnson }
2407eea693dSMark Johnson 
2417eea693dSMark Johnson 
2427eea693dSMark Johnson /*
2437eea693dSMark Johnson  * blk_ring_fini()
2447eea693dSMark Johnson  */
2457eea693dSMark Johnson void
blk_ring_fini(blk_ring_t * ringp)2467eea693dSMark Johnson blk_ring_fini(blk_ring_t *ringp)
2477eea693dSMark Johnson {
2487eea693dSMark Johnson 	blk_ring_t ring;
2497eea693dSMark Johnson 
2507eea693dSMark Johnson 
2517eea693dSMark Johnson 	ring = *ringp;
2527eea693dSMark Johnson 
2537eea693dSMark Johnson 	mutex_enter(&ring->ri_mutex);
2547eea693dSMark Johnson 	if (ring->ri_if_status != BLK_IF_DISCONNECTED) {
2557eea693dSMark Johnson 		blk_ring_close(ring);
2567eea693dSMark Johnson 	}
2577eea693dSMark Johnson 	mutex_exit(&ring->ri_mutex);
2587eea693dSMark Johnson 
2597eea693dSMark Johnson 	xvdi_remove_event_handler(ring->ri_dip, NULL);
2607eea693dSMark Johnson 	blk_kstat_fini(ring);
2617eea693dSMark Johnson 	cv_destroy(&ring->ri_state.rs_cv);
2627eea693dSMark Johnson 	mutex_destroy(&ring->ri_state.rs_mutex);
2637eea693dSMark Johnson 	mutex_destroy(&ring->ri_mutex);
2647eea693dSMark Johnson 	kmem_free(ring, sizeof (struct blk_ring_s));
2657eea693dSMark Johnson 
2667eea693dSMark Johnson 	*ringp = NULL;
2677eea693dSMark Johnson }
2687eea693dSMark Johnson 
2697eea693dSMark Johnson 
2707eea693dSMark Johnson /*
2717eea693dSMark Johnson  * blk_kstat_init()
2727eea693dSMark Johnson  */
2737eea693dSMark Johnson static int
blk_kstat_init(blk_ring_t ring)2747eea693dSMark Johnson blk_kstat_init(blk_ring_t ring)
2757eea693dSMark Johnson {
2767eea693dSMark Johnson 	int nstat = sizeof (blk_stats) / sizeof (blk_stats[0]);
2777eea693dSMark Johnson 	char **cp = blk_stats;
2787eea693dSMark Johnson 	kstat_named_t *knp;
2797eea693dSMark Johnson 
2807eea693dSMark Johnson 	ring->ri_kstats = kstat_create(ddi_get_name(ring->ri_dip),
2817eea693dSMark Johnson 	    ddi_get_instance(ring->ri_dip), "req_statistics", "block",
2827eea693dSMark Johnson 	    KSTAT_TYPE_NAMED, nstat, 0);
2837eea693dSMark Johnson 	if (ring->ri_kstats == NULL) {
2847eea693dSMark Johnson 		return (DDI_FAILURE);
2857eea693dSMark Johnson 	}
2867eea693dSMark Johnson 
2877eea693dSMark Johnson 	ring->ri_kstats->ks_private = ring;
2887eea693dSMark Johnson 	ring->ri_kstats->ks_update = blk_kstat_update;
2897eea693dSMark Johnson 
2907eea693dSMark Johnson 	knp = ring->ri_kstats->ks_data;
2917eea693dSMark Johnson 	while (nstat > 0) {
2927eea693dSMark Johnson 		kstat_named_init(knp, *cp, KSTAT_DATA_UINT64);
2937eea693dSMark Johnson 		knp++;
2947eea693dSMark Johnson 		cp++;
2957eea693dSMark Johnson 		nstat--;
2967eea693dSMark Johnson 	}
2977eea693dSMark Johnson 
2987eea693dSMark Johnson 	kstat_install(ring->ri_kstats);
2997eea693dSMark Johnson 
3007eea693dSMark Johnson 	return (DDI_SUCCESS);
3017eea693dSMark Johnson }
3027eea693dSMark Johnson 
3037eea693dSMark Johnson 
3047eea693dSMark Johnson /*
3057eea693dSMark Johnson  * blk_kstat_fini()
3067eea693dSMark Johnson  */
3077eea693dSMark Johnson static void
blk_kstat_fini(blk_ring_t ring)3087eea693dSMark Johnson blk_kstat_fini(blk_ring_t ring)
3097eea693dSMark Johnson {
3107eea693dSMark Johnson 	kstat_delete(ring->ri_kstats);
3117eea693dSMark Johnson }
3127eea693dSMark Johnson 
3137eea693dSMark Johnson 
3147eea693dSMark Johnson /*
3157eea693dSMark Johnson  * blk_kstat_update()
3167eea693dSMark Johnson  */
3177eea693dSMark Johnson static int
blk_kstat_update(kstat_t * ksp,int flag)3187eea693dSMark Johnson blk_kstat_update(kstat_t *ksp, int flag)
3197eea693dSMark Johnson {
3207eea693dSMark Johnson 	kstat_named_t *knp;
3217eea693dSMark Johnson 	blk_stats_t *stats;
3227eea693dSMark Johnson 	blk_ring_t ring;
3237eea693dSMark Johnson 
3247eea693dSMark Johnson 
3257eea693dSMark Johnson 	if (flag != KSTAT_READ) {
3267eea693dSMark Johnson 		return (EACCES);
3277eea693dSMark Johnson 	}
3287eea693dSMark Johnson 
3297eea693dSMark Johnson 	ring = ksp->ks_private;
3307eea693dSMark Johnson 	stats = &ring->ri_stats;
3317eea693dSMark Johnson 	knp = ksp->ks_data;
3327eea693dSMark Johnson 
3337eea693dSMark Johnson 	/*
3347eea693dSMark Johnson 	 * Assignment order should match that of the names in
3357eea693dSMark Johnson 	 * blk_stats.
3367eea693dSMark Johnson 	 */
3377eea693dSMark Johnson 	(knp++)->value.ui64 = stats->bs_req_reads;
3387eea693dSMark Johnson 	(knp++)->value.ui64 = stats->bs_req_writes;
3397eea693dSMark Johnson 	(knp++)->value.ui64 = stats->bs_req_barriers;
3407eea693dSMark Johnson 	(knp++)->value.ui64 = stats->bs_req_flushes;
3417eea693dSMark Johnson 	(knp++)->value.ui64 = 0; /* oo_req */
3427eea693dSMark Johnson 
3437eea693dSMark Johnson 	return (0);
3447eea693dSMark Johnson }
3457eea693dSMark Johnson 
3467eea693dSMark Johnson 
3477eea693dSMark Johnson /*
3487eea693dSMark Johnson  * blk_oe_state_change()
3497eea693dSMark Johnson  */
3507eea693dSMark Johnson /*ARGSUSED*/
3517eea693dSMark Johnson static void
blk_oe_state_change(dev_info_t * dip,ddi_eventcookie_t id,void * arg,void * impl_data)3527eea693dSMark Johnson blk_oe_state_change(dev_info_t *dip, ddi_eventcookie_t id, void *arg,
3537eea693dSMark Johnson     void *impl_data)
3547eea693dSMark Johnson {
3557eea693dSMark Johnson 	XenbusState new_state;
3567eea693dSMark Johnson 	blk_ring_t ring;
3577eea693dSMark Johnson 
3587eea693dSMark Johnson 
3597eea693dSMark Johnson 	ring = (blk_ring_t)arg;
3607eea693dSMark Johnson 	new_state = *(XenbusState *)impl_data;
3617eea693dSMark Johnson 
3627eea693dSMark Johnson 	mutex_enter(&ring->ri_mutex);
3637eea693dSMark Johnson 
3647eea693dSMark Johnson 	if (blk_check_state_transition(ring, new_state) == DDI_FAILURE) {
3657eea693dSMark Johnson 		mutex_exit(&ring->ri_mutex);
3667eea693dSMark Johnson 		return;
3677eea693dSMark Johnson 	}
3687eea693dSMark Johnson 
3697eea693dSMark Johnson 	switch (new_state) {
3707eea693dSMark Johnson 	case XenbusStateInitialised:
3717eea693dSMark Johnson 		ASSERT(ring->ri_if_status == BLK_IF_UNKNOWN);
3727eea693dSMark Johnson 
3737eea693dSMark Johnson 		/* frontend is ready for connecting */
3747eea693dSMark Johnson 		ring->ri_fe_status = BLK_FE_READY;
3757eea693dSMark Johnson 
3767eea693dSMark Johnson 		if (ring->ri_be_status == BLK_BE_READY) {
3777eea693dSMark Johnson 			mutex_exit(&ring->ri_mutex);
3787eea693dSMark Johnson 			if (blk_start_connect(ring) != DDI_SUCCESS)
3797eea693dSMark Johnson 				(void) blk_start_disconnect(ring);
3807eea693dSMark Johnson 			mutex_enter(&ring->ri_mutex);
3817eea693dSMark Johnson 		}
3827eea693dSMark Johnson 		break;
3837eea693dSMark Johnson 	case XenbusStateClosing:
3847eea693dSMark Johnson 		(void) xvdi_switch_state(dip, XBT_NULL, XenbusStateClosing);
3857eea693dSMark Johnson 		break;
3867eea693dSMark Johnson 	case XenbusStateClosed:
3877eea693dSMark Johnson 		/* clean up */
3887eea693dSMark Johnson 		(void) xvdi_post_event(ring->ri_dip, XEN_HP_REMOVE);
3897eea693dSMark Johnson 		if (ring->ri_ringdown != NULL) {
3907eea693dSMark Johnson 			(*(ring->ri_ringdown))(ring->ri_ringdown_arg);
3917eea693dSMark Johnson 		}
3927eea693dSMark Johnson 		blk_ring_close(ring);
3937eea693dSMark Johnson 
3947eea693dSMark Johnson 		/* reset state in case of reconnect */
3957eea693dSMark Johnson 		ring->ri_if_status = BLK_IF_UNKNOWN;
3967eea693dSMark Johnson 		ring->ri_be_status = BLK_BE_UNKNOWN;
3977eea693dSMark Johnson 		ring->ri_fe_status = BLK_FE_UNKNOWN;
3987eea693dSMark Johnson 		ring->ri_state.rs_sleeping_on_ring = B_FALSE;
3997eea693dSMark Johnson 		ring->ri_state.rs_ring_up = B_FALSE;
4007eea693dSMark Johnson 
4017eea693dSMark Johnson 		break;
4027eea693dSMark Johnson 	default:
4037eea693dSMark Johnson 		ASSERT(0);
4047eea693dSMark Johnson 	}
4057eea693dSMark Johnson 
4067eea693dSMark Johnson 	mutex_exit(&ring->ri_mutex);
4077eea693dSMark Johnson }
4087eea693dSMark Johnson 
4097eea693dSMark Johnson 
4107eea693dSMark Johnson /*
4117eea693dSMark Johnson  * blk_hp_state_change()
4127eea693dSMark Johnson  */
4137eea693dSMark Johnson /*ARGSUSED*/
4147eea693dSMark Johnson static void
blk_hp_state_change(dev_info_t * dip,ddi_eventcookie_t id,void * arg,void * impl_data)4157eea693dSMark Johnson blk_hp_state_change(dev_info_t *dip, ddi_eventcookie_t id, void *arg,
4167eea693dSMark Johnson     void *impl_data)
4177eea693dSMark Johnson {
4187eea693dSMark Johnson 	xendev_hotplug_state_t hpstate;
4197eea693dSMark Johnson 	blk_ring_t ring;
4207eea693dSMark Johnson 
4217eea693dSMark Johnson 
4227eea693dSMark Johnson 	ring = (blk_ring_t)arg;
4237eea693dSMark Johnson 	hpstate = *(xendev_hotplug_state_t *)impl_data;
4247eea693dSMark Johnson 
4257eea693dSMark Johnson 	mutex_enter(&ring->ri_mutex);
4267eea693dSMark Johnson 	if (hpstate == Connected) {
4277eea693dSMark Johnson 		/* Hotplug script has completed successfully */
4287eea693dSMark Johnson 		if (ring->ri_be_status == BLK_BE_UNKNOWN) {
4297eea693dSMark Johnson 			ring->ri_be_status = BLK_BE_READY;
4307eea693dSMark Johnson 			if (ring->ri_fe_status == BLK_FE_READY) {
4317eea693dSMark Johnson 				mutex_exit(&ring->ri_mutex);
4327eea693dSMark Johnson 				/* try to connect to frontend */
4337eea693dSMark Johnson 				if (blk_start_connect(ring) != DDI_SUCCESS)
4347eea693dSMark Johnson 					(void) blk_start_disconnect(ring);
4357eea693dSMark Johnson 				mutex_enter(&ring->ri_mutex);
4367eea693dSMark Johnson 			}
4377eea693dSMark Johnson 		}
4387eea693dSMark Johnson 	}
4397eea693dSMark Johnson 	mutex_exit(&ring->ri_mutex);
4407eea693dSMark Johnson }
4417eea693dSMark Johnson 
4427eea693dSMark Johnson 
4437eea693dSMark Johnson /*
4447eea693dSMark Johnson  * blk_check_state_transition()
4457eea693dSMark Johnson  *    check the XenbusState change to see if the change is a valid transition
4467eea693dSMark Johnson  *    or not. The new state is written by frontend domain, or by running
4477eea693dSMark Johnson  *    xenstore-write to change it manually in dom0.
4487eea693dSMark Johnson  */
4497eea693dSMark Johnson static int
blk_check_state_transition(blk_ring_t ring,XenbusState oestate)4507eea693dSMark Johnson blk_check_state_transition(blk_ring_t ring, XenbusState oestate)
4517eea693dSMark Johnson {
4527eea693dSMark Johnson 	switch (ring->ri_if_status) {
4537eea693dSMark Johnson 	case BLK_IF_UNKNOWN:
4547eea693dSMark Johnson 		if (ring->ri_fe_status == BLK_FE_UNKNOWN) {
4557eea693dSMark Johnson 			if ((oestate == XenbusStateUnknown)		||
4567eea693dSMark Johnson 			    (oestate == XenbusStateConnected))
4577eea693dSMark Johnson 				goto statechkfail_bug;
4587eea693dSMark Johnson 			else if ((oestate == XenbusStateInitialising)	||
4597eea693dSMark Johnson 			    (oestate == XenbusStateInitWait))
4607eea693dSMark Johnson 				goto statechkfail_nop;
4617eea693dSMark Johnson 		} else {
4627eea693dSMark Johnson 			if ((oestate == XenbusStateUnknown)		||
4637eea693dSMark Johnson 			    (oestate == XenbusStateInitialising)	||
4647eea693dSMark Johnson 			    (oestate == XenbusStateInitWait)		||
4657eea693dSMark Johnson 			    (oestate == XenbusStateConnected))
4667eea693dSMark Johnson 				goto statechkfail_bug;
4677eea693dSMark Johnson 			else if (oestate == XenbusStateInitialised)
4687eea693dSMark Johnson 				goto statechkfail_nop;
4697eea693dSMark Johnson 		}
4707eea693dSMark Johnson 		break;
4717eea693dSMark Johnson 
4727eea693dSMark Johnson 	case BLK_IF_CONNECTED:
4737eea693dSMark Johnson 		if ((oestate == XenbusStateUnknown)		||
4747eea693dSMark Johnson 		    (oestate == XenbusStateInitialising)	||
4757eea693dSMark Johnson 		    (oestate == XenbusStateInitWait)		||
4767eea693dSMark Johnson 		    (oestate == XenbusStateInitialised))
4777eea693dSMark Johnson 			goto statechkfail_bug;
4787eea693dSMark Johnson 		else if (oestate == XenbusStateConnected)
4797eea693dSMark Johnson 			goto statechkfail_nop;
4807eea693dSMark Johnson 		break;
4817eea693dSMark Johnson 
4827eea693dSMark Johnson 	case BLK_IF_DISCONNECTED:
4837eea693dSMark Johnson 	default:
4847eea693dSMark Johnson 		goto statechkfail_bug;
4857eea693dSMark Johnson 	}
4867eea693dSMark Johnson 
4877eea693dSMark Johnson 	return (DDI_SUCCESS);
4887eea693dSMark Johnson 
4897eea693dSMark Johnson statechkfail_bug:
4907eea693dSMark Johnson 	cmn_err(CE_NOTE, "blk@%s: unexpected otherend "
4917eea693dSMark Johnson 	    "state change to %d!, when status is %d",
4927eea693dSMark Johnson 	    ddi_get_name_addr(ring->ri_dip), oestate,
4937eea693dSMark Johnson 	    ring->ri_if_status);
4947eea693dSMark Johnson 
4957eea693dSMark Johnson statechkfail_nop:
4967eea693dSMark Johnson 	return (DDI_FAILURE);
4977eea693dSMark Johnson }
4987eea693dSMark Johnson 
4997eea693dSMark Johnson 
5007eea693dSMark Johnson /*
5017eea693dSMark Johnson  * blk_start_connect()
5027eea693dSMark Johnson  *    Kick-off connect process
5037eea693dSMark Johnson  *    If ri_fe_status == BLK_FE_READY and ri_be_status == BLK_BE_READY
5047eea693dSMark Johnson  *    the ri_if_status will be changed to BLK_IF_CONNECTED on success,
5057eea693dSMark Johnson  *    otherwise, ri_if_status will not be changed
5067eea693dSMark Johnson  */
5077eea693dSMark Johnson static int
blk_start_connect(blk_ring_t ring)5087eea693dSMark Johnson blk_start_connect(blk_ring_t ring)
5097eea693dSMark Johnson {
5107eea693dSMark Johnson 	xenbus_transaction_t xbt;
5117eea693dSMark Johnson 	dev_info_t *dip;
5127eea693dSMark Johnson 	char *barrier;
5137eea693dSMark Johnson 	char *xsnode;
5147eea693dSMark Johnson 	uint_t len;
5157eea693dSMark Johnson 	int e;
5167eea693dSMark Johnson 
5177eea693dSMark Johnson 
5187eea693dSMark Johnson 	dip = ring->ri_dip;
5197eea693dSMark Johnson 
5207eea693dSMark Johnson 	/*
5217eea693dSMark Johnson 	 * Start connect to frontend only when backend device are ready
5227eea693dSMark Johnson 	 * and frontend has moved to XenbusStateInitialised, which means
5237eea693dSMark Johnson 	 * ready to connect
5247eea693dSMark Johnson 	 */
5257eea693dSMark Johnson 	ASSERT(ring->ri_fe_status == BLK_FE_READY);
5267eea693dSMark Johnson 	ASSERT(ring->ri_be_status == BLK_BE_READY);
5277eea693dSMark Johnson 
5287eea693dSMark Johnson 	xsnode = xvdi_get_xsname(dip);
5297eea693dSMark Johnson 	if (xsnode == NULL) {
5307eea693dSMark Johnson 		goto startconnectfail_get_xsname;
5317eea693dSMark Johnson 	}
5327eea693dSMark Johnson 
5337eea693dSMark Johnson 	ring->ri_fe = xvdi_get_oeid(dip);
5347eea693dSMark Johnson 	if (ring->ri_fe == (domid_t)-1) {
5357eea693dSMark Johnson 		goto startconnectfail_get_oeid;
5367eea693dSMark Johnson 	}
5377eea693dSMark Johnson 
5387eea693dSMark Johnson 	e =  xvdi_switch_state(dip, XBT_NULL, XenbusStateInitialised);
5397eea693dSMark Johnson 	if (e > 0) {
5407eea693dSMark Johnson 		goto startconnectfail_switch_init;
5417eea693dSMark Johnson 	}
5427eea693dSMark Johnson 
5437eea693dSMark Johnson 	e = blk_bindto_frontend(ring);
5447eea693dSMark Johnson 	if (e != DDI_SUCCESS) {
5457eea693dSMark Johnson 		goto startconnectfail_bindto_frontend;
5467eea693dSMark Johnson 	}
5477eea693dSMark Johnson 	ring->ri_if_status = BLK_IF_CONNECTED;
5487eea693dSMark Johnson 
5497eea693dSMark Johnson 	e = ddi_add_intr(dip, 0, NULL, NULL, blk_intr, (caddr_t)ring);
5507eea693dSMark Johnson 	if (e != DDI_SUCCESS) {
5517eea693dSMark Johnson 		goto startconnectfail_add_intr;
5527eea693dSMark Johnson 	}
5537eea693dSMark Johnson 
5547eea693dSMark Johnson trans_retry:
5557eea693dSMark Johnson 	e = xenbus_transaction_start(&xbt);
5567eea693dSMark Johnson 	if (e != 0) {
5577eea693dSMark Johnson 		xvdi_fatal_error(dip, e, "transaction start");
5587eea693dSMark Johnson 		goto startconnectfail_transaction_start;
5597eea693dSMark Johnson 	}
5607eea693dSMark Johnson 
561*62dcc6f3SMark Johnson 	/* xentop requires the instance in xenstore */
562*62dcc6f3SMark Johnson 	e = xenbus_printf(xbt, xsnode, "instance", "%d",
563*62dcc6f3SMark Johnson 	    ddi_get_instance(ring->ri_dip));
564*62dcc6f3SMark Johnson 	if (e != 0) {
565*62dcc6f3SMark Johnson 		cmn_err(CE_WARN, "xdb@%s: failed to write 'instance'",
566*62dcc6f3SMark Johnson 		    ddi_get_name_addr(dip));
567*62dcc6f3SMark Johnson 		xvdi_fatal_error(dip, e, "writing 'instance'");
568*62dcc6f3SMark Johnson 		(void) xenbus_transaction_end(xbt, 1);
569*62dcc6f3SMark Johnson 		goto startconnectfail_xenbus_printf;
570*62dcc6f3SMark Johnson 	}
571*62dcc6f3SMark Johnson 
5727eea693dSMark Johnson 	/* If feature-barrier isn't present in xenstore, add it */
5737eea693dSMark Johnson 	e = xenbus_read(xbt, xsnode, "feature-barrier", (void **)&barrier,
5747eea693dSMark Johnson 	    &len);
5757eea693dSMark Johnson 	if (e != 0) {
5767eea693dSMark Johnson 		e = xenbus_printf(xbt, xsnode, "feature-barrier", "%d", 1);
5777eea693dSMark Johnson 		if (e != 0) {
5787eea693dSMark Johnson 			cmn_err(CE_WARN, "xdb@%s: failed to write "
5797eea693dSMark Johnson 			    "'feature-barrier'", ddi_get_name_addr(dip));
5807eea693dSMark Johnson 			xvdi_fatal_error(dip, e, "writing 'feature-barrier'");
5817eea693dSMark Johnson 			(void) xenbus_transaction_end(xbt, 1);
5827eea693dSMark Johnson 			goto startconnectfail_xenbus_printf;
5837eea693dSMark Johnson 		}
5847eea693dSMark Johnson 	} else {
5857eea693dSMark Johnson 		kmem_free(barrier, len);
5867eea693dSMark Johnson 	}
5877eea693dSMark Johnson 
5887eea693dSMark Johnson 	e = xvdi_switch_state(dip, xbt, XenbusStateConnected);
5897eea693dSMark Johnson 	if (e > 0) {
5907eea693dSMark Johnson 		xvdi_fatal_error(dip, e, "writing 'state'");
5917eea693dSMark Johnson 		(void) xenbus_transaction_end(xbt, 1);
5927eea693dSMark Johnson 		goto startconnectfail_switch_connected;
5937eea693dSMark Johnson 	}
5947eea693dSMark Johnson 
5957eea693dSMark Johnson 	e = xenbus_transaction_end(xbt, 0);
5967eea693dSMark Johnson 	if (e != 0) {
5977eea693dSMark Johnson 		if (e == EAGAIN) {
5987eea693dSMark Johnson 			/* transaction is ended, don't need to abort it */
5997eea693dSMark Johnson 			goto trans_retry;
6007eea693dSMark Johnson 		}
6017eea693dSMark Johnson 		xvdi_fatal_error(dip, e, "completing transaction");
6027eea693dSMark Johnson 		goto startconnectfail_transaction_end;
6037eea693dSMark Johnson 	}
6047eea693dSMark Johnson 
6057eea693dSMark Johnson 	mutex_enter(&ring->ri_state.rs_mutex);
6067eea693dSMark Johnson 	ring->ri_state.rs_ring_up = B_TRUE;
6077eea693dSMark Johnson 	if (ring->ri_state.rs_sleeping_on_ring) {
6087eea693dSMark Johnson 		ring->ri_state.rs_sleeping_on_ring = B_FALSE;
6097eea693dSMark Johnson 		cv_signal(&ring->ri_state.rs_cv);
6107eea693dSMark Johnson 	}
6117eea693dSMark Johnson 	mutex_exit(&ring->ri_state.rs_mutex);
6127eea693dSMark Johnson 
6137eea693dSMark Johnson 	if (ring->ri_ringup != NULL) {
6147eea693dSMark Johnson 		(*(ring->ri_ringup))(ring->ri_ringup_arg);
6157eea693dSMark Johnson 	}
6167eea693dSMark Johnson 
6177eea693dSMark Johnson 	return (DDI_SUCCESS);
6187eea693dSMark Johnson 
6197eea693dSMark Johnson 
6207eea693dSMark Johnson startconnectfail_transaction_end:
6217eea693dSMark Johnson startconnectfail_switch_connected:
6227eea693dSMark Johnson startconnectfail_xenbus_printf:
6237eea693dSMark Johnson startconnectfail_transaction_start:
6247eea693dSMark Johnson 	ddi_remove_intr(dip, 0, NULL);
6257eea693dSMark Johnson startconnectfail_add_intr:
6267eea693dSMark Johnson 	blk_unbindfrom_frontend(ring);
6277eea693dSMark Johnson 	ring->ri_fe = (domid_t)-1;
6287eea693dSMark Johnson startconnectfail_bindto_frontend:
6297eea693dSMark Johnson 	(void) xvdi_switch_state(dip, XBT_NULL, XenbusStateClosed);
6307eea693dSMark Johnson startconnectfail_switch_init:
6317eea693dSMark Johnson startconnectfail_get_oeid:
6327eea693dSMark Johnson startconnectfail_get_xsname:
6337eea693dSMark Johnson 	return (DDI_FAILURE);
6347eea693dSMark Johnson }
6357eea693dSMark Johnson 
6367eea693dSMark Johnson 
6377eea693dSMark Johnson /*
6387eea693dSMark Johnson  * blk_start_disconnect()
6397eea693dSMark Johnson  *    Kick-off disconnect process. ri_if_status will not be changed
6407eea693dSMark Johnson  */
6417eea693dSMark Johnson static void
blk_start_disconnect(blk_ring_t ring)6427eea693dSMark Johnson blk_start_disconnect(blk_ring_t ring)
6437eea693dSMark Johnson {
6447eea693dSMark Johnson 	/* Kick-off disconnect process */
6457eea693dSMark Johnson 	(void) xvdi_switch_state(ring->ri_dip, XBT_NULL, XenbusStateClosing);
6467eea693dSMark Johnson }
6477eea693dSMark Johnson 
6487eea693dSMark Johnson 
6497eea693dSMark Johnson /*
6507eea693dSMark Johnson  * blk_ring_close()
6517eea693dSMark Johnson  *    Disconnect from frontend and close backend device
6527eea693dSMark Johnson  *    ifstatus will be changed to BLK_DISCONNECTED
6537eea693dSMark Johnson  *    Xenbus state will be changed to XenbusStateClosed
6547eea693dSMark Johnson  */
6557eea693dSMark Johnson static void
blk_ring_close(blk_ring_t ring)6567eea693dSMark Johnson blk_ring_close(blk_ring_t ring)
6577eea693dSMark Johnson {
6587eea693dSMark Johnson 	dev_info_t *dip;
6597eea693dSMark Johnson 
6607eea693dSMark Johnson 
6617eea693dSMark Johnson 	/* mutex protect ri_if_status only here */
6627eea693dSMark Johnson 	ASSERT(MUTEX_HELD(&ring->ri_mutex));
6637eea693dSMark Johnson 
6647eea693dSMark Johnson 	dip = ring->ri_dip;
6657eea693dSMark Johnson 
6667eea693dSMark Johnson 	if (ring->ri_if_status != BLK_IF_CONNECTED) {
6677eea693dSMark Johnson 		return;
6687eea693dSMark Johnson 	}
6697eea693dSMark Johnson 
6707eea693dSMark Johnson 	ring->ri_if_status = BLK_IF_DISCONNECTED;
6717eea693dSMark Johnson 	mutex_exit(&ring->ri_mutex);
6727eea693dSMark Johnson 
6737eea693dSMark Johnson 	/* stop accepting I/O request from frontend */
6747eea693dSMark Johnson 	ddi_remove_intr(dip, 0, NULL);
6757eea693dSMark Johnson 
6767eea693dSMark Johnson 	blk_unbindfrom_frontend(ring);
6777eea693dSMark Johnson 	ring->ri_fe = (domid_t)-1;
6787eea693dSMark Johnson 	(void) xvdi_switch_state(dip, XBT_NULL, XenbusStateClosed);
6797eea693dSMark Johnson 	mutex_enter(&ring->ri_mutex);
6807eea693dSMark Johnson }
6817eea693dSMark Johnson 
6827eea693dSMark Johnson 
6837eea693dSMark Johnson /*
6847eea693dSMark Johnson  * blk_bindto_frontend()
6857eea693dSMark Johnson  */
6867eea693dSMark Johnson static int
blk_bindto_frontend(blk_ring_t ring)6877eea693dSMark Johnson blk_bindto_frontend(blk_ring_t ring)
6887eea693dSMark Johnson {
6897eea693dSMark Johnson 	evtchn_port_t evtchn;
6907eea693dSMark Johnson 	char protocol[64];
6917eea693dSMark Johnson 	grant_ref_t gref;
6927eea693dSMark Johnson 	dev_info_t *dip;
6937eea693dSMark Johnson 	char *oename;
6947eea693dSMark Johnson 	int e;
6957eea693dSMark Johnson 
6967eea693dSMark Johnson 
6977eea693dSMark Johnson 	dip = ring->ri_dip;
6987eea693dSMark Johnson 	protocol[0] = 0x0;
6997eea693dSMark Johnson 
7007eea693dSMark Johnson 	/*
7017eea693dSMark Johnson 	 * Gather info from frontend
7027eea693dSMark Johnson 	 */
7037eea693dSMark Johnson 	oename = xvdi_get_oename(dip);
7047eea693dSMark Johnson 	if (oename == NULL) {
7057eea693dSMark Johnson 		return (DDI_FAILURE);
7067eea693dSMark Johnson 	}
7077eea693dSMark Johnson 
7087eea693dSMark Johnson 	e = xenbus_gather(XBT_NULL, oename, "ring-ref", "%lu", &gref,
7097eea693dSMark Johnson 	    "event-channel", "%u", &evtchn, NULL);
7107eea693dSMark Johnson 	if (e != 0) {
7117eea693dSMark Johnson 		xvdi_fatal_error(dip, e,
7127eea693dSMark Johnson 		    "Getting ring-ref and evtchn from frontend");
7137eea693dSMark Johnson 		return (DDI_FAILURE);
7147eea693dSMark Johnson 	}
7157eea693dSMark Johnson 
7167eea693dSMark Johnson 	e = xenbus_gather(XBT_NULL, oename, "protocol", "%63s",
7177eea693dSMark Johnson 	    protocol, NULL);
7187eea693dSMark Johnson 	if (e != 0) {
7197eea693dSMark Johnson 		(void) strcpy(protocol, "unspecified, assuming native");
7207eea693dSMark Johnson 	} else if (strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE) == 0) {
7217eea693dSMark Johnson 		ring->ri_protocol = BLKIF_PROTOCOL_NATIVE;
7227eea693dSMark Johnson 		ring->ri_nentry = BLKIF_RING_SIZE;
7237eea693dSMark Johnson 		ring->ri_entrysize = sizeof (union blkif_sring_entry);
7247eea693dSMark Johnson 	} else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
7257eea693dSMark Johnson 		ring->ri_protocol = BLKIF_PROTOCOL_X86_32;
7267eea693dSMark Johnson 		ring->ri_nentry = BLKIF_X86_32_RING_SIZE;
7277eea693dSMark Johnson 		ring->ri_entrysize = sizeof (union blkif_x86_32_sring_entry);
7287eea693dSMark Johnson 	} else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
7297eea693dSMark Johnson 		ring->ri_protocol = BLKIF_PROTOCOL_X86_64;
7307eea693dSMark Johnson 		ring->ri_nentry = BLKIF_X86_64_RING_SIZE;
7317eea693dSMark Johnson 		ring->ri_entrysize = sizeof (union blkif_x86_64_sring_entry);
7327eea693dSMark Johnson 	} else {
7337eea693dSMark Johnson 		xvdi_fatal_error(dip, e, "unknown fe protocol");
7347eea693dSMark Johnson 		return (DDI_FAILURE);
7357eea693dSMark Johnson 	}
7367eea693dSMark Johnson 
7377eea693dSMark Johnson 	/*
7387eea693dSMark Johnson 	 * map and init ring
7397eea693dSMark Johnson 	 */
7407eea693dSMark Johnson 	e = xvdi_map_ring(dip, ring->ri_nentry, ring->ri_entrysize, gref,
7417eea693dSMark Johnson 	    &ring->ri_ring);
7427eea693dSMark Johnson 	if (e != DDI_SUCCESS) {
7437eea693dSMark Johnson 		return (DDI_FAILURE);
7447eea693dSMark Johnson 	}
7457eea693dSMark Johnson 
7467eea693dSMark Johnson 	/*
7477eea693dSMark Johnson 	 * bind event channel
7487eea693dSMark Johnson 	 */
7497eea693dSMark Johnson 	e = xvdi_bind_evtchn(dip, evtchn);
7507eea693dSMark Johnson 	if (e != DDI_SUCCESS) {
7517eea693dSMark Johnson 		xvdi_unmap_ring(ring->ri_ring);
7527eea693dSMark Johnson 		return (DDI_FAILURE);
7537eea693dSMark Johnson 	}
7547eea693dSMark Johnson 
7557eea693dSMark Johnson 
7567eea693dSMark Johnson 	return (DDI_SUCCESS);
7577eea693dSMark Johnson }
7587eea693dSMark Johnson 
7597eea693dSMark Johnson 
7607eea693dSMark Johnson /*
7617eea693dSMark Johnson  * blk_unbindfrom_frontend()
7627eea693dSMark Johnson  */
7637eea693dSMark Johnson static void
blk_unbindfrom_frontend(blk_ring_t ring)7647eea693dSMark Johnson blk_unbindfrom_frontend(blk_ring_t ring)
7657eea693dSMark Johnson {
7667eea693dSMark Johnson 	xvdi_free_evtchn(ring->ri_dip);
7677eea693dSMark Johnson 	xvdi_unmap_ring(ring->ri_ring);
7687eea693dSMark Johnson }
7697eea693dSMark Johnson 
7707eea693dSMark Johnson 
7717eea693dSMark Johnson /*
7727eea693dSMark Johnson  * blk_intr()
7737eea693dSMark Johnson  */
7747eea693dSMark Johnson static uint_t
blk_intr(caddr_t arg)7757eea693dSMark Johnson blk_intr(caddr_t arg)
7767eea693dSMark Johnson {
7777eea693dSMark Johnson 	blk_ring_t ring;
7787eea693dSMark Johnson 
7797eea693dSMark Johnson 	ring = (blk_ring_t)arg;
7807eea693dSMark Johnson 	if (ring->ri_if_status != BLK_IF_CONNECTED) {
7817eea693dSMark Johnson 		return (DDI_INTR_CLAIMED);
7827eea693dSMark Johnson 	}
7837eea693dSMark Johnson 
7847eea693dSMark Johnson 	(void) (*ring->ri_intr)(ring->ri_intr_arg);
7857eea693dSMark Johnson 	return (DDI_INTR_CLAIMED);
7867eea693dSMark Johnson }
7877eea693dSMark Johnson 
7887eea693dSMark Johnson 
7897eea693dSMark Johnson /*
7907eea693dSMark Johnson  * blk_ring_request_get()
7917eea693dSMark Johnson  */
7927eea693dSMark Johnson boolean_t
blk_ring_request_get(blk_ring_t ring,blkif_request_t * req)7937eea693dSMark Johnson blk_ring_request_get(blk_ring_t ring, blkif_request_t *req)
7947eea693dSMark Johnson {
7957eea693dSMark Johnson 	blkif_request_t *src;
7967eea693dSMark Johnson 	blk_stats_t *stats;
7977eea693dSMark Johnson 
7987eea693dSMark Johnson 
7997eea693dSMark Johnson 	mutex_enter(&ring->ri_mutex);
800349b53ddSStuart Maybee 
801349b53ddSStuart Maybee 	if (ring->ri_if_status != BLK_IF_CONNECTED) {
802349b53ddSStuart Maybee 		mutex_exit(&ring->ri_mutex);
803349b53ddSStuart Maybee 		return (B_FALSE);
804349b53ddSStuart Maybee 	}
805349b53ddSStuart Maybee 
8067eea693dSMark Johnson 	src = xvdi_ring_get_request(ring->ri_ring);
8077eea693dSMark Johnson 	if (src == NULL) {
8087eea693dSMark Johnson 		mutex_exit(&ring->ri_mutex);
8097eea693dSMark Johnson 		return (B_FALSE);
8107eea693dSMark Johnson 	}
8117eea693dSMark Johnson 
8127eea693dSMark Johnson 	switch (ring->ri_protocol) {
8137eea693dSMark Johnson 	case BLKIF_PROTOCOL_NATIVE:
8147eea693dSMark Johnson 		bcopy(src, req, sizeof (*req));
8157eea693dSMark Johnson 		break;
8167eea693dSMark Johnson 	case BLKIF_PROTOCOL_X86_32:
8177eea693dSMark Johnson 		blk_ring_request_32(req, (blkif_x86_32_request_t *)src);
8187eea693dSMark Johnson 		break;
8197eea693dSMark Johnson 	case BLKIF_PROTOCOL_X86_64:
8207eea693dSMark Johnson 		blk_ring_request_64(req, (blkif_x86_64_request_t *)src);
8217eea693dSMark Johnson 		break;
8227eea693dSMark Johnson 	default:
8237eea693dSMark Johnson 		cmn_err(CE_WARN, "blkif@%s: unrecognised protocol: %d",
8247eea693dSMark Johnson 		    ddi_get_name_addr(ring->ri_dip),
8257eea693dSMark Johnson 		    ring->ri_protocol);
8267eea693dSMark Johnson 	}
8277eea693dSMark Johnson 	mutex_exit(&ring->ri_mutex);
8287eea693dSMark Johnson 
8297eea693dSMark Johnson 	stats = &ring->ri_stats;
8307eea693dSMark Johnson 	switch (req->operation) {
8317eea693dSMark Johnson 	case BLKIF_OP_READ:
8327eea693dSMark Johnson 		stats->bs_req_reads++;
8337eea693dSMark Johnson 		break;
8347eea693dSMark Johnson 	case BLKIF_OP_WRITE:
8357eea693dSMark Johnson 		stats->bs_req_writes++;
8367eea693dSMark Johnson 		break;
8377eea693dSMark Johnson 	case BLKIF_OP_WRITE_BARRIER:
8387eea693dSMark Johnson 		stats->bs_req_barriers++;
8397eea693dSMark Johnson 		break;
8407eea693dSMark Johnson 	case BLKIF_OP_FLUSH_DISKCACHE:
8417eea693dSMark Johnson 		stats->bs_req_flushes++;
8427eea693dSMark Johnson 		break;
8437eea693dSMark Johnson 	}
8447eea693dSMark Johnson 
8457eea693dSMark Johnson 	return (B_TRUE);
8467eea693dSMark Johnson }
8477eea693dSMark Johnson 
8487eea693dSMark Johnson 
8497eea693dSMark Johnson /*
8507eea693dSMark Johnson  * blk_ring_request_requeue()
8517eea693dSMark Johnson  *    if a request is requeued, caller will have to poll for request
8527eea693dSMark Johnson  *    later.
8537eea693dSMark Johnson  */
8547eea693dSMark Johnson void
blk_ring_request_requeue(blk_ring_t ring)8557eea693dSMark Johnson blk_ring_request_requeue(blk_ring_t ring)
8567eea693dSMark Johnson {
857349b53ddSStuart Maybee 	mutex_enter(&ring->ri_mutex);
858349b53ddSStuart Maybee 
859349b53ddSStuart Maybee 	if (ring->ri_if_status != BLK_IF_CONNECTED) {
860349b53ddSStuart Maybee 		mutex_exit(&ring->ri_mutex);
861349b53ddSStuart Maybee 		return;
862349b53ddSStuart Maybee 	}
863349b53ddSStuart Maybee 
8647eea693dSMark Johnson 	ring->ri_ring->xr_sring.br.req_cons--;
865349b53ddSStuart Maybee 
866349b53ddSStuart Maybee 	mutex_exit(&ring->ri_mutex);
8677eea693dSMark Johnson }
8687eea693dSMark Johnson 
8697eea693dSMark Johnson 
8707eea693dSMark Johnson /*
8717eea693dSMark Johnson  * blk_ring_response_put()
8727eea693dSMark Johnson  */
8737eea693dSMark Johnson void
blk_ring_response_put(blk_ring_t ring,blkif_response_t * src)8747eea693dSMark Johnson blk_ring_response_put(blk_ring_t ring, blkif_response_t *src)
8757eea693dSMark Johnson {
876349b53ddSStuart Maybee 	blkif_response_t *rsp;
8777eea693dSMark Johnson 	int e;
8787eea693dSMark Johnson 
879349b53ddSStuart Maybee 
880349b53ddSStuart Maybee 	mutex_enter(&ring->ri_mutex);
881349b53ddSStuart Maybee 
882349b53ddSStuart Maybee 	if (ring->ri_if_status != BLK_IF_CONNECTED) {
883349b53ddSStuart Maybee 		mutex_exit(&ring->ri_mutex);
884349b53ddSStuart Maybee 		return;
885349b53ddSStuart Maybee 	}
886349b53ddSStuart Maybee 
887349b53ddSStuart Maybee 	rsp = xvdi_ring_get_response(ring->ri_ring);
8887eea693dSMark Johnson 	ASSERT(rsp);
8897eea693dSMark Johnson 
8907eea693dSMark Johnson 	switch (ring->ri_protocol) {
8917eea693dSMark Johnson 	case BLKIF_PROTOCOL_NATIVE:
8927eea693dSMark Johnson 		bcopy(src, rsp, sizeof (*rsp));
8937eea693dSMark Johnson 		break;
8947eea693dSMark Johnson 	case BLKIF_PROTOCOL_X86_32:
8957eea693dSMark Johnson 		blk_ring_response_32((blkif_x86_32_response_t *)rsp, src);
8967eea693dSMark Johnson 		break;
8977eea693dSMark Johnson 	case BLKIF_PROTOCOL_X86_64:
8987eea693dSMark Johnson 		blk_ring_response_64((blkif_x86_64_response_t *)rsp, src);
8997eea693dSMark Johnson 		break;
9007eea693dSMark Johnson 	default:
9017eea693dSMark Johnson 		cmn_err(CE_WARN, "blk@%s: unrecognised protocol: %d",
9027eea693dSMark Johnson 		    ddi_get_name_addr(ring->ri_dip),
9037eea693dSMark Johnson 		    ring->ri_protocol);
9047eea693dSMark Johnson 	}
9057eea693dSMark Johnson 
9067eea693dSMark Johnson 	e = xvdi_ring_push_response(ring->ri_ring);
9077eea693dSMark Johnson 	if (e != 0) {
9087eea693dSMark Johnson 		xvdi_notify_oe(ring->ri_dip);
9097eea693dSMark Johnson 	}
910349b53ddSStuart Maybee 
911349b53ddSStuart Maybee 	mutex_exit(&ring->ri_mutex);
9127eea693dSMark Johnson }
9137eea693dSMark Johnson 
9147eea693dSMark Johnson 
9157eea693dSMark Johnson /*
9167eea693dSMark Johnson  * blk_ring_request_32()
9177eea693dSMark Johnson  */
9187eea693dSMark Johnson static void
blk_ring_request_32(blkif_request_t * dst,blkif_x86_32_request_t * src)9197eea693dSMark Johnson blk_ring_request_32(blkif_request_t *dst, blkif_x86_32_request_t *src)
9207eea693dSMark Johnson {
9217eea693dSMark Johnson 	int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
9227eea693dSMark Johnson 	dst->operation = src->operation;
9237eea693dSMark Johnson 	dst->nr_segments = src->nr_segments;
9247eea693dSMark Johnson 	dst->handle = src->handle;
9257eea693dSMark Johnson 	dst->id = src->id;
9267eea693dSMark Johnson 	dst->sector_number = src->sector_number;
9277eea693dSMark Johnson 	if (n > src->nr_segments)
9287eea693dSMark Johnson 		n = src->nr_segments;
9297eea693dSMark Johnson 	for (i = 0; i < n; i++)
9307eea693dSMark Johnson 		dst->seg[i] = src->seg[i];
9317eea693dSMark Johnson }
9327eea693dSMark Johnson 
9337eea693dSMark Johnson 
9347eea693dSMark Johnson /*
9357eea693dSMark Johnson  * blk_ring_request_64()
9367eea693dSMark Johnson  */
9377eea693dSMark Johnson static void
blk_ring_request_64(blkif_request_t * dst,blkif_x86_64_request_t * src)9387eea693dSMark Johnson blk_ring_request_64(blkif_request_t *dst, blkif_x86_64_request_t *src)
9397eea693dSMark Johnson {
9407eea693dSMark Johnson 	int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
9417eea693dSMark Johnson 	dst->operation = src->operation;
9427eea693dSMark Johnson 	dst->nr_segments = src->nr_segments;
9437eea693dSMark Johnson 	dst->handle = src->handle;
9447eea693dSMark Johnson 	dst->id = src->id;
9457eea693dSMark Johnson 	dst->sector_number = src->sector_number;
9467eea693dSMark Johnson 	if (n > src->nr_segments)
9477eea693dSMark Johnson 		n = src->nr_segments;
9487eea693dSMark Johnson 	for (i = 0; i < n; i++)
9497eea693dSMark Johnson 		dst->seg[i] = src->seg[i];
9507eea693dSMark Johnson }
9517eea693dSMark Johnson 
9527eea693dSMark Johnson 
9537eea693dSMark Johnson /*
9547eea693dSMark Johnson  * blk_ring_response_32()
9557eea693dSMark Johnson  */
9567eea693dSMark Johnson static void
blk_ring_response_32(blkif_x86_32_response_t * dst,blkif_response_t * src)9577eea693dSMark Johnson blk_ring_response_32(blkif_x86_32_response_t *dst, blkif_response_t *src)
9587eea693dSMark Johnson {
9597eea693dSMark Johnson 	dst->id = src->id;
9607eea693dSMark Johnson 	dst->operation = src->operation;
9617eea693dSMark Johnson 	dst->status = src->status;
9627eea693dSMark Johnson }
9637eea693dSMark Johnson 
9647eea693dSMark Johnson 
9657eea693dSMark Johnson /*
9667eea693dSMark Johnson  * blk_ring_response_64()
9677eea693dSMark Johnson  */
9687eea693dSMark Johnson static void
blk_ring_response_64(blkif_x86_64_response_t * dst,blkif_response_t * src)9697eea693dSMark Johnson blk_ring_response_64(blkif_x86_64_response_t *dst, blkif_response_t *src)
9707eea693dSMark Johnson {
9717eea693dSMark Johnson 	dst->id = src->id;
9727eea693dSMark Johnson 	dst->operation = src->operation;
9737eea693dSMark Johnson 	dst->status = src->status;
9747eea693dSMark Johnson }
9757eea693dSMark Johnson 
9767eea693dSMark Johnson 
9777eea693dSMark Johnson /*
9787eea693dSMark Johnson  * blk_ring_request_dump()
9797eea693dSMark Johnson  */
9807eea693dSMark Johnson void
blk_ring_request_dump(blkif_request_t * req)9817eea693dSMark Johnson blk_ring_request_dump(blkif_request_t *req)
9827eea693dSMark Johnson {
9837eea693dSMark Johnson 	int i;
9847eea693dSMark Johnson 
9857eea693dSMark Johnson 	/*
9867eea693dSMark Johnson 	 * Exploit the public interface definitions for BLKIF_OP_READ
9877eea693dSMark Johnson 	 * etc..
9887eea693dSMark Johnson 	 */
9897eea693dSMark Johnson 	char *op_name[] = { "read", "write", "barrier", "flush" };
9907eea693dSMark Johnson 
9917eea693dSMark Johnson 	cmn_err(CE_NOTE, "   op=%s", op_name[req->operation]);
9927eea693dSMark Johnson 	cmn_err(CE_NOTE, "   num of segments=%d", req->nr_segments);
9937eea693dSMark Johnson 	cmn_err(CE_NOTE, "   handle=%d", req->handle);
9947eea693dSMark Johnson 	cmn_err(CE_NOTE, "   id=0x%llx", (unsigned long long)req->id);
9957eea693dSMark Johnson 	cmn_err(CE_NOTE, "   start sector=%llu",
9967eea693dSMark Johnson 	    (unsigned long long)req->sector_number);
9977eea693dSMark Johnson 	for (i = 0; i < req->nr_segments; i++) {
9987eea693dSMark Johnson 		cmn_err(CE_NOTE, "   gref=%d, first sec=%d,"
9997eea693dSMark Johnson 		    "last sec=%d", req->seg[i].gref, req->seg[i].first_sect,
10007eea693dSMark Johnson 		    req->seg[i].last_sect);
10017eea693dSMark Johnson 	}
10027eea693dSMark Johnson }
10037eea693dSMark Johnson 
10047eea693dSMark Johnson 
10057eea693dSMark Johnson /*
10067eea693dSMark Johnson  * blk_ring_response_dump()
10077eea693dSMark Johnson  */
10087eea693dSMark Johnson void
blk_ring_response_dump(blkif_response_t * resp)10097eea693dSMark Johnson blk_ring_response_dump(blkif_response_t *resp)
10107eea693dSMark Johnson {
10117eea693dSMark Johnson 	/*
10127eea693dSMark Johnson 	 * Exploit the public interface definitions for BLKIF_OP_READ
10137eea693dSMark Johnson 	 * etc..
10147eea693dSMark Johnson 	 */
10157eea693dSMark Johnson 	char *op_name[] = { "read", "write", "barrier", "flush" };
10167eea693dSMark Johnson 
10177eea693dSMark Johnson 	cmn_err(CE_NOTE, "   op=%d:%s", resp->operation,
10187eea693dSMark Johnson 	    op_name[resp->operation]);
10197eea693dSMark Johnson 	cmn_err(CE_NOTE, "   op=%d", resp->operation);
10207eea693dSMark Johnson 	cmn_err(CE_NOTE, "   status=%d", resp->status);
10217eea693dSMark Johnson }
1022