diff -r 37cde7841498 -r d2703777cccb linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile --- a/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Thu Nov 24 16:28:47 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Thu Nov 24 18:30:37 2005 @@ -11,3 +11,4 @@ xenidc-objs += xenidc_grant_table.o xenidc-objs += xenidc_vaddress.o xenidc-objs += xenidc_gnttab_channel.o +xenidc-objs += xenidc_xbgt_channel.o diff -r 37cde7841498 -r d2703777cccb linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel.c --- /dev/null Thu Nov 24 16:28:47 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel.c Thu Nov 24 18:30:37 2005 @@ -0,0 +1,1303 @@ +/*****************************************************************************/ +/* This is a class which uses a xenidc_gnttab_channel (grant-tables based */ +/* message channel class) and xenbus to implement an interdomain message */ +/* channel with grant-tables based message transfer and xenbus based */ +/* bring-up and tear-down handshaking. */ +/* This class is used in the implementation of the xenidc_endpoint class. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* The state machine below makes the following assumptions: */ +/* */ +/* 1) The store might contain some stale cruft from the last time our device */ +/* driver failed. This is a handy assumption for testing new versions of */ +/* the driver but isn't strictly necessary. */ +/* */ +/* 2) If the other side generates a protocol error on the inter-domain */ +/* connection then we attempt to disconnect and reconnect. An alternative */ +/* behaviour would be to wait for our interface to be called to disconnect */ +/* and then reconnect before retrying. */ +/* */ +/* 3) If we experience an internal failure (fail to register watch for */ +/* example) then we attempt to disconnect and wait for our interface to be */ +/* called to disconnect (by module unload for example) and reconnect before */ +/* retrying. */ +/* */ +/* 4) Connection and disconnection of the channel is done in two phases: the */ +/* first phase makes the local resources available to the remote side, the */ +/* second phase uses the resources of the remote side to complete the */ +/* connection. */ +/* */ +/* The key for the stimuli is as follows: */ +/* */ +/* cn: interface called to connect the channel when interface state is */ +/* disconnected (for example on module load). */ +/* */ +/* pe: protocol error detected when channel is in a state between phase two */ +/* connected and the completion of the phase two disconnect callback. */ +/* */ +/* dn: interface called to disconnect the channel when the interface state */ +/* is connected (for example on module unload). */ +/* */ +/* ou: a synchronous stimulus from the response test_other_state which */ +/* indicates that the other state is still unknown because the watch */ +/* callback hasn't happened yet. Can only happen when making the response */ +/* test_other_state. */ +/* */ +/* od: other state is disconnected. This is both a synchronous stimulus */ +/* from test_other_state and an asynchronous stimulus from the watch */ +/* function. Disconnected means that we can't read at least the other side's */ +/* ready node from the store. */ +/* */ +/* or: other state is ready. This is both a synchronous stimulus from */ +/* test_other_state and an asynchronous stimulus from the watch function. */ +/* Ready means that we can see the other side's ready node but not the */ +/* ring-reference and event-channel information. */ +/* */ +/* oc: other state is connected. This is both a synchronous stimulus from */ +/* test_other_state and an asynchronous stimulus from the watch function. */ +/* Connected means that we found both the ready node and the connected */ +/* information in the store. */ +/* */ +/* If the values of the connected information change when the other side is */ +/* connected then we generate the 'oc' stimulus again which forces a */ +/* reconnect. */ +/* */ +/* rs: An asynchronous response was successful (we only make one response at */ +/* a time so all asynchronous responses have the same completion stimuli). */ +/* */ +/* rf: An asynchronous response failed. Only register_watch, clear_store, */ +/* write_ready, write_connected, phase_two_connect can fail. Only */ +/* phase_two_connect has a good reason for failure: the other side might */ +/* have passed bogus parameters; the other failures are poor API design and */ +/* ought to be promoted to domain failures. */ +/* */ +/* The state machine responses are as follows: */ +/* */ +/* test_other_state: what state do we currently think the other side is in */ +/* as reflected by the last watch event. Synchronous (called with the lock */ +/* held) completes with ou/od/or/oc. */ +/* */ +/* register_watch: register a watch on the other side. */ +/* */ +/* unregister_watch: unregister the watch. */ +/* */ +/* clear_store: remove the ready node and connected information. */ +/* */ +/* write_ready: write the ready node to the store. */ +/* */ +/* write_connected: write the connected information to the store. */ +/* */ +/* phase_one_connect: grant the remote side access to the local page etc. */ +/* */ +/* phase_two_connect: map the remote page etc. */ +/* */ +/* phase_two_disconnect: unmap the remote page. */ +/* */ +/* phase_one_disconnect: revoke the access of the remote side. */ +/* */ +/* complete_disconnect: When our interface is called to get us to disconnect */ +/* the channel we quiesce and disconnect and then call this to indicate we */ +/* are done. */ +/* */ +/*****************************************************************************/ + +#include +#include +#include "xenidc_trace.h" + +typedef enum { + xenidc_xbgt_channel_stimulus_cn,/* Connect: disconnected */ + xenidc_xbgt_channel_stimulus_pe,/* P.col err: ph2c->ph2dc inclusive */ + xenidc_xbgt_channel_stimulus_dn,/* Disconnect: connected */ + xenidc_xbgt_channel_stimulus_ou,/* Other unknown: test other only */ + xenidc_xbgt_channel_stimulus_od,/* Other disconnected: watch / test */ + xenidc_xbgt_channel_stimulus_or,/* Other ready: watch / test */ + xenidc_xbgt_channel_stimulus_oc,/* Other connected: watch / test */ + xenidc_xbgt_channel_stimulus_rs,/* Resp. successful: making response */ + xenidc_xbgt_channel_stimulus_rf /* Resp. failed: r. watch, tra, ph2c */ +} xenidc_xbgt_channel_stimulus; + +static void +xenidc_xbgt_channel_handle_stimulus(struct xenidc_xbgt_channel *channel, +xenidc_xbgt_channel_stimulus stimulus); + +static int +xenidc_xbgt_channel_init_or_exit(struct xenidc_xbgt_channel *channel, +int exit); + +int xenidc_xbgt_channel_init(struct xenidc_xbgt_channel *channel) +{ + return xenidc_xbgt_channel_init_or_exit(channel, 0); +} + +void +xenidc_xbgt_channel_connect(struct xenidc_xbgt_channel *channel, +const char *local_path, const char *remote_path, domid_t remote_domain_id) +{ + unsigned long flags; + trace(); + spin_lock_irqsave(&channel->lock, flags); + channel->local_path = local_path; + channel->remote_path = remote_path; + channel->remote_domain_id = remote_domain_id; + xenidc_xbgt_channel_handle_stimulus(channel, + xenidc_xbgt_channel_stimulus_cn); + spin_unlock_irqrestore(&channel->lock, flags); +} + +static void +xenidc_xbgt_channel_watch(struct xenbus_watch *watch, const char **vec, +unsigned int len) +{ + struct xenidc_xbgt_channel *channel = + container_of(watch, struct xenidc_xbgt_channel, watch); + struct xenbus_transaction *transaction; + unsigned int event_channel, ring_reference, ready; + int error; + unsigned long flags; + trace(); + transaction = xenbus_transaction_start(); + if (IS_ERR(transaction)) { + trace_info("error starting transaction"); + goto disconnected; + } + error = xenbus_gather(transaction, watch->node, "ready", "%u", &ready, + "event-channel", "%u", &event_channel, + "ring-reference", "%u", &ring_reference, NULL); + if (error == 0) { + spin_lock_irqsave(&channel->lock, flags); + if ((channel->other_state != + xenidc_xbgt_channel_other_state_connected) || + (channel->ready_event_channel != event_channel) || + (channel->ready_ring_reference != ring_reference)) { + channel->other_state = + xenidc_xbgt_channel_other_state_connected; + channel->ready_event_channel = event_channel; + channel->ready_ring_reference = ring_reference; + xenidc_xbgt_channel_handle_stimulus(channel, + xenidc_xbgt_channel_stimulus_oc); + } + spin_unlock_irqrestore(&channel->lock, flags); + xenbus_transaction_end(transaction, 1 /* abort */ ); + return; + } + error = xenbus_gather(transaction, watch->node, "ready", "%u", &ready, + NULL); + if (error == 0) { + spin_lock_irqsave(&channel->lock, flags); + if ((channel->other_state != + xenidc_xbgt_channel_other_state_ready)) { + channel->other_state = + xenidc_xbgt_channel_other_state_ready; + xenidc_xbgt_channel_handle_stimulus(channel, + xenidc_xbgt_channel_stimulus_or); + } + spin_unlock_irqrestore(&channel->lock, flags); + xenbus_transaction_end(transaction, 1 /* abort */ ); + return; + } + xenbus_transaction_end(transaction, 1 /* abort */ ); + disconnected: + spin_lock_irqsave(&channel->lock, flags); + if (channel->other_state != + xenidc_xbgt_channel_other_state_disconnected) { + channel->other_state = + xenidc_xbgt_channel_other_state_disconnected; + xenidc_xbgt_channel_handle_stimulus(channel, + xenidc_xbgt_channel_stimulus_od); + } + spin_unlock_irqrestore(&channel->lock, flags); +} + +static void +xenidc_xbgt_channel_protocol_error( +struct xenidc_gnttab_channel *gnttab_channel) { + struct xenidc_xbgt_channel *channel = + xenidc_xbgt_channel_gnttab_channel_to(gnttab_channel); + unsigned long flags; + trace(); + spin_lock_irqsave(&channel->lock, flags); + xenidc_xbgt_channel_handle_stimulus(channel, + xenidc_xbgt_channel_stimulus_pe); + spin_unlock_irqrestore(&channel->lock, flags); +} + +void +xenidc_xbgt_channel_disconnect(struct xenidc_xbgt_channel *channel, +struct xenidc_callback *callback) +{ + unsigned long flags; + trace(); + spin_lock_irqsave(&channel->lock, flags); + channel->disconnect_callback = callback; + xenidc_xbgt_channel_handle_stimulus(channel, + xenidc_xbgt_channel_stimulus_dn); + spin_unlock_irqrestore(&channel->lock, flags); +} + +void +xenidc_xbgt_channel_exit(struct xenidc_xbgt_channel *channel) +{ + trace(); + (void)xenidc_xbgt_channel_init_or_exit(channel, 1); +} + +static void xenidc_xbgt_channel_register_watch_1(void *data); +static void xenidc_xbgt_channel_unregister_watch_1(void *data); +static void xenidc_xbgt_channel_clear_store_1(void *data); +static void xenidc_xbgt_channel_write_ready_1(void *data); +static void xenidc_xbgt_channel_write_connected_1(void *data); +static void xenidc_xbgt_channel_phase_one_connect_1(void *data); +static void +xenidc_xbgt_channel_phase_one_connect_2(struct xenidc_callback *callback); +static void xenidc_xbgt_channel_phase_two_connect_1(void *data); +static void +xenidc_xbgt_channel_phase_two_connect_2(struct xenidc_callback *callback); +static void xenidc_xbgt_channel_phase_two_disconnect_1(void *data); +static void +xenidc_xbgt_channel_phase_two_disconnect_2(struct xenidc_callback *callback); +static void xenidc_xbgt_channel_phase_one_disconnect_1(void *data); +static void +xenidc_xbgt_channel_phase_one_disconnect_2(struct xenidc_callback *callback); + +static int +xenidc_xbgt_channel_init_or_exit(struct xenidc_xbgt_channel *channel, +int exit) +{ + int return_value = 0; + trace(); + if (exit) + goto exit_path; + if ((return_value = xenidc_gnttab_channel_init(&channel->channel, + xenidc_xbgt_channel_protocol_error)) != 0) { + goto exit_no_gnttab_channel; + } + spin_lock_init(&channel->lock); + channel->state = xenidc_xbgt_channel_state_i; + xenidc_work_init(&channel->register_watch_1_work, + xenidc_xbgt_channel_register_watch_1, channel); + xenidc_work_init(&channel->unregister_watch_1_work, + xenidc_xbgt_channel_unregister_watch_1, channel); + xenidc_work_init(&channel->clear_store_1_work, + xenidc_xbgt_channel_clear_store_1, channel); + xenidc_work_init(&channel->write_ready_1_work, + xenidc_xbgt_channel_write_ready_1, channel); + xenidc_work_init(&channel->write_connected_1_work, + xenidc_xbgt_channel_write_connected_1, channel); + xenidc_work_init(&channel->phase_one_connect_1_work, + xenidc_xbgt_channel_phase_one_connect_1, channel); + xenidc_work_init(&channel->phase_two_connect_1_work, + xenidc_xbgt_channel_phase_two_connect_1, channel); + xenidc_work_init(&channel->phase_two_disconnect_1_work, + xenidc_xbgt_channel_phase_two_disconnect_1, channel); + xenidc_work_init(&channel->phase_one_disconnect_1_work, + xenidc_xbgt_channel_phase_one_disconnect_1, channel); + xenidc_callback_init(&channel->phase_one_connect_request.callback, + xenidc_xbgt_channel_phase_one_connect_2); + xenidc_callback_init(&channel->phase_two_connect_request.callback, + xenidc_xbgt_channel_phase_two_connect_2); + xenidc_callback_init(&channel->phase_two_disconnect_callback, + xenidc_xbgt_channel_phase_two_disconnect_2); + xenidc_callback_init(&channel->phase_one_disconnect_callback, + xenidc_xbgt_channel_phase_one_disconnect_2); + return 0; + exit_path: + xenidc_gnttab_channel_exit(&channel->channel); + exit_no_gnttab_channel: + return return_value; +} + +static void +xenidc_xbgt_channel_invalid_stimulus(struct xenidc_xbgt_channel *channel, +xenidc_xbgt_channel_stimulus stimulus); +static void +xenidc_xbgt_channel_test_other_state(struct xenidc_xbgt_channel *channel); +static void +xenidc_xbgt_channel_register_watch(struct xenidc_xbgt_channel *channel); +static void +xenidc_xbgt_channel_unregister_watch(struct xenidc_xbgt_channel *channel); +static void +xenidc_xbgt_channel_clear_store(struct xenidc_xbgt_channel *channel); +static void +xenidc_xbgt_channel_write_ready(struct xenidc_xbgt_channel *channel); +static void +xenidc_xbgt_channel_write_connected(struct xenidc_xbgt_channel *channel); +static void +xenidc_xbgt_channel_phase_one_connect(struct xenidc_xbgt_channel *channel); +static void +xenidc_xbgt_channel_phase_two_connect(struct xenidc_xbgt_channel *channel); +static void +xenidc_xbgt_channel_phase_two_disconnect(struct xenidc_xbgt_channel *channel); +static void +xenidc_xbgt_channel_phase_one_disconnect(struct xenidc_xbgt_channel *channel); +static void +xenidc_xbgt_channel_complete_disconnect(struct xenidc_xbgt_channel *channel); + +static void +xenidc_xbgt_channel_handle_stimulus(struct xenidc_xbgt_channel *channel, +xenidc_xbgt_channel_stimulus stimulus) { + trace_info("xbgt channel %p in state %d received stimulus %d", channel, + channel->state, stimulus); + switch (channel->state) { + case xenidc_xbgt_channel_state_i: + /* Interface disconnected. */ + /* Gnttab channel disconnected. */ + /* Local store unknown. */ + /* Watch not registered. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_cn: + channel->state = xenidc_xbgt_channel_state_i_cn; + xenidc_xbgt_channel_phase_one_connect(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn: + /* Interface connected. */ + /* Gnttab channel phase one connecting. */ + /* Local store unknown. */ + /* Watch not registered. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = xenidc_xbgt_channel_state_i_cn_dn; + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = xenidc_xbgt_channel_state_i_cn_rs; + xenidc_xbgt_channel_register_watch(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_dn: + /* Interface disconnecting. */ + /* Gnttab channel phase one connecting */ + /* Local store unknown. */ + /* Watch not registered. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_rs: + channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs; + xenidc_xbgt_channel_clear_store(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs: + /* Interface connected. */ + /* Gnttab channel phase one connected and registering watch */ + /* or watch registered and gnttab channel phase two */ + /* disconnecting. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_pe: + break; + case xenidc_xbgt_channel_stimulus_dn: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn; + break; + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs; + xenidc_xbgt_channel_clear_store(channel); + break; + case xenidc_xbgt_channel_stimulus_rf: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rf; + xenidc_xbgt_channel_clear_store(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_dn_rs: + /* Interface disconnecting. */ + /* Gnttab channel phase one connected */ + /* Clearing store. */ + /* Watch not registered. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_rs: + case xenidc_xbgt_channel_stimulus_rf: + channel->state = + xenidc_xbgt_channel_state_i_cn_dn_rs_rs; + xenidc_xbgt_channel_phase_one_disconnect(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_dn: + /* Interface disconnecting. */ + /* Gnttab channel phase one connected. */ + /* Local store unknown. */ + /* Registering watch. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_dn_rs; + xenidc_xbgt_channel_unregister_watch(channel); + break; + case xenidc_xbgt_channel_stimulus_rf: + channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs; + xenidc_xbgt_channel_clear_store(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs: + /* Interface connected. */ + /* Gnttab channel phase one connected. */ + /* Clearing Store. */ + /* Watch Registered. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_dn; + break; + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rs; + xenidc_xbgt_channel_test_other_state(channel); + break; + case xenidc_xbgt_channel_stimulus_rf: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rf; + xenidc_xbgt_channel_unregister_watch(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rf: + /* Interface connected. */ + /* Gnttab channel phase one connected. */ + /* Clearing store. */ + /* Something failed. */ + /* Watch not registered. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs; + break; + case xenidc_xbgt_channel_stimulus_rs: + case xenidc_xbgt_channel_stimulus_rf: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rf_rs; + xenidc_xbgt_channel_phase_one_disconnect(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_dn_rs_rs: + /* Interface disconnecting. */ + /* Gnttab channel phase one disconnecting */ + /* Attempted to clear store. */ + /* Watch not registered. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_rs: + channel->state = xenidc_xbgt_channel_state_i; + xenidc_xbgt_channel_complete_disconnect(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_dn_rs: + /* Interface disconnecting. */ + /* Gnttab channel phase one connected. */ + /* Local store unknown. */ + /* Unregistering watch. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs; + xenidc_xbgt_channel_clear_store(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_dn: + /* Interface disconnecting. */ + /* Gnttab channel phase one connected unless */ + /* ph2 disconnecting below. */ + /* Clearing Store / writing ready / writing connected / ... */ + /* ... ph2 disconnecting */ + /* Watch Registered. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_pe: + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + break; + case xenidc_xbgt_channel_stimulus_rs: + case xenidc_xbgt_channel_stimulus_rf: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_dn_rs; + xenidc_xbgt_channel_unregister_watch(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_rs: + /* Interface connected. */ + /* Gnttab channel phase one connected. */ + /* Store clear. */ + /* Watch Registered. */ + /* Testing other state / other state unknown/connected */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_dn_rs; + xenidc_xbgt_channel_unregister_watch(channel); + break; + case xenidc_xbgt_channel_stimulus_ou: + break; + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od; + xenidc_xbgt_channel_write_ready(channel); + break; + case xenidc_xbgt_channel_stimulus_oc: + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_rf: + /* Interface connected. */ + /* Gnttab channel phase one connected. */ + /* Unregistering watch. */ + /* Something failed. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_dn_rs; + break; + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rf; + xenidc_xbgt_channel_clear_store(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rf_rs: + /* Interface connected. */ + /* Gnttab channel phase one disconnecting. */ + /* Attempted to clear store. */ + /* Something failed. */ + /* Watch not registered. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = + xenidc_xbgt_channel_state_i_cn_dn_rs_rs; + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rf_rs_rs; + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od: + /* Interface connected. */ + /* Gnttab channel phase one connected. */ + /* Writing Ready. */ + /* Watch Registered. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_dn; + break; + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs; + xenidc_xbgt_channel_test_other_state(channel); + break; + case xenidc_xbgt_channel_stimulus_rf: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rf; + xenidc_xbgt_channel_unregister_watch(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rf_rs_rs: + /* Interface connected. */ + /* Gnttab channel phase one disconnected. */ + /* Attempted to clear store. */ + /* Something failed. */ + /* Watch not registered. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = xenidc_xbgt_channel_state_i; + xenidc_xbgt_channel_complete_disconnect(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs: + /* Interface connected. */ + /* Gnttab channel phase one connected. */ + /* Ready. */ + /* Watch registered. */ + /* Testing other state or other state disconnected */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_dn_rs; + xenidc_xbgt_channel_unregister_watch(channel); + break; + case xenidc_xbgt_channel_stimulus_od: + break; + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or; + xenidc_xbgt_channel_write_connected(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or: + /* Interface connected. */ + /* Gnttab channel phase one connected. */ + /* Writing Connected. */ + /* Watch registered. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_dn; + break; + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs; + xenidc_xbgt_channel_test_other_state(channel); + break; + case xenidc_xbgt_channel_stimulus_rf: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rf; + xenidc_xbgt_channel_unregister_watch(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs: + /* Interface connected. */ + /* Gnttab channel phase one connected. */ + /* Connected. */ + /* Watch registered. */ + /* Testing other state / other state ready. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_dn_rs; + xenidc_xbgt_channel_unregister_watch(channel); + break; + case xenidc_xbgt_channel_stimulus_od: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs; + xenidc_xbgt_channel_clear_store(channel); + break; + case xenidc_xbgt_channel_stimulus_or: + break; + case xenidc_xbgt_channel_stimulus_oc: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc; + xenidc_xbgt_channel_phase_two_connect(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc: + /* Interface connected. */ + /* Gnttab channel phase two connecting. */ + /* Connected. */ + /* Watch registered. */ + /* Other side connected. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_pe: + /* Phase two disconnect then go around. */ + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_pe; + break; + case xenidc_xbgt_channel_stimulus_dn: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_dn; + break; + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_pe; + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_rs; + break; + case xenidc_xbgt_channel_stimulus_rf: + /* Maybe we picked up stale state from the store. Go around. */ + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs; + xenidc_xbgt_channel_clear_store(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_pe: + /* Interface connected. */ + /* Gnttab channel phase two connecting. */ + /* Connected. */ + /* Watch registered. */ + /* Protocol error or glitch. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_pe: + break; + case xenidc_xbgt_channel_stimulus_dn: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_dn; + break; + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = xenidc_xbgt_channel_state_i_cn_rs; + xenidc_xbgt_channel_phase_two_disconnect(channel); + break; + case xenidc_xbgt_channel_stimulus_rf: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs; + xenidc_xbgt_channel_clear_store(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_dn: + /* Interface disconnecting. */ + /* Gnttab channel phase two connecting. */ + /* Connected. */ + /* Watch registered. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_pe: + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_dn; + xenidc_xbgt_channel_phase_two_disconnect(channel); + break; + case xenidc_xbgt_channel_stimulus_rf: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_dn_rs; + xenidc_xbgt_channel_unregister_watch(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_rs: + /* Interface connected. */ + /* Gnttab channel phase two connected. */ + /* Connected. */ + /* Watch registered. */ + /* Other side connected. */ + /* Totally happy. */ + switch (stimulus) { + case xenidc_xbgt_channel_stimulus_pe: + channel->state = xenidc_xbgt_channel_state_i_cn_rs; + xenidc_xbgt_channel_phase_two_disconnect(channel); + break; + case xenidc_xbgt_channel_stimulus_dn: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_dn; + xenidc_xbgt_channel_phase_two_disconnect(channel); + break; + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + channel->state = xenidc_xbgt_channel_state_i_cn_rs; + xenidc_xbgt_channel_phase_two_disconnect(channel); + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } + break; + default: + xenidc_xbgt_channel_invalid_stimulus(channel, stimulus); + break; + } +} + +static void +xenidc_xbgt_channel_invalid_stimulus(struct xenidc_xbgt_channel *channel, +xenidc_xbgt_channel_stimulus stimulus) +{ + trace(); + printk(KERN_ERR "xenidc: xbgt channel %p in state %d" + "received invalid stimulus %d", channel, channel->state, + stimulus); +} + +static void +xenidc_xbgt_channel_test_other_state(struct xenidc_xbgt_channel *channel) +{ + trace(); + switch (channel->other_state) { + case xenidc_xbgt_channel_other_state_unknown: + xenidc_xbgt_channel_handle_stimulus + (channel, xenidc_xbgt_channel_stimulus_ou); + break; + case xenidc_xbgt_channel_other_state_disconnected: + xenidc_xbgt_channel_handle_stimulus + (channel, xenidc_xbgt_channel_stimulus_od); + break; + case xenidc_xbgt_channel_other_state_ready: + xenidc_xbgt_channel_handle_stimulus + (channel, xenidc_xbgt_channel_stimulus_or); + break; + case xenidc_xbgt_channel_other_state_connected: + xenidc_xbgt_channel_handle_stimulus + (channel, xenidc_xbgt_channel_stimulus_oc); + break; + } +} + +static void +xenidc_xbgt_channel_register_watch(struct xenidc_xbgt_channel *channel) +{ + trace(); + channel->other_state = xenidc_xbgt_channel_other_state_unknown; + (void)xenidc_work_schedule(&channel->register_watch_1_work); +} + +static void +xenidc_xbgt_channel_register_watch_1(void *data) +{ + struct xenidc_xbgt_channel *channel = + (struct xenidc_xbgt_channel *)data; + int return_value; + unsigned long flags; + trace(); + channel->watch.node = channel->remote_path; + channel->watch.callback = xenidc_xbgt_channel_watch; + return_value = register_xenbus_watch(&channel->watch); + spin_lock_irqsave(&channel->lock, flags); + if (return_value == 0) { + xenidc_xbgt_channel_handle_stimulus(channel, + xenidc_xbgt_channel_stimulus_rs); + } else { + xenidc_xbgt_channel_handle_stimulus(channel, + xenidc_xbgt_channel_stimulus_rf); + } + spin_unlock_irqrestore(&channel->lock, flags); +} + +static void +xenidc_xbgt_channel_unregister_watch(struct xenidc_xbgt_channel *channel) +{ + trace(); + (void)xenidc_work_schedule(&channel->unregister_watch_1_work); +} + +static void +xenidc_xbgt_channel_unregister_watch_1(void *data) +{ + struct xenidc_xbgt_channel *channel = + (struct xenidc_xbgt_channel *)data; + unsigned long flags; + trace(); + unregister_xenbus_watch(&channel->watch); + spin_lock_irqsave(&channel->lock, flags); + xenidc_xbgt_channel_handle_stimulus(channel, + xenidc_xbgt_channel_stimulus_rs); + spin_unlock_irqrestore(&channel->lock, flags); +} + +static void +xenidc_xbgt_channel_clear_store(struct xenidc_xbgt_channel *channel) +{ + trace(); + (void)xenidc_work_schedule(&channel->clear_store_1_work); +} + +static void +xenidc_xbgt_channel_clear_store_1(void *data) +{ + struct xenidc_xbgt_channel *channel = + (struct xenidc_xbgt_channel *)data; + struct xenbus_transaction *transaction; + int error; + unsigned long flags; + trace(); + again: + transaction = xenbus_transaction_start(); + if (IS_ERR(transaction)) { + trace_info("error starting transaction"); + goto transaction_error; + } + error = xenbus_rm(transaction, channel->local_path, "ready"); + if (error) { + trace_info("error removing ready field from store"); + goto abort_transaction; + } + error = xenbus_rm(transaction, channel->local_path, "event-channel"); + if (error) { + trace_info("error removing event-channel field from store"); + goto abort_transaction; + } + error = xenbus_rm(transaction, channel->local_path, "ring-reference"); + if (error) { + trace_info("error removing ring-reference field from store"); + goto abort_transaction; + } + error = xenbus_transaction_end(transaction, 0 /* commit */ ); + if (error) { + if (error == -EAGAIN) { + goto again; + } else { + trace_info("error committing transaction"); + goto transaction_error; + } + } + spin_lock_irqsave(&channel->lock, flags); + xenidc_xbgt_channel_handle_stimulus(channel, + xenidc_xbgt_channel_stimulus_rs); + spin_unlock_irqrestore(&channel->lock, flags); + return; + abort_transaction: + xenbus_transaction_end(transaction, 1 /* abort */ ); + transaction_error: + spin_lock_irqsave(&channel->lock, flags); + xenidc_xbgt_channel_handle_stimulus(channel, + xenidc_xbgt_channel_stimulus_rf); + spin_unlock_irqrestore(&channel->lock, flags); +} + +static void +xenidc_xbgt_channel_write_ready(struct xenidc_xbgt_channel *channel) +{ + trace(); + (void)xenidc_work_schedule(&channel->write_ready_1_work); +} + +static void +xenidc_xbgt_channel_write_ready_1(void *data) +{ + struct xenidc_xbgt_channel *channel = + (struct xenidc_xbgt_channel *)data; + struct xenbus_transaction *transaction; + int error; + unsigned long flags; + trace(); + again: + transaction = xenbus_transaction_start(); + if (IS_ERR(transaction)) { + trace_info("error starting transaction"); + goto transaction_error; + } + error = xenbus_write(transaction, channel->local_path, "ready", "1"); + if (error) { + trace_info("error writing ready to store"); + goto abort_transaction; + } + error = xenbus_transaction_end(transaction, 0 /* commit */ ); + if (error) { + if (error == -EAGAIN) { + goto again; + } else { + trace_info("error committing transaction"); + goto transaction_error; + } + } + spin_lock_irqsave(&channel->lock, flags); + xenidc_xbgt_channel_handle_stimulus(channel, + xenidc_xbgt_channel_stimulus_rs); + spin_unlock_irqrestore(&channel->lock, flags); + return; + abort_transaction: + xenbus_transaction_end(transaction, 1 /* abort */ ); + transaction_error: + spin_lock_irqsave(&channel->lock, flags); + xenidc_xbgt_channel_handle_stimulus(channel, + xenidc_xbgt_channel_stimulus_rf); + spin_unlock_irqrestore(&channel->lock, flags); +} + +static void +xenidc_xbgt_channel_write_connected(struct xenidc_xbgt_channel *channel) +{ + trace(); + (void)xenidc_work_schedule(&channel->write_connected_1_work); +} + +static void +xenidc_xbgt_channel_write_connected_1(void *data) +{ + struct xenidc_xbgt_channel *channel = + (struct xenidc_xbgt_channel *)data; + struct xenbus_transaction *transaction; + int error; + unsigned long flags; + trace(); + xenidc_gnttab_channel_reset_ring(&channel->channel); + again: + transaction = xenbus_transaction_start(); + if (IS_ERR(transaction)) { + trace_info("error starting transaction"); + goto transaction_error; + } + error = xenbus_printf(transaction, channel->local_path, + "ring-reference", "%u", channel-> + phase_one_connect_request.send_ring_ref); + if (error) { + trace_info("error writing ring-reference to store"); + goto abort_transaction; + } + error = xenbus_printf(transaction, channel->local_path, + "event-channel", "%u", channel-> + phase_one_connect_request.send_event_channel); + if (error) { + trace_info("error writing event-channel to store"); + goto abort_transaction; + } + error = xenbus_transaction_end(transaction, 0 /* commit */ ); + if (error) { + if (error == -EAGAIN) { + goto again; + } else { + trace_info("error committing transaction"); + goto transaction_error; + } + } + spin_lock_irqsave(&channel->lock, flags); + xenidc_xbgt_channel_handle_stimulus(channel, + xenidc_xbgt_channel_stimulus_rs); + spin_unlock_irqrestore(&channel->lock, flags); + return; + abort_transaction: + xenbus_transaction_end(transaction, 1 /* abort */ ); + transaction_error: + spin_lock_irqsave(&channel->lock, flags); + xenidc_xbgt_channel_handle_stimulus(channel, + xenidc_xbgt_channel_stimulus_rf); + spin_unlock_irqrestore(&channel->lock, flags); +} + +static void +xenidc_xbgt_channel_phase_one_connect(struct xenidc_xbgt_channel *channel) +{ + trace(); + channel->phase_one_connect_request.remote_domain_id = + channel->remote_domain_id; + (void)xenidc_work_schedule(&channel->phase_one_connect_1_work); +} + +static void xenidc_xbgt_channel_phase_one_connect_1(void *data) +{ + struct xenidc_xbgt_channel *channel = + (struct xenidc_xbgt_channel *)data; + trace(); + xenidc_gnttab_channel_phase_one_connect(&channel->channel, + &channel->phase_one_connect_request); +} + +static void +xenidc_xbgt_channel_phase_one_connect_2(struct xenidc_callback *callback) +{ + struct xenidc_xbgt_channel *channel = container_of( + xenidc_gnttab_channel_phase_one_connect_request_callback_to( + callback), + struct xenidc_xbgt_channel, + phase_one_connect_request); + unsigned long flags; + trace(); + spin_lock_irqsave(&channel->lock, flags); + xenidc_xbgt_channel_handle_stimulus(channel, + xenidc_xbgt_channel_stimulus_rs); + spin_unlock_irqrestore(&channel->lock, flags); +} + +static void +xenidc_xbgt_channel_phase_two_connect(struct xenidc_xbgt_channel *channel) +{ + trace(); + channel->phase_two_connect_request.remote_domain_id = + channel->remote_domain_id; + channel->phase_two_connect_request.recv_ring_ref = + channel->ready_ring_reference; + channel->phase_two_connect_request.recv_event_channel = + channel->ready_event_channel; + (void)xenidc_work_schedule(&channel->phase_two_connect_1_work); +} + +static void xenidc_xbgt_channel_phase_two_connect_1(void *data) +{ + struct xenidc_xbgt_channel *channel = + (struct xenidc_xbgt_channel *)data; + trace(); + xenidc_gnttab_channel_phase_two_connect(&channel->channel, + &channel->phase_two_connect_request); +} + +static void xenidc_xbgt_channel_phase_two_connect_2( +struct xenidc_callback *callback) +{ + struct xenidc_xbgt_channel *channel = container_of( + xenidc_gnttab_channel_phase_two_connect_request_callback_to( + callback), + struct xenidc_xbgt_channel, + phase_two_connect_request); + unsigned long flags; + trace(); + spin_lock_irqsave(&channel->lock, flags); + if (xenidc_callback_query_error(callback) == XENIDC_ERROR_SUCCESS) { + xenidc_xbgt_channel_handle_stimulus(channel, + xenidc_xbgt_channel_stimulus_rs); + } else { + xenidc_xbgt_channel_handle_stimulus(channel, + xenidc_xbgt_channel_stimulus_rf); + } + spin_unlock_irqrestore(&channel->lock, flags); +} + +static void +xenidc_xbgt_channel_phase_two_disconnect(struct xenidc_xbgt_channel *channel) +{ + trace(); + (void)xenidc_work_schedule(&channel->phase_two_disconnect_1_work); +} + +static void xenidc_xbgt_channel_phase_two_disconnect_1(void *data) +{ + struct xenidc_xbgt_channel *channel = + (struct xenidc_xbgt_channel *)data; + trace(); + xenidc_gnttab_channel_phase_two_disconnect(&channel->channel, + &channel->phase_two_disconnect_callback); +} + +static void +xenidc_xbgt_channel_phase_two_disconnect_2(struct xenidc_callback *callback) +{ + struct xenidc_xbgt_channel *channel = container_of(callback, + struct xenidc_xbgt_channel, phase_two_disconnect_callback); + unsigned long flags; + trace(); + spin_lock_irqsave(&channel->lock, flags); + xenidc_xbgt_channel_handle_stimulus(channel, + xenidc_xbgt_channel_stimulus_rs); + spin_unlock_irqrestore(&channel->lock, flags); +} + +static void xenidc_xbgt_channel_phase_one_disconnect( +struct xenidc_xbgt_channel *channel) +{ + trace(); + (void)xenidc_work_schedule(&channel->phase_one_disconnect_1_work); +} + +static void xenidc_xbgt_channel_phase_one_disconnect_1(void *data) +{ + struct xenidc_xbgt_channel *channel = + (struct xenidc_xbgt_channel *)data; + trace(); + xenidc_gnttab_channel_phase_one_disconnect(&channel->channel, + &channel->phase_one_disconnect_callback); +} + +static void +xenidc_xbgt_channel_phase_one_disconnect_2(struct xenidc_callback *callback) +{ + struct xenidc_xbgt_channel *channel = container_of(callback, + struct xenidc_xbgt_channel, phase_one_disconnect_callback); + unsigned long flags; + trace(); + spin_lock_irqsave(&channel->lock, flags); + xenidc_xbgt_channel_handle_stimulus(channel, + xenidc_xbgt_channel_stimulus_rs); + spin_unlock_irqrestore(&channel->lock, flags); +} + +static void xenidc_xbgt_channel_complete_disconnect( +struct xenidc_xbgt_channel *channel) +{ + trace(); + xenidc_callback_success(channel->disconnect_callback); +} diff -r 37cde7841498 -r d2703777cccb linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel_enumeration.dot --- /dev/null Thu Nov 24 16:28:47 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel_enumeration.dot Thu Nov 24 18:30:37 2005 @@ -0,0 +1,109 @@ +digraph enumeration { +size="7,7" + +i[style=filled,fillcolor=green] +i->i_cn[label="cn\nphase_one_connect"]; + +i_cn[style=filled,fillcolor=green] +i_cn->i_cn_dn[label="dn"]; +i_cn->i_cn_rs[label="rs\nregister_watch"]; + +i_cn_dn[style=filled,fillcolor=orange] +i_cn_dn->i_cn_dn_rs[label="rs\nclear_store"]; + +i_cn_rs[style=filled,fillcolor=green] +i_cn_rs->i_cn_rs_dn[label="dn"]; +i_cn_rs->i_cn_rs[label="pe/od/or/oc"]; +i_cn_rs->i_cn_rs_rs[label="rs\nclear_store"]; +i_cn_rs->i_cn_rs_rf[label="rf\nclear_store"]; + +i_cn_dn_rs[style=filled,fillcolor=orange] +i_cn_dn_rs->i_cn_dn_rs_rs[label="rs/rf\nphase_one_disconnect"]; + +i_cn_rs_dn[style=filled,fillcolor=orange] +i_cn_rs_dn->i_cn_rs_dn[label="od/or/oc"]; +i_cn_rs_dn->i_cn_rs_dn_rs[label="rs\nunregister_watch"]; +i_cn_rs_dn->i_cn_dn_rs[label="rf\nclear_store"]; + +i_cn_rs_rs[style=filled,fillcolor=green] +i_cn_rs_rs->i_cn_rs_rs_dn[label="dn"]; +i_cn_rs_rs->i_cn_rs_rs[label="od/or/oc"]; +i_cn_rs_rs->i_cn_rs_rs_rs[label="rs\ntest_other_state"]; +i_cn_rs_rs->i_cn_rs_rs_rf[label="rf\nunregister_watch"]; + +i_cn_rs_rf[style=filled,fillcolor=red] +i_cn_rs_rf->i_cn_dn_rs[label="dn"]; +i_cn_rs_rf->i_cn_rs_rf_rs[label="rs/rf\nphase_one_disconnect"]; + +i_cn_dn_rs_rs[style=filled,fillcolor=orange] +i_cn_dn_rs_rs->i[label="rs\ncomplete_disconnect"]; + +i_cn_rs_dn_rs[style=filled,fillcolor=orange] +i_cn_rs_dn_rs->i_cn_rs_dn_rs[label="od/or/oc"]; +i_cn_rs_dn_rs->i_cn_dn_rs[label="rs\nclear_store"]; + +i_cn_rs_rs_dn[style=filled,fillcolor=orange] +i_cn_rs_rs_dn->i_cn_rs_rs_dn[label="od/or/oc"]; +i_cn_rs_rs_dn->i_cn_rs_dn_rs[label="rs/rf\nunregister_watch"]; + +i_cn_rs_rs_rs[style=filled,fillcolor=green] +i_cn_rs_rs_rs->i_cn_rs_dn_rs[label="dn\nunregister_watch"]; +i_cn_rs_rs_rs->i_cn_rs_rs_rs[label="ou/oc"]; +i_cn_rs_rs_rs->i_cn_rs_rs_rs_od[label="od/or\nwrite_ready"]; + +i_cn_rs_rs_rf[style=filled,fillcolor=red] +i_cn_rs_rs_rf->i_cn_rs_dn_rs[label="dn"]; +i_cn_rs_rs_rf->i_cn_rs_rs_rf[label="od/or/oc"]; +i_cn_rs_rs_rf->i_cn_rs_rf[label="rs\nclear_store"]; + +i_cn_rs_rf_rs[style=filled,fillcolor=red] +i_cn_rs_rf_rs->i_cn_dn_rs_rs[label="dn"]; +i_cn_rs_rf_rs->i_cn_rs_rf_rs_rs[label="rs"]; + +i_cn_rs_rs_rs_od[style=filled,fillcolor=green] +i_cn_rs_rs_rs_od->i_cn_rs_rs_dn[label="dn"]; +i_cn_rs_rs_rs_od->i_cn_rs_rs_rs_od[label="od/or/oc"]; +i_cn_rs_rs_rs_od->i_cn_rs_rs_rs_od_rs[label="rs\ntest_other_state"]; +i_cn_rs_rs_rs_od->i_cn_rs_rs_rf[label="rf\nunregister_watch"]; + +i_cn_rs_rf_rs_rs[style=filled,fillcolor=red] +i_cn_rs_rf_rs_rs->i[label="dn\ncomplete_disconnect"]; + +i_cn_rs_rs_rs_od_rs[style=filled,fillcolor=green] +i_cn_rs_rs_rs_od_rs->i_cn_rs_dn_rs[label="dn\nunregister_watch"]; +i_cn_rs_rs_rs_od_rs->i_cn_rs_rs_rs_od_rs[label="od"]; +i_cn_rs_rs_rs_od_rs->i_cn_rs_rs_rs_od_rs_or[label="or/oc\nwrite_connected"]; + +i_cn_rs_rs_rs_od_rs_or[style=filled,fillcolor=green] +i_cn_rs_rs_rs_od_rs_or->i_cn_rs_rs_dn[label="dn"]; +i_cn_rs_rs_rs_od_rs_or->i_cn_rs_rs_rs_od_rs_or[label="od/or/oc"]; +i_cn_rs_rs_rs_od_rs_or->i_cn_rs_rs_rs_od_rs_or_rs[label="rs\ntest_other_state"]; +i_cn_rs_rs_rs_od_rs_or->i_cn_rs_rs_rf[label="rf\nunregister_watch"]; + +i_cn_rs_rs_rs_od_rs_or_rs[style=filled,fillcolor=green] +i_cn_rs_rs_rs_od_rs_or_rs->i_cn_rs_dn_rs[label="dn\nunregister_watch"]; +i_cn_rs_rs_rs_od_rs_or_rs->i_cn_rs_rs[label="od\nclear_store"]; +i_cn_rs_rs_rs_od_rs_or_rs->i_cn_rs_rs_rs_od_rs_or_rs[label="or"]; +i_cn_rs_rs_rs_od_rs_or_rs->i_cn_rs_rs_rs_od_rs_or_rs_oc[label="oc\nphase_two_connect"]; + +i_cn_rs_rs_rs_od_rs_or_rs_oc[style=filled,fillcolor=green] +i_cn_rs_rs_rs_od_rs_or_rs_oc->i_cn_rs_rs_rs_od_rs_or_rs_oc_pe[label="pe/od/or/oc"]; +i_cn_rs_rs_rs_od_rs_or_rs_oc->i_cn_rs_rs_rs_od_rs_or_rs_oc_dn[label="dn"]; +i_cn_rs_rs_rs_od_rs_or_rs_oc->i_cn_rs_rs_rs_od_rs_or_rs_oc_rs[label="rs"]; +i_cn_rs_rs_rs_od_rs_or_rs_oc->i_cn_rs_rs[label="rf\nclear_store"]; + +i_cn_rs_rs_rs_od_rs_or_rs_oc_pe[style=filled,fillcolor=blue] +i_cn_rs_rs_rs_od_rs_or_rs_oc_pe->i_cn_rs_rs_rs_od_rs_or_rs_oc_pe[label="pe/od/or/oc"] +i_cn_rs_rs_rs_od_rs_or_rs_oc_pe->i_cn_rs_rs_rs_od_rs_or_rs_oc_dn[label="dn"] +i_cn_rs_rs_rs_od_rs_or_rs_oc_pe->i_cn_rs[label="rs\nphase_two_disconnect"] +i_cn_rs_rs_rs_od_rs_or_rs_oc_pe->i_cn_rs_rs[label="rf\nclear_store"] + +i_cn_rs_rs_rs_od_rs_or_rs_oc_dn[style=filled,fillcolor=orange] +i_cn_rs_rs_rs_od_rs_or_rs_oc_dn->i_cn_rs_rs_rs_od_rs_or_rs_oc_dn[label="pe/od/or/oc"] +i_cn_rs_rs_rs_od_rs_or_rs_oc_dn->i_cn_rs_rs_dn[label="rs\nphase_two_disconnect"] +i_cn_rs_rs_rs_od_rs_or_rs_oc_dn->i_cn_rs_dn_rs[label="rf\nunregister_watch"] + +i_cn_rs_rs_rs_od_rs_or_rs_oc_rs[style=filled,fillcolor=green] +i_cn_rs_rs_rs_od_rs_or_rs_oc_rs->i_cn_rs[label="pe/od/or/oc\nphase_two_disconnect"] +i_cn_rs_rs_rs_od_rs_or_rs_oc_rs->i_cn_rs_rs_dn[label="dn\nphase_two_disconnect"] +} diff -r 37cde7841498 -r d2703777cccb linux-2.6-xen-sparse/include/asm-xen/xenidc_xbgt_channel.h --- /dev/null Thu Nov 24 16:28:47 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_xbgt_channel.h Thu Nov 24 18:30:37 2005 @@ -0,0 +1,148 @@ +/*****************************************************************************/ +/* This is a class which uses a xenidc_gnttab_channel (grant-tables based */ +/* message channel class) and xenbus to implement an interdomain message */ +/* channel with grant-tables based message transfer and xenbus based */ +/* bring-up and tear-down handshaking. */ +/* This class is used in the implementation of the xenidc_endpoint class. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef XENIDC_XBGT_CHANNEL_H +#define XENIDC_XBGT_CHANNEL_H + +#include +#include + +typedef enum { + xenidc_xbgt_channel_state_i, + xenidc_xbgt_channel_state_i_cn, + xenidc_xbgt_channel_state_i_cn_dn, + xenidc_xbgt_channel_state_i_cn_rs, + xenidc_xbgt_channel_state_i_cn_dn_rs, + xenidc_xbgt_channel_state_i_cn_rs_dn, + xenidc_xbgt_channel_state_i_cn_rs_rs, + xenidc_xbgt_channel_state_i_cn_rs_rf, + xenidc_xbgt_channel_state_i_cn_dn_rs_rs, + xenidc_xbgt_channel_state_i_cn_rs_dn_rs, + xenidc_xbgt_channel_state_i_cn_rs_rs_dn, + xenidc_xbgt_channel_state_i_cn_rs_rs_rs, + xenidc_xbgt_channel_state_i_cn_rs_rs_rf, + xenidc_xbgt_channel_state_i_cn_rs_rf_rs, + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od, + xenidc_xbgt_channel_state_i_cn_rs_rf_rs_rs, + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs, + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or, + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs, + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc, + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_pe, + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_dn, + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_rs +} xenidc_xbgt_channel_state; + +typedef enum { + xenidc_xbgt_channel_other_state_unknown, + xenidc_xbgt_channel_other_state_disconnected, + xenidc_xbgt_channel_other_state_ready, + xenidc_xbgt_channel_other_state_connected +} xenidc_xbgt_channel_other_state; + +struct xenidc_xbgt_channel { + struct xenidc_gnttab_channel channel; + + struct xenbus_watch watch; + + spinlock_t lock; + + xenidc_xbgt_channel_state state; + xenidc_xbgt_channel_other_state other_state; + + const char *local_path; + const char *remote_path; + domid_t remote_domain_id; + + struct xenidc_callback *disconnect_callback; + + int ready_ring_reference; + int ready_event_channel; + + struct xenidc_work register_watch_1_work; + struct xenidc_work unregister_watch_1_work; + struct xenidc_work clear_store_1_work; + struct xenidc_work write_ready_1_work; + struct xenidc_work write_connected_1_work; + struct xenidc_work phase_one_connect_1_work; + struct xenidc_work phase_two_connect_1_work; + struct xenidc_work phase_two_disconnect_1_work; + struct xenidc_work phase_one_disconnect_1_work; + + struct xenidc_gnttab_channel_phase_one_connect_request + phase_one_connect_request; + struct xenidc_gnttab_channel_phase_two_connect_request + phase_two_connect_request; + + struct xenidc_callback phase_two_disconnect_callback; + struct xenidc_callback phase_one_disconnect_callback; +}; + +/* This class implements the xenidc_channel interface. */ + +static inline struct xenidc_channel * +xenidc_xbgt_channel_to_channel(struct xenidc_xbgt_channel *channel) +{ + return xenidc_gnttab_channel_to_channel(&channel->channel); +} + +/* Cast from base class. */ + +static inline struct xenidc_xbgt_channel * +xenidc_xbgt_channel_gnttab_channel_to( +struct xenidc_gnttab_channel *gnttab_channel) +{ + return container_of(gnttab_channel, struct xenidc_xbgt_channel, + channel); +} + +/* Cast from base class. */ + +static inline struct xenidc_xbgt_channel * +xenidc_xbgt_channel_channel_to(struct xenidc_channel *channel) +{ + return xenidc_xbgt_channel_gnttab_channel_to( + xenidc_gnttab_channel_channel_to(channel)); +} + +int xenidc_xbgt_channel_init(struct xenidc_xbgt_channel *channel); + +/* xenidc_xbgt_channel_connect called to connect the channel. Passed the */ +/* xenbus specific addressing information of the remote domain and device. */ + +void +xenidc_xbgt_channel_connect(struct xenidc_xbgt_channel *channel, +const char *local_path, const char *remote_path, domid_t remote_domain_id); + +/* Called to disconnect. Callback completes after base channel class has */ +/* disconnected its client. */ + +void +xenidc_xbgt_channel_disconnect(struct xenidc_xbgt_channel *channel, +struct xenidc_callback *callback); + +void xenidc_xbgt_channel_exit(struct xenidc_xbgt_channel *channel); + +#endif