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