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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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