/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "blk_common.h" /* blk interface status */ enum blk_if_state { /* * initial state */ BLK_IF_UNKNOWN = 0, /* * frontend xenbus state changed to XenbusStateConnected, * we finally connect */ BLK_IF_CONNECTED, /* * frontend xenbus state changed to XenbusStateClosed, * interface disconnected */ BLK_IF_DISCONNECTED }; /* backend device status */ enum blk_be_state { /* initial state */ BLK_BE_UNKNOWN = 0, /* backend device is ready (hotplug script finishes successfully) */ BLK_BE_READY }; /* frontend status */ enum blk_fe_state { /* initial state */ BLK_FE_UNKNOWN = 0, /* * frontend's xenbus state has changed to * XenbusStateInitialised, is ready for connecting */ BLK_FE_READY }; typedef struct blk_ring_state_s { kmutex_t rs_mutex; boolean_t rs_sleeping_on_ring; boolean_t rs_ring_up; kcondvar_t rs_cv; } blk_ring_state_t; /* Disk Statistics */ static char *blk_stats[] = { "rd_reqs", "wr_reqs", "br_reqs", "fl_reqs", "oo_reqs" }; typedef struct blk_stats_s { uint64_t bs_req_reads; uint64_t bs_req_writes; uint64_t bs_req_barriers; uint64_t bs_req_flushes; } blk_stats_t; struct blk_ring_s { kmutex_t ri_mutex; dev_info_t *ri_dip; kstat_t *ri_kstats; blk_stats_t ri_stats; blk_intr_t ri_intr; caddr_t ri_intr_arg; blk_ring_cb_t ri_ringup; caddr_t ri_ringup_arg; blk_ring_cb_t ri_ringdown; caddr_t ri_ringdown_arg; /* blk interface, backend, and frontend status */ enum blk_if_state ri_if_status; enum blk_be_state ri_be_status; enum blk_fe_state ri_fe_status; domid_t ri_fe; enum blkif_protocol ri_protocol; size_t ri_nentry; size_t ri_entrysize; xendev_ring_t *ri_ring; blk_ring_state_t ri_state; }; static void blk_oe_state_change(dev_info_t *dip, ddi_eventcookie_t id, void *arg, void *impl_data); static void blk_hp_state_change(dev_info_t *dip, ddi_eventcookie_t id, void *arg, void *impl_data); static int blk_check_state_transition(blk_ring_t ring, XenbusState oestate); static int blk_start_connect(blk_ring_t ring); static void blk_start_disconnect(blk_ring_t ring); static void blk_ring_close(blk_ring_t ring); static int blk_bindto_frontend(blk_ring_t ring); static void blk_unbindfrom_frontend(blk_ring_t ring); static uint_t blk_intr(caddr_t arg); static int blk_kstat_init(blk_ring_t ring); static void blk_kstat_fini(blk_ring_t ring); static int blk_kstat_update(kstat_t *ksp, int flag); static void blk_ring_request_32(blkif_request_t *dst, blkif_x86_32_request_t *src); static void blk_ring_request_64(blkif_request_t *dst, blkif_x86_64_request_t *src); static void blk_ring_response_32(blkif_x86_32_response_t *dst, blkif_response_t *src); static void blk_ring_response_64(blkif_x86_64_response_t *dst, blkif_response_t *src); /* * blk_ring_init() */ int blk_ring_init(blk_ringinit_args_t *args, blk_ring_t *ringp) { blk_ring_t ring; int e; ring = kmem_zalloc(sizeof (struct blk_ring_s), KM_SLEEP); mutex_init(&ring->ri_mutex, NULL, MUTEX_DRIVER, NULL); ring->ri_dip = args->ar_dip; ring->ri_intr = args->ar_intr; ring->ri_intr_arg = args->ar_intr_arg; ring->ri_ringup = args->ar_ringup; ring->ri_ringup_arg = args->ar_ringup_arg; ring->ri_ringdown = args->ar_ringdown; ring->ri_ringdown_arg = args->ar_ringdown_arg; ring->ri_if_status = BLK_IF_UNKNOWN; ring->ri_be_status = BLK_BE_UNKNOWN; ring->ri_fe_status = BLK_FE_UNKNOWN; ring->ri_state.rs_sleeping_on_ring = B_FALSE; ring->ri_state.rs_ring_up = B_FALSE; mutex_init(&ring->ri_state.rs_mutex, NULL, MUTEX_DRIVER, NULL); cv_init(&ring->ri_state.rs_cv, NULL, CV_DRIVER, NULL); e = blk_kstat_init(ring); if (e != DDI_SUCCESS) { goto ringinitfail_kstat; } /* Watch frontend and hotplug state change */ if (xvdi_add_event_handler(ring->ri_dip, XS_OE_STATE, blk_oe_state_change, ring) != DDI_SUCCESS) { goto ringinitfail_oestate; } if (xvdi_add_event_handler(ring->ri_dip, XS_HP_STATE, blk_hp_state_change, ring) != DDI_SUCCESS) { goto ringinitfail_hpstate; } /* * Kick-off hotplug script */ if (xvdi_post_event(ring->ri_dip, XEN_HP_ADD) != DDI_SUCCESS) { cmn_err(CE_WARN, "blk@%s: failed to start hotplug script", ddi_get_name_addr(ring->ri_dip)); goto ringinitfail_postevent; } /* * start waiting for hotplug event and otherend state event * mainly for debugging, frontend will not take any op seeing this */ (void) xvdi_switch_state(ring->ri_dip, XBT_NULL, XenbusStateInitWait); *ringp = ring; return (DDI_SUCCESS); ringinitfail_postevent: xvdi_remove_event_handler(ring->ri_dip, XS_HP_STATE); ringinitfail_hpstate: xvdi_remove_event_handler(ring->ri_dip, XS_OE_STATE); ringinitfail_oestate: blk_kstat_fini(ring); ringinitfail_kstat: cv_destroy(&ring->ri_state.rs_cv); mutex_destroy(&ring->ri_state.rs_mutex); mutex_destroy(&ring->ri_mutex); kmem_free(ring, sizeof (struct blk_ring_s)); return (DDI_FAILURE); } /* * blk_ring_fini() */ void blk_ring_fini(blk_ring_t *ringp) { blk_ring_t ring; ring = *ringp; mutex_enter(&ring->ri_mutex); if (ring->ri_if_status != BLK_IF_DISCONNECTED) { blk_ring_close(ring); } mutex_exit(&ring->ri_mutex); xvdi_remove_event_handler(ring->ri_dip, NULL); blk_kstat_fini(ring); cv_destroy(&ring->ri_state.rs_cv); mutex_destroy(&ring->ri_state.rs_mutex); mutex_destroy(&ring->ri_mutex); kmem_free(ring, sizeof (struct blk_ring_s)); *ringp = NULL; } /* * blk_kstat_init() */ static int blk_kstat_init(blk_ring_t ring) { int nstat = sizeof (blk_stats) / sizeof (blk_stats[0]); char **cp = blk_stats; kstat_named_t *knp; ring->ri_kstats = kstat_create(ddi_get_name(ring->ri_dip), ddi_get_instance(ring->ri_dip), "req_statistics", "block", KSTAT_TYPE_NAMED, nstat, 0); if (ring->ri_kstats == NULL) { return (DDI_FAILURE); } ring->ri_kstats->ks_private = ring; ring->ri_kstats->ks_update = blk_kstat_update; knp = ring->ri_kstats->ks_data; while (nstat > 0) { kstat_named_init(knp, *cp, KSTAT_DATA_UINT64); knp++; cp++; nstat--; } kstat_install(ring->ri_kstats); return (DDI_SUCCESS); } /* * blk_kstat_fini() */ static void blk_kstat_fini(blk_ring_t ring) { kstat_delete(ring->ri_kstats); } /* * blk_kstat_update() */ static int blk_kstat_update(kstat_t *ksp, int flag) { kstat_named_t *knp; blk_stats_t *stats; blk_ring_t ring; if (flag != KSTAT_READ) { return (EACCES); } ring = ksp->ks_private; stats = &ring->ri_stats; knp = ksp->ks_data; /* * Assignment order should match that of the names in * blk_stats. */ (knp++)->value.ui64 = stats->bs_req_reads; (knp++)->value.ui64 = stats->bs_req_writes; (knp++)->value.ui64 = stats->bs_req_barriers; (knp++)->value.ui64 = stats->bs_req_flushes; (knp++)->value.ui64 = 0; /* oo_req */ return (0); } /* * blk_oe_state_change() */ /*ARGSUSED*/ static void blk_oe_state_change(dev_info_t *dip, ddi_eventcookie_t id, void *arg, void *impl_data) { XenbusState new_state; blk_ring_t ring; ring = (blk_ring_t)arg; new_state = *(XenbusState *)impl_data; mutex_enter(&ring->ri_mutex); if (blk_check_state_transition(ring, new_state) == DDI_FAILURE) { mutex_exit(&ring->ri_mutex); return; } switch (new_state) { case XenbusStateInitialised: ASSERT(ring->ri_if_status == BLK_IF_UNKNOWN); /* frontend is ready for connecting */ ring->ri_fe_status = BLK_FE_READY; if (ring->ri_be_status == BLK_BE_READY) { mutex_exit(&ring->ri_mutex); if (blk_start_connect(ring) != DDI_SUCCESS) (void) blk_start_disconnect(ring); mutex_enter(&ring->ri_mutex); } break; case XenbusStateClosing: (void) xvdi_switch_state(dip, XBT_NULL, XenbusStateClosing); break; case XenbusStateClosed: /* clean up */ (void) xvdi_post_event(ring->ri_dip, XEN_HP_REMOVE); if (ring->ri_ringdown != NULL) { (*(ring->ri_ringdown))(ring->ri_ringdown_arg); } blk_ring_close(ring); /* reset state in case of reconnect */ ring->ri_if_status = BLK_IF_UNKNOWN; ring->ri_be_status = BLK_BE_UNKNOWN; ring->ri_fe_status = BLK_FE_UNKNOWN; ring->ri_state.rs_sleeping_on_ring = B_FALSE; ring->ri_state.rs_ring_up = B_FALSE; break; default: ASSERT(0); } mutex_exit(&ring->ri_mutex); } /* * blk_hp_state_change() */ /*ARGSUSED*/ static void blk_hp_state_change(dev_info_t *dip, ddi_eventcookie_t id, void *arg, void *impl_data) { xendev_hotplug_state_t hpstate; blk_ring_t ring; ring = (blk_ring_t)arg; hpstate = *(xendev_hotplug_state_t *)impl_data; mutex_enter(&ring->ri_mutex); if (hpstate == Connected) { /* Hotplug script has completed successfully */ if (ring->ri_be_status == BLK_BE_UNKNOWN) { ring->ri_be_status = BLK_BE_READY; if (ring->ri_fe_status == BLK_FE_READY) { mutex_exit(&ring->ri_mutex); /* try to connect to frontend */ if (blk_start_connect(ring) != DDI_SUCCESS) (void) blk_start_disconnect(ring); mutex_enter(&ring->ri_mutex); } } } mutex_exit(&ring->ri_mutex); } /* * blk_check_state_transition() * check the XenbusState change to see if the change is a valid transition * or not. The new state is written by frontend domain, or by running * xenstore-write to change it manually in dom0. */ static int blk_check_state_transition(blk_ring_t ring, XenbusState oestate) { switch (ring->ri_if_status) { case BLK_IF_UNKNOWN: if (ring->ri_fe_status == BLK_FE_UNKNOWN) { if ((oestate == XenbusStateUnknown) || (oestate == XenbusStateConnected)) goto statechkfail_bug; else if ((oestate == XenbusStateInitialising) || (oestate == XenbusStateInitWait)) goto statechkfail_nop; } else { if ((oestate == XenbusStateUnknown) || (oestate == XenbusStateInitialising) || (oestate == XenbusStateInitWait) || (oestate == XenbusStateConnected)) goto statechkfail_bug; else if (oestate == XenbusStateInitialised) goto statechkfail_nop; } break; case BLK_IF_CONNECTED: if ((oestate == XenbusStateUnknown) || (oestate == XenbusStateInitialising) || (oestate == XenbusStateInitWait) || (oestate == XenbusStateInitialised)) goto statechkfail_bug; else if (oestate == XenbusStateConnected) goto statechkfail_nop; break; case BLK_IF_DISCONNECTED: default: goto statechkfail_bug; } return (DDI_SUCCESS); statechkfail_bug: cmn_err(CE_NOTE, "blk@%s: unexpected otherend " "state change to %d!, when status is %d", ddi_get_name_addr(ring->ri_dip), oestate, ring->ri_if_status); statechkfail_nop: return (DDI_FAILURE); } /* * blk_start_connect() * Kick-off connect process * If ri_fe_status == BLK_FE_READY and ri_be_status == BLK_BE_READY * the ri_if_status will be changed to BLK_IF_CONNECTED on success, * otherwise, ri_if_status will not be changed */ static int blk_start_connect(blk_ring_t ring) { xenbus_transaction_t xbt; dev_info_t *dip; char *barrier; char *xsnode; uint_t len; int e; dip = ring->ri_dip; /* * Start connect to frontend only when backend device are ready * and frontend has moved to XenbusStateInitialised, which means * ready to connect */ ASSERT(ring->ri_fe_status == BLK_FE_READY); ASSERT(ring->ri_be_status == BLK_BE_READY); xsnode = xvdi_get_xsname(dip); if (xsnode == NULL) { goto startconnectfail_get_xsname; } ring->ri_fe = xvdi_get_oeid(dip); if (ring->ri_fe == (domid_t)-1) { goto startconnectfail_get_oeid; } e = xvdi_switch_state(dip, XBT_NULL, XenbusStateInitialised); if (e > 0) { goto startconnectfail_switch_init; } e = blk_bindto_frontend(ring); if (e != DDI_SUCCESS) { goto startconnectfail_bindto_frontend; } ring->ri_if_status = BLK_IF_CONNECTED; e = ddi_add_intr(dip, 0, NULL, NULL, blk_intr, (caddr_t)ring); if (e != DDI_SUCCESS) { goto startconnectfail_add_intr; } trans_retry: e = xenbus_transaction_start(&xbt); if (e != 0) { xvdi_fatal_error(dip, e, "transaction start"); goto startconnectfail_transaction_start; } /* xentop requires the instance in xenstore */ e = xenbus_printf(xbt, xsnode, "instance", "%d", ddi_get_instance(ring->ri_dip)); if (e != 0) { cmn_err(CE_WARN, "xdb@%s: failed to write 'instance'", ddi_get_name_addr(dip)); xvdi_fatal_error(dip, e, "writing 'instance'"); (void) xenbus_transaction_end(xbt, 1); goto startconnectfail_xenbus_printf; } /* If feature-barrier isn't present in xenstore, add it */ e = xenbus_read(xbt, xsnode, "feature-barrier", (void **)&barrier, &len); if (e != 0) { e = xenbus_printf(xbt, xsnode, "feature-barrier", "%d", 1); if (e != 0) { cmn_err(CE_WARN, "xdb@%s: failed to write " "'feature-barrier'", ddi_get_name_addr(dip)); xvdi_fatal_error(dip, e, "writing 'feature-barrier'"); (void) xenbus_transaction_end(xbt, 1); goto startconnectfail_xenbus_printf; } } else { kmem_free(barrier, len); } e = xvdi_switch_state(dip, xbt, XenbusStateConnected); if (e > 0) { xvdi_fatal_error(dip, e, "writing 'state'"); (void) xenbus_transaction_end(xbt, 1); goto startconnectfail_switch_connected; } e = xenbus_transaction_end(xbt, 0); if (e != 0) { if (e == EAGAIN) { /* transaction is ended, don't need to abort it */ goto trans_retry; } xvdi_fatal_error(dip, e, "completing transaction"); goto startconnectfail_transaction_end; } mutex_enter(&ring->ri_state.rs_mutex); ring->ri_state.rs_ring_up = B_TRUE; if (ring->ri_state.rs_sleeping_on_ring) { ring->ri_state.rs_sleeping_on_ring = B_FALSE; cv_signal(&ring->ri_state.rs_cv); } mutex_exit(&ring->ri_state.rs_mutex); if (ring->ri_ringup != NULL) { (*(ring->ri_ringup))(ring->ri_ringup_arg); } return (DDI_SUCCESS); startconnectfail_transaction_end: startconnectfail_switch_connected: startconnectfail_xenbus_printf: startconnectfail_transaction_start: ddi_remove_intr(dip, 0, NULL); startconnectfail_add_intr: blk_unbindfrom_frontend(ring); ring->ri_fe = (domid_t)-1; startconnectfail_bindto_frontend: (void) xvdi_switch_state(dip, XBT_NULL, XenbusStateClosed); startconnectfail_switch_init: startconnectfail_get_oeid: startconnectfail_get_xsname: return (DDI_FAILURE); } /* * blk_start_disconnect() * Kick-off disconnect process. ri_if_status will not be changed */ static void blk_start_disconnect(blk_ring_t ring) { /* Kick-off disconnect process */ (void) xvdi_switch_state(ring->ri_dip, XBT_NULL, XenbusStateClosing); } /* * blk_ring_close() * Disconnect from frontend and close backend device * ifstatus will be changed to BLK_DISCONNECTED * Xenbus state will be changed to XenbusStateClosed */ static void blk_ring_close(blk_ring_t ring) { dev_info_t *dip; /* mutex protect ri_if_status only here */ ASSERT(MUTEX_HELD(&ring->ri_mutex)); dip = ring->ri_dip; if (ring->ri_if_status != BLK_IF_CONNECTED) { return; } ring->ri_if_status = BLK_IF_DISCONNECTED; mutex_exit(&ring->ri_mutex); /* stop accepting I/O request from frontend */ ddi_remove_intr(dip, 0, NULL); blk_unbindfrom_frontend(ring); ring->ri_fe = (domid_t)-1; (void) xvdi_switch_state(dip, XBT_NULL, XenbusStateClosed); mutex_enter(&ring->ri_mutex); } /* * blk_bindto_frontend() */ static int blk_bindto_frontend(blk_ring_t ring) { evtchn_port_t evtchn; char protocol[64]; grant_ref_t gref; dev_info_t *dip; char *oename; int e; dip = ring->ri_dip; protocol[0] = 0x0; /* * Gather info from frontend */ oename = xvdi_get_oename(dip); if (oename == NULL) { return (DDI_FAILURE); } e = xenbus_gather(XBT_NULL, oename, "ring-ref", "%lu", &gref, "event-channel", "%u", &evtchn, NULL); if (e != 0) { xvdi_fatal_error(dip, e, "Getting ring-ref and evtchn from frontend"); return (DDI_FAILURE); } e = xenbus_gather(XBT_NULL, oename, "protocol", "%63s", protocol, NULL); if (e != 0) { (void) strcpy(protocol, "unspecified, assuming native"); } else if (strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE) == 0) { ring->ri_protocol = BLKIF_PROTOCOL_NATIVE; ring->ri_nentry = BLKIF_RING_SIZE; ring->ri_entrysize = sizeof (union blkif_sring_entry); } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) { ring->ri_protocol = BLKIF_PROTOCOL_X86_32; ring->ri_nentry = BLKIF_X86_32_RING_SIZE; ring->ri_entrysize = sizeof (union blkif_x86_32_sring_entry); } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) { ring->ri_protocol = BLKIF_PROTOCOL_X86_64; ring->ri_nentry = BLKIF_X86_64_RING_SIZE; ring->ri_entrysize = sizeof (union blkif_x86_64_sring_entry); } else { xvdi_fatal_error(dip, e, "unknown fe protocol"); return (DDI_FAILURE); } /* * map and init ring */ e = xvdi_map_ring(dip, ring->ri_nentry, ring->ri_entrysize, gref, &ring->ri_ring); if (e != DDI_SUCCESS) { return (DDI_FAILURE); } /* * bind event channel */ e = xvdi_bind_evtchn(dip, evtchn); if (e != DDI_SUCCESS) { xvdi_unmap_ring(ring->ri_ring); return (DDI_FAILURE); } return (DDI_SUCCESS); } /* * blk_unbindfrom_frontend() */ static void blk_unbindfrom_frontend(blk_ring_t ring) { xvdi_free_evtchn(ring->ri_dip); xvdi_unmap_ring(ring->ri_ring); } /* * blk_intr() */ static uint_t blk_intr(caddr_t arg) { blk_ring_t ring; ring = (blk_ring_t)arg; if (ring->ri_if_status != BLK_IF_CONNECTED) { return (DDI_INTR_CLAIMED); } (void) (*ring->ri_intr)(ring->ri_intr_arg); return (DDI_INTR_CLAIMED); } /* * blk_ring_request_get() */ boolean_t blk_ring_request_get(blk_ring_t ring, blkif_request_t *req) { blkif_request_t *src; blk_stats_t *stats; mutex_enter(&ring->ri_mutex); if (ring->ri_if_status != BLK_IF_CONNECTED) { mutex_exit(&ring->ri_mutex); return (B_FALSE); } src = xvdi_ring_get_request(ring->ri_ring); if (src == NULL) { mutex_exit(&ring->ri_mutex); return (B_FALSE); } switch (ring->ri_protocol) { case BLKIF_PROTOCOL_NATIVE: bcopy(src, req, sizeof (*req)); break; case BLKIF_PROTOCOL_X86_32: blk_ring_request_32(req, (blkif_x86_32_request_t *)src); break; case BLKIF_PROTOCOL_X86_64: blk_ring_request_64(req, (blkif_x86_64_request_t *)src); break; default: cmn_err(CE_WARN, "blkif@%s: unrecognised protocol: %d", ddi_get_name_addr(ring->ri_dip), ring->ri_protocol); } mutex_exit(&ring->ri_mutex); stats = &ring->ri_stats; switch (req->operation) { case BLKIF_OP_READ: stats->bs_req_reads++; break; case BLKIF_OP_WRITE: stats->bs_req_writes++; break; case BLKIF_OP_WRITE_BARRIER: stats->bs_req_barriers++; break; case BLKIF_OP_FLUSH_DISKCACHE: stats->bs_req_flushes++; break; } return (B_TRUE); } /* * blk_ring_request_requeue() * if a request is requeued, caller will have to poll for request * later. */ void blk_ring_request_requeue(blk_ring_t ring) { mutex_enter(&ring->ri_mutex); if (ring->ri_if_status != BLK_IF_CONNECTED) { mutex_exit(&ring->ri_mutex); return; } ring->ri_ring->xr_sring.br.req_cons--; mutex_exit(&ring->ri_mutex); } /* * blk_ring_response_put() */ void blk_ring_response_put(blk_ring_t ring, blkif_response_t *src) { blkif_response_t *rsp; int e; mutex_enter(&ring->ri_mutex); if (ring->ri_if_status != BLK_IF_CONNECTED) { mutex_exit(&ring->ri_mutex); return; } rsp = xvdi_ring_get_response(ring->ri_ring); ASSERT(rsp); switch (ring->ri_protocol) { case BLKIF_PROTOCOL_NATIVE: bcopy(src, rsp, sizeof (*rsp)); break; case BLKIF_PROTOCOL_X86_32: blk_ring_response_32((blkif_x86_32_response_t *)rsp, src); break; case BLKIF_PROTOCOL_X86_64: blk_ring_response_64((blkif_x86_64_response_t *)rsp, src); break; default: cmn_err(CE_WARN, "blk@%s: unrecognised protocol: %d", ddi_get_name_addr(ring->ri_dip), ring->ri_protocol); } e = xvdi_ring_push_response(ring->ri_ring); if (e != 0) { xvdi_notify_oe(ring->ri_dip); } mutex_exit(&ring->ri_mutex); } /* * blk_ring_request_32() */ static void blk_ring_request_32(blkif_request_t *dst, blkif_x86_32_request_t *src) { int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST; dst->operation = src->operation; dst->nr_segments = src->nr_segments; dst->handle = src->handle; dst->id = src->id; dst->sector_number = src->sector_number; if (n > src->nr_segments) n = src->nr_segments; for (i = 0; i < n; i++) dst->seg[i] = src->seg[i]; } /* * blk_ring_request_64() */ static void blk_ring_request_64(blkif_request_t *dst, blkif_x86_64_request_t *src) { int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST; dst->operation = src->operation; dst->nr_segments = src->nr_segments; dst->handle = src->handle; dst->id = src->id; dst->sector_number = src->sector_number; if (n > src->nr_segments) n = src->nr_segments; for (i = 0; i < n; i++) dst->seg[i] = src->seg[i]; } /* * blk_ring_response_32() */ static void blk_ring_response_32(blkif_x86_32_response_t *dst, blkif_response_t *src) { dst->id = src->id; dst->operation = src->operation; dst->status = src->status; } /* * blk_ring_response_64() */ static void blk_ring_response_64(blkif_x86_64_response_t *dst, blkif_response_t *src) { dst->id = src->id; dst->operation = src->operation; dst->status = src->status; } /* * blk_ring_request_dump() */ void blk_ring_request_dump(blkif_request_t *req) { int i; /* * Exploit the public interface definitions for BLKIF_OP_READ * etc.. */ char *op_name[] = { "read", "write", "barrier", "flush" }; cmn_err(CE_NOTE, " op=%s", op_name[req->operation]); cmn_err(CE_NOTE, " num of segments=%d", req->nr_segments); cmn_err(CE_NOTE, " handle=%d", req->handle); cmn_err(CE_NOTE, " id=0x%llx", (unsigned long long)req->id); cmn_err(CE_NOTE, " start sector=%llu", (unsigned long long)req->sector_number); for (i = 0; i < req->nr_segments; i++) { cmn_err(CE_NOTE, " gref=%d, first sec=%d," "last sec=%d", req->seg[i].gref, req->seg[i].first_sect, req->seg[i].last_sect); } } /* * blk_ring_response_dump() */ void blk_ring_response_dump(blkif_response_t *resp) { /* * Exploit the public interface definitions for BLKIF_OP_READ * etc.. */ char *op_name[] = { "read", "write", "barrier", "flush" }; cmn_err(CE_NOTE, " op=%d:%s", resp->operation, op_name[resp->operation]); cmn_err(CE_NOTE, " op=%d", resp->operation); cmn_err(CE_NOTE, " status=%d", resp->status); }