Staging: hv: rename ChannelMgmt.c and .h to channel_mgmt.c and .h
authorGreg Kroah-Hartman <gregkh@suse.de>
Thu, 6 May 2010 05:34:18 +0000 (22:34 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 11 May 2010 18:36:17 +0000 (11:36 -0700)
Cc: Hank Janssen <hjanssen@microsoft.com>
Cc: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/staging/hv/ChannelMgmt.c [deleted file]
drivers/staging/hv/ChannelMgmt.h [deleted file]
drivers/staging/hv/Makefile
drivers/staging/hv/VmbusPrivate.h
drivers/staging/hv/channel.h
drivers/staging/hv/channel_mgmt.c [new file with mode: 0644]
drivers/staging/hv/channel_mgmt.h [new file with mode: 0644]

diff --git a/drivers/staging/hv/ChannelMgmt.c b/drivers/staging/hv/ChannelMgmt.c
deleted file mode 100644 (file)
index 3698230..0000000
+++ /dev/null
@@ -1,856 +0,0 @@
-/*
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * Authors:
- *   Haiyang Zhang <haiyangz@microsoft.com>
- *   Hank Janssen  <hjanssen@microsoft.com>
- */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include "osd.h"
-#include "logging.h"
-#include "VmbusPrivate.h"
-#include "utils.h"
-
-struct vmbus_channel_message_table_entry {
-       enum vmbus_channel_message_type messageType;
-       void (*messageHandler)(struct vmbus_channel_message_header *msg);
-};
-
-#define MAX_MSG_TYPES                    2
-#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 6
-
-static const struct hv_guid
-       gSupportedDeviceClasses[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = {
-       /* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
-       /* Storage - SCSI */
-       {
-               .data  = {
-                       0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
-                       0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
-               }
-       },
-
-       /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
-       /* Network */
-       {
-               .data = {
-                       0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
-                       0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E
-               }
-       },
-
-       /* {CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} */
-       /* Input */
-       {
-               .data = {
-                       0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
-                       0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A
-               }
-       },
-
-       /* {32412632-86cb-44a2-9b5c-50d1417354f5} */
-       /* IDE */
-       {
-               .data = {
-                       0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
-                       0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
-               }
-       },
-       /* 0E0B6031-5213-4934-818B-38D90CED39DB */
-       /* Shutdown */
-       {
-               .data = {
-                       0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
-                       0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
-               }
-       },
-       /* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
-       /* TimeSync */
-       {
-               .data = {
-                       0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
-                       0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
-               }
-       },
-};
-
-
-/**
- * prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
- * @icmsghdrp: Pointer to msg header structure
- * @icmsg_negotiate: Pointer to negotiate message structure
- * @buf: Raw buffer channel data
- *
- * @icmsghdrp is of type &struct icmsg_hdr.
- * @negop is of type &struct icmsg_negotiate.
- * Set up and fill in default negotiate response message. This response can
- * come from both the vmbus driver and the hv_utils driver. The current api
- * will respond properly to both Windows 2008 and Windows 2008-R2 operating
- * systems.
- *
- * Mainly used by Hyper-V drivers.
- */
-void prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
-                            struct icmsg_negotiate *negop,
-                            u8 *buf)
-{
-       if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
-               icmsghdrp->icmsgsize = 0x10;
-
-               negop = (struct icmsg_negotiate *)&buf[
-                       sizeof(struct vmbuspipe_hdr) +
-                       sizeof(struct icmsg_hdr)];
-
-               if (negop->icframe_vercnt == 2 &&
-                  negop->icversion_data[1].major == 3) {
-                       negop->icversion_data[0].major = 3;
-                       negop->icversion_data[0].minor = 0;
-                       negop->icversion_data[1].major = 3;
-                       negop->icversion_data[1].minor = 0;
-               } else {
-                       negop->icversion_data[0].major = 1;
-                       negop->icversion_data[0].minor = 0;
-                       negop->icversion_data[1].major = 1;
-                       negop->icversion_data[1].minor = 0;
-               }
-
-               negop->icframe_vercnt = 1;
-               negop->icmsg_vercnt = 1;
-       }
-}
-EXPORT_SYMBOL(prep_negotiate_resp);
-
-/**
- * chn_cb_negotiate() - Default handler for non IDE/SCSI/NETWORK
- * Hyper-V requests
- * @context: Pointer to argument structure.
- *
- * Set up the default handler for non device driver specific requests
- * from Hyper-V. This stub responds to the default negotiate messages
- * that come in for every non IDE/SCSI/Network request.
- * This behavior is normally overwritten in the hv_utils driver. That
- * driver handles requests like gracefull shutdown, heartbeats etc.
- *
- * Mainly used by Hyper-V drivers.
- */
-void chn_cb_negotiate(void *context)
-{
-       struct vmbus_channel *channel = context;
-       u8 *buf;
-       u32 buflen, recvlen;
-       u64 requestid;
-
-       struct icmsg_hdr *icmsghdrp;
-       struct icmsg_negotiate *negop = NULL;
-
-       buflen = PAGE_SIZE;
-       buf = kmalloc(buflen, GFP_ATOMIC);
-
-       VmbusChannelRecvPacket(channel, buf, buflen, &recvlen, &requestid);
-
-       if (recvlen > 0) {
-               icmsghdrp = (struct icmsg_hdr *)&buf[
-                       sizeof(struct vmbuspipe_hdr)];
-
-               prep_negotiate_resp(icmsghdrp, negop, buf);
-
-               icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
-                       | ICMSGHDRFLAG_RESPONSE;
-
-               VmbusChannelSendPacket(channel, buf,
-                                      recvlen, requestid,
-                                      VmbusPacketTypeDataInBand, 0);
-       }
-
-       kfree(buf);
-}
-EXPORT_SYMBOL(chn_cb_negotiate);
-
-/*
- * Function table used for message responses for non IDE/SCSI/Network type
- * messages. (Such as KVP/Shutdown etc)
- */
-struct hyperv_service_callback hv_cb_utils[MAX_MSG_TYPES] = {
-       /* 0E0B6031-5213-4934-818B-38D90CED39DB */
-       /* Shutdown */
-       {
-               .msg_type = HV_SHUTDOWN_MSG,
-               .data = {
-                       0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
-                       0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
-               },
-               .callback = chn_cb_negotiate,
-               .log_msg = "Shutdown channel functionality initialized"
-       },
-
-       /* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
-       /* TimeSync */
-       {
-               .msg_type = HV_TIMESYNC_MSG,
-               .data = {
-                       0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
-                       0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
-               },
-               .callback = chn_cb_negotiate,
-               .log_msg = "Timesync channel functionality initialized"
-       },
-};
-EXPORT_SYMBOL(hv_cb_utils);
-
-/*
- * AllocVmbusChannel - Allocate and initialize a vmbus channel object
- */
-struct vmbus_channel *AllocVmbusChannel(void)
-{
-       struct vmbus_channel *channel;
-
-       channel = kzalloc(sizeof(*channel), GFP_ATOMIC);
-       if (!channel)
-               return NULL;
-
-       spin_lock_init(&channel->inbound_lock);
-
-       init_timer(&channel->poll_timer);
-       channel->poll_timer.data = (unsigned long)channel;
-       channel->poll_timer.function = VmbusChannelOnTimer;
-
-       channel->ControlWQ = create_workqueue("hv_vmbus_ctl");
-       if (!channel->ControlWQ) {
-               kfree(channel);
-               return NULL;
-       }
-
-       return channel;
-}
-
-/*
- * ReleaseVmbusChannel - Release the vmbus channel object itself
- */
-static inline void ReleaseVmbusChannel(void *context)
-{
-       struct vmbus_channel *channel = context;
-
-       DPRINT_ENTER(VMBUS);
-
-       DPRINT_DBG(VMBUS, "releasing channel (%p)", channel);
-       destroy_workqueue(channel->ControlWQ);
-       DPRINT_DBG(VMBUS, "channel released (%p)", channel);
-
-       kfree(channel);
-
-       DPRINT_EXIT(VMBUS);
-}
-
-/*
- * FreeVmbusChannel - Release the resources used by the vmbus channel object
- */
-void FreeVmbusChannel(struct vmbus_channel *Channel)
-{
-       del_timer_sync(&Channel->poll_timer);
-
-       /*
-        * We have to release the channel's workqueue/thread in the vmbus's
-        * workqueue/thread context
-        * ie we can't destroy ourselves.
-        */
-       osd_schedule_callback(gVmbusConnection.WorkQueue, ReleaseVmbusChannel,
-                             Channel);
-}
-
-/*
- * VmbusChannelProcessOffer - Process the offer by creating a channel/device
- * associated with this offer
- */
-static void VmbusChannelProcessOffer(void *context)
-{
-       struct vmbus_channel *newChannel = context;
-       struct vmbus_channel *channel;
-       bool fNew = true;
-       int ret;
-       int cnt;
-       unsigned long flags;
-
-       DPRINT_ENTER(VMBUS);
-
-       /* Make sure this is a new offer */
-       spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
-
-       list_for_each_entry(channel, &gVmbusConnection.ChannelList, ListEntry) {
-               if (!memcmp(&channel->OfferMsg.Offer.InterfaceType,
-                           &newChannel->OfferMsg.Offer.InterfaceType,
-                           sizeof(struct hv_guid)) &&
-                   !memcmp(&channel->OfferMsg.Offer.InterfaceInstance,
-                           &newChannel->OfferMsg.Offer.InterfaceInstance,
-                           sizeof(struct hv_guid))) {
-                       fNew = false;
-                       break;
-               }
-       }
-
-       if (fNew)
-               list_add_tail(&newChannel->ListEntry,
-                             &gVmbusConnection.ChannelList);
-
-       spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
-
-       if (!fNew) {
-               DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)",
-                          newChannel->OfferMsg.ChildRelId);
-               FreeVmbusChannel(newChannel);
-               DPRINT_EXIT(VMBUS);
-               return;
-       }
-
-       /*
-        * Start the process of binding this offer to the driver
-        * We need to set the DeviceObject field before calling
-        * VmbusChildDeviceAdd()
-        */
-       newChannel->DeviceObject = VmbusChildDeviceCreate(
-               &newChannel->OfferMsg.Offer.InterfaceType,
-               &newChannel->OfferMsg.Offer.InterfaceInstance,
-               newChannel);
-
-       DPRINT_DBG(VMBUS, "child device object allocated - %p",
-                  newChannel->DeviceObject);
-
-       /*
-        * Add the new device to the bus. This will kick off device-driver
-        * binding which eventually invokes the device driver's AddDevice()
-        * method.
-        */
-       ret = VmbusChildDeviceAdd(newChannel->DeviceObject);
-       if (ret != 0) {
-               DPRINT_ERR(VMBUS,
-                          "unable to add child device object (relid %d)",
-                          newChannel->OfferMsg.ChildRelId);
-
-               spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
-               list_del(&newChannel->ListEntry);
-               spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
-
-               FreeVmbusChannel(newChannel);
-       } else {
-               /*
-                * This state is used to indicate a successful open
-                * so that when we do close the channel normally, we
-                * can cleanup properly
-                */
-               newChannel->State = CHANNEL_OPEN_STATE;
-               cnt = 0;
-
-               while (cnt != MAX_MSG_TYPES) {
-                       if (memcmp(&newChannel->OfferMsg.Offer.InterfaceType,
-                                  &hv_cb_utils[cnt].data,
-                                  sizeof(struct hv_guid)) == 0) {
-                               DPRINT_INFO(VMBUS, "%s",
-                                           hv_cb_utils[cnt].log_msg);
-
-                               if (VmbusChannelOpen(newChannel, 2 * PAGE_SIZE,
-                                                   2 * PAGE_SIZE, NULL, 0,
-                                                   hv_cb_utils[cnt].callback,
-                                                   newChannel) == 0)
-                                       hv_cb_utils[cnt].channel = newChannel;
-                       }
-                       cnt++;
-               }
-       }
-       DPRINT_EXIT(VMBUS);
-}
-
-/*
- * VmbusChannelProcessRescindOffer - Rescind the offer by initiating a device removal
- */
-static void VmbusChannelProcessRescindOffer(void *context)
-{
-       struct vmbus_channel *channel = context;
-
-       DPRINT_ENTER(VMBUS);
-       VmbusChildDeviceRemove(channel->DeviceObject);
-       DPRINT_EXIT(VMBUS);
-}
-
-/*
- * VmbusChannelOnOffer - Handler for channel offers from vmbus in parent partition.
- *
- * We ignore all offers except network and storage offers. For each network and
- * storage offers, we create a channel object and queue a work item to the
- * channel object to process the offer synchronously
- */
-static void VmbusChannelOnOffer(struct vmbus_channel_message_header *hdr)
-{
-       struct vmbus_channel_offer_channel *offer;
-       struct vmbus_channel *newChannel;
-       struct hv_guid *guidType;
-       struct hv_guid *guidInstance;
-       int i;
-       int fSupported = 0;
-
-       DPRINT_ENTER(VMBUS);
-
-       offer = (struct vmbus_channel_offer_channel *)hdr;
-       for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
-               if (memcmp(&offer->Offer.InterfaceType,
-                   &gSupportedDeviceClasses[i], sizeof(struct hv_guid)) == 0) {
-                       fSupported = 1;
-                       break;
-               }
-       }
-
-       if (!fSupported) {
-               DPRINT_DBG(VMBUS, "Ignoring channel offer notification for "
-                          "child relid %d", offer->ChildRelId);
-               DPRINT_EXIT(VMBUS);
-               return;
-       }
-
-       guidType = &offer->Offer.InterfaceType;
-       guidInstance = &offer->Offer.InterfaceInstance;
-
-       DPRINT_INFO(VMBUS, "Channel offer notification - "
-                   "child relid %d monitor id %d allocated %d, "
-                   "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
-                   "%02x%02x%02x%02x%02x%02x%02x%02x} "
-                   "instance {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
-                   "%02x%02x%02x%02x%02x%02x%02x%02x}",
-                   offer->ChildRelId, offer->MonitorId,
-                   offer->MonitorAllocated,
-                   guidType->data[3], guidType->data[2],
-                   guidType->data[1], guidType->data[0],
-                   guidType->data[5], guidType->data[4],
-                   guidType->data[7], guidType->data[6],
-                   guidType->data[8], guidType->data[9],
-                   guidType->data[10], guidType->data[11],
-                   guidType->data[12], guidType->data[13],
-                   guidType->data[14], guidType->data[15],
-                   guidInstance->data[3], guidInstance->data[2],
-                   guidInstance->data[1], guidInstance->data[0],
-                   guidInstance->data[5], guidInstance->data[4],
-                   guidInstance->data[7], guidInstance->data[6],
-                   guidInstance->data[8], guidInstance->data[9],
-                   guidInstance->data[10], guidInstance->data[11],
-                   guidInstance->data[12], guidInstance->data[13],
-                   guidInstance->data[14], guidInstance->data[15]);
-
-       /* Allocate the channel object and save this offer. */
-       newChannel = AllocVmbusChannel();
-       if (!newChannel) {
-               DPRINT_ERR(VMBUS, "unable to allocate channel object");
-               return;
-       }
-
-       DPRINT_DBG(VMBUS, "channel object allocated - %p", newChannel);
-
-       memcpy(&newChannel->OfferMsg, offer,
-              sizeof(struct vmbus_channel_offer_channel));
-       newChannel->MonitorGroup = (u8)offer->MonitorId / 32;
-       newChannel->MonitorBit = (u8)offer->MonitorId % 32;
-
-       /* TODO: Make sure the offer comes from our parent partition */
-       osd_schedule_callback(newChannel->ControlWQ, VmbusChannelProcessOffer,
-                             newChannel);
-
-       DPRINT_EXIT(VMBUS);
-}
-
-/*
- * VmbusChannelOnOfferRescind - Rescind offer handler.
- *
- * We queue a work item to process this offer synchronously
- */
-static void VmbusChannelOnOfferRescind(struct vmbus_channel_message_header *hdr)
-{
-       struct vmbus_channel_rescind_offer *rescind;
-       struct vmbus_channel *channel;
-
-       DPRINT_ENTER(VMBUS);
-
-       rescind = (struct vmbus_channel_rescind_offer *)hdr;
-       channel = GetChannelFromRelId(rescind->ChildRelId);
-       if (channel == NULL) {
-               DPRINT_DBG(VMBUS, "channel not found for relId %d",
-                          rescind->ChildRelId);
-               return;
-       }
-
-       osd_schedule_callback(channel->ControlWQ,
-                             VmbusChannelProcessRescindOffer,
-                             channel);
-
-       DPRINT_EXIT(VMBUS);
-}
-
-/*
- * VmbusChannelOnOffersDelivered - This is invoked when all offers have been delivered.
- *
- * Nothing to do here.
- */
-static void VmbusChannelOnOffersDelivered(
-                       struct vmbus_channel_message_header *hdr)
-{
-       DPRINT_ENTER(VMBUS);
-       DPRINT_EXIT(VMBUS);
-}
-
-/*
- * VmbusChannelOnOpenResult - Open result handler.
- *
- * This is invoked when we received a response to our channel open request.
- * Find the matching request, copy the response and signal the requesting
- * thread.
- */
-static void VmbusChannelOnOpenResult(struct vmbus_channel_message_header *hdr)
-{
-       struct vmbus_channel_open_result *result;
-       struct list_head *curr;
-       struct vmbus_channel_msginfo *msgInfo;
-       struct vmbus_channel_message_header *requestHeader;
-       struct vmbus_channel_open_channel *openMsg;
-       unsigned long flags;
-
-       DPRINT_ENTER(VMBUS);
-
-       result = (struct vmbus_channel_open_result *)hdr;
-       DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status);
-
-       /*
-        * Find the open msg, copy the result and signal/unblock the wait event
-        */
-       spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
-
-       list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
-/* FIXME: this should probably use list_entry() instead */
-               msgInfo = (struct vmbus_channel_msginfo *)curr;
-               requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
-
-               if (requestHeader->MessageType == ChannelMessageOpenChannel) {
-                       openMsg = (struct vmbus_channel_open_channel *)msgInfo->Msg;
-                       if (openMsg->ChildRelId == result->ChildRelId &&
-                           openMsg->OpenId == result->OpenId) {
-                               memcpy(&msgInfo->Response.OpenResult,
-                                      result,
-                                      sizeof(struct vmbus_channel_open_result));
-                               osd_WaitEventSet(msgInfo->WaitEvent);
-                               break;
-                       }
-               }
-       }
-       spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
-       DPRINT_EXIT(VMBUS);
-}
-
-/*
- * VmbusChannelOnGpadlCreated - GPADL created handler.
- *
- * This is invoked when we received a response to our gpadl create request.
- * Find the matching request, copy the response and signal the requesting
- * thread.
- */
-static void VmbusChannelOnGpadlCreated(struct vmbus_channel_message_header *hdr)
-{
-       struct vmbus_channel_gpadl_created *gpadlCreated;
-       struct list_head *curr;
-       struct vmbus_channel_msginfo *msgInfo;
-       struct vmbus_channel_message_header *requestHeader;
-       struct vmbus_channel_gpadl_header *gpadlHeader;
-       unsigned long flags;
-
-       DPRINT_ENTER(VMBUS);
-
-       gpadlCreated = (struct vmbus_channel_gpadl_created *)hdr;
-       DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d",
-                  gpadlCreated->CreationStatus);
-
-       /*
-        * Find the establish msg, copy the result and signal/unblock the wait
-        * event
-        */
-       spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
-
-       list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
-/* FIXME: this should probably use list_entry() instead */
-               msgInfo = (struct vmbus_channel_msginfo *)curr;
-               requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
-
-               if (requestHeader->MessageType == ChannelMessageGpadlHeader) {
-                       gpadlHeader = (struct vmbus_channel_gpadl_header *)requestHeader;
-
-                       if ((gpadlCreated->ChildRelId ==
-                            gpadlHeader->ChildRelId) &&
-                           (gpadlCreated->Gpadl == gpadlHeader->Gpadl)) {
-                               memcpy(&msgInfo->Response.GpadlCreated,
-                                      gpadlCreated,
-                                      sizeof(struct vmbus_channel_gpadl_created));
-                               osd_WaitEventSet(msgInfo->WaitEvent);
-                               break;
-                       }
-               }
-       }
-       spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
-       DPRINT_EXIT(VMBUS);
-}
-
-/*
- * VmbusChannelOnGpadlTorndown - GPADL torndown handler.
- *
- * This is invoked when we received a response to our gpadl teardown request.
- * Find the matching request, copy the response and signal the requesting
- * thread.
- */
-static void VmbusChannelOnGpadlTorndown(
-                       struct vmbus_channel_message_header *hdr)
-{
-       struct vmbus_channel_gpadl_torndown *gpadlTorndown;
-       struct list_head *curr;
-       struct vmbus_channel_msginfo *msgInfo;
-       struct vmbus_channel_message_header *requestHeader;
-       struct vmbus_channel_gpadl_teardown *gpadlTeardown;
-       unsigned long flags;
-
-       DPRINT_ENTER(VMBUS);
-
-       gpadlTorndown = (struct vmbus_channel_gpadl_torndown *)hdr;
-
-       /*
-        * Find the open msg, copy the result and signal/unblock the wait event
-        */
-       spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
-
-       list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
-/* FIXME: this should probably use list_entry() instead */
-               msgInfo = (struct vmbus_channel_msginfo *)curr;
-               requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
-
-               if (requestHeader->MessageType == ChannelMessageGpadlTeardown) {
-                       gpadlTeardown = (struct vmbus_channel_gpadl_teardown *)requestHeader;
-
-                       if (gpadlTorndown->Gpadl == gpadlTeardown->Gpadl) {
-                               memcpy(&msgInfo->Response.GpadlTorndown,
-                                      gpadlTorndown,
-                                      sizeof(struct vmbus_channel_gpadl_torndown));
-                               osd_WaitEventSet(msgInfo->WaitEvent);
-                               break;
-                       }
-               }
-       }
-       spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
-       DPRINT_EXIT(VMBUS);
-}
-
-/*
- * VmbusChannelOnVersionResponse - Version response handler
- *
- * This is invoked when we received a response to our initiate contact request.
- * Find the matching request, copy the response and signal the requesting
- * thread.
- */
-static void VmbusChannelOnVersionResponse(
-               struct vmbus_channel_message_header *hdr)
-{
-       struct list_head *curr;
-       struct vmbus_channel_msginfo *msgInfo;
-       struct vmbus_channel_message_header *requestHeader;
-       struct vmbus_channel_initiate_contact *initiate;
-       struct vmbus_channel_version_response *versionResponse;
-       unsigned long flags;
-
-       DPRINT_ENTER(VMBUS);
-
-       versionResponse = (struct vmbus_channel_version_response *)hdr;
-       spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
-
-       list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
-/* FIXME: this should probably use list_entry() instead */
-               msgInfo = (struct vmbus_channel_msginfo *)curr;
-               requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
-
-               if (requestHeader->MessageType ==
-                   ChannelMessageInitiateContact) {
-                       initiate = (struct vmbus_channel_initiate_contact *)requestHeader;
-                       memcpy(&msgInfo->Response.VersionResponse,
-                             versionResponse,
-                             sizeof(struct vmbus_channel_version_response));
-                       osd_WaitEventSet(msgInfo->WaitEvent);
-               }
-       }
-       spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
-       DPRINT_EXIT(VMBUS);
-}
-
-/* Channel message dispatch table */
-static struct vmbus_channel_message_table_entry
-       gChannelMessageTable[ChannelMessageCount] = {
-       {ChannelMessageInvalid,                 NULL},
-       {ChannelMessageOfferChannel,            VmbusChannelOnOffer},
-       {ChannelMessageRescindChannelOffer,     VmbusChannelOnOfferRescind},
-       {ChannelMessageRequestOffers,           NULL},
-       {ChannelMessageAllOffersDelivered,      VmbusChannelOnOffersDelivered},
-       {ChannelMessageOpenChannel,             NULL},
-       {ChannelMessageOpenChannelResult,       VmbusChannelOnOpenResult},
-       {ChannelMessageCloseChannel,            NULL},
-       {ChannelMessageGpadlHeader,             NULL},
-       {ChannelMessageGpadlBody,               NULL},
-       {ChannelMessageGpadlCreated,            VmbusChannelOnGpadlCreated},
-       {ChannelMessageGpadlTeardown,           NULL},
-       {ChannelMessageGpadlTorndown,           VmbusChannelOnGpadlTorndown},
-       {ChannelMessageRelIdReleased,           NULL},
-       {ChannelMessageInitiateContact,         NULL},
-       {ChannelMessageVersionResponse,         VmbusChannelOnVersionResponse},
-       {ChannelMessageUnload,                  NULL},
-};
-
-/*
- * VmbusOnChannelMessage - Handler for channel protocol messages.
- *
- * This is invoked in the vmbus worker thread context.
- */
-void VmbusOnChannelMessage(void *Context)
-{
-       struct hv_message *msg = Context;
-       struct vmbus_channel_message_header *hdr;
-       int size;
-
-       DPRINT_ENTER(VMBUS);
-
-       hdr = (struct vmbus_channel_message_header *)msg->u.Payload;
-       size = msg->Header.PayloadSize;
-
-       DPRINT_DBG(VMBUS, "message type %d size %d", hdr->MessageType, size);
-
-       if (hdr->MessageType >= ChannelMessageCount) {
-               DPRINT_ERR(VMBUS,
-                          "Received invalid channel message type %d size %d",
-                          hdr->MessageType, size);
-               print_hex_dump_bytes("", DUMP_PREFIX_NONE,
-                                    (unsigned char *)msg->u.Payload, size);
-               kfree(msg);
-               return;
-       }
-
-       if (gChannelMessageTable[hdr->MessageType].messageHandler)
-               gChannelMessageTable[hdr->MessageType].messageHandler(hdr);
-       else
-               DPRINT_ERR(VMBUS, "Unhandled channel message type %d",
-                          hdr->MessageType);
-
-       /* Free the msg that was allocated in VmbusOnMsgDPC() */
-       kfree(msg);
-       DPRINT_EXIT(VMBUS);
-}
-
-/*
- * VmbusChannelRequestOffers - Send a request to get all our pending offers.
- */
-int VmbusChannelRequestOffers(void)
-{
-       struct vmbus_channel_message_header *msg;
-       struct vmbus_channel_msginfo *msgInfo;
-       int ret;
-
-       DPRINT_ENTER(VMBUS);
-
-       msgInfo = kmalloc(sizeof(*msgInfo) +
-                         sizeof(struct vmbus_channel_message_header),
-                         GFP_KERNEL);
-       if (!msgInfo)
-               return -ENOMEM;
-
-       msgInfo->WaitEvent = osd_WaitEventCreate();
-       if (!msgInfo->WaitEvent) {
-               kfree(msgInfo);
-               return -ENOMEM;
-       }
-
-       msg = (struct vmbus_channel_message_header *)msgInfo->Msg;
-
-       msg->MessageType = ChannelMessageRequestOffers;
-
-       /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
-       INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList,
-                        &msgInfo->msgListEntry);
-       SpinlockRelease(gVmbusConnection.channelMsgLock);*/
-
-       ret = VmbusPostMessage(msg,
-                              sizeof(struct vmbus_channel_message_header));
-       if (ret != 0) {
-               DPRINT_ERR(VMBUS, "Unable to request offers - %d", ret);
-
-               /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
-               REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
-               SpinlockRelease(gVmbusConnection.channelMsgLock);*/
-
-               goto Cleanup;
-       }
-       /* osd_WaitEventWait(msgInfo->waitEvent); */
-
-       /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
-       REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
-       SpinlockRelease(gVmbusConnection.channelMsgLock);*/
-
-
-Cleanup:
-       if (msgInfo) {
-               kfree(msgInfo->WaitEvent);
-               kfree(msgInfo);
-       }
-
-       DPRINT_EXIT(VMBUS);
-       return ret;
-}
-
-/*
- * VmbusChannelReleaseUnattachedChannels - Release channels that are
- * unattached/unconnected ie (no drivers associated)
- */
-void VmbusChannelReleaseUnattachedChannels(void)
-{
-       struct vmbus_channel *channel, *pos;
-       struct vmbus_channel *start = NULL;
-       unsigned long flags;
-
-       spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
-
-       list_for_each_entry_safe(channel, pos, &gVmbusConnection.ChannelList,
-                                ListEntry) {
-               if (channel == start)
-                       break;
-
-               if (!channel->DeviceObject->Driver) {
-                       list_del(&channel->ListEntry);
-                       DPRINT_INFO(VMBUS,
-                                   "Releasing unattached device object %p",
-                                   channel->DeviceObject);
-
-                       VmbusChildDeviceRemove(channel->DeviceObject);
-                       FreeVmbusChannel(channel);
-               } else {
-                       if (!start)
-                               start = channel;
-               }
-       }
-
-       spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
-}
-
-/* eof */
diff --git a/drivers/staging/hv/ChannelMgmt.h b/drivers/staging/hv/ChannelMgmt.h
deleted file mode 100644 (file)
index 9219199..0000000
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * Authors:
- *   Haiyang Zhang <haiyangz@microsoft.com>
- *   Hank Janssen  <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _CHANNEL_MGMT_H_
-#define _CHANNEL_MGMT_H_
-
-#include <linux/list.h>
-#include <linux/timer.h>
-#include "ring_buffer.h"
-#include "VmbusChannelInterface.h"
-#include "VmbusPacketFormat.h"
-
-/* Version 1 messages */
-enum vmbus_channel_message_type {
-       ChannelMessageInvalid                   =  0,
-       ChannelMessageOfferChannel              =  1,
-       ChannelMessageRescindChannelOffer       =  2,
-       ChannelMessageRequestOffers             =  3,
-       ChannelMessageAllOffersDelivered        =  4,
-       ChannelMessageOpenChannel               =  5,
-       ChannelMessageOpenChannelResult         =  6,
-       ChannelMessageCloseChannel              =  7,
-       ChannelMessageGpadlHeader               =  8,
-       ChannelMessageGpadlBody                 =  9,
-       ChannelMessageGpadlCreated              = 10,
-       ChannelMessageGpadlTeardown             = 11,
-       ChannelMessageGpadlTorndown             = 12,
-       ChannelMessageRelIdReleased             = 13,
-       ChannelMessageInitiateContact           = 14,
-       ChannelMessageVersionResponse           = 15,
-       ChannelMessageUnload                    = 16,
-#ifdef VMBUS_FEATURE_PARENT_OR_PEER_MEMORY_MAPPED_INTO_A_CHILD
-       ChannelMessageViewRangeAdd              = 17,
-       ChannelMessageViewRangeRemove           = 18,
-#endif
-       ChannelMessageCount
-};
-
-struct vmbus_channel_message_header {
-       enum vmbus_channel_message_type MessageType;
-       u32 Padding;
-} __attribute__((packed));
-
-/* Query VMBus Version parameters */
-struct vmbus_channel_query_vmbus_version {
-       struct vmbus_channel_message_header Header;
-       u32 Version;
-} __attribute__((packed));
-
-/* VMBus Version Supported parameters */
-struct vmbus_channel_version_supported {
-       struct vmbus_channel_message_header Header;
-       bool VersionSupported;
-} __attribute__((packed));
-
-/* Offer Channel parameters */
-struct vmbus_channel_offer_channel {
-       struct vmbus_channel_message_header Header;
-       struct vmbus_channel_offer Offer;
-       u32 ChildRelId;
-       u8 MonitorId;
-       bool MonitorAllocated;
-} __attribute__((packed));
-
-/* Rescind Offer parameters */
-struct vmbus_channel_rescind_offer {
-       struct vmbus_channel_message_header Header;
-       u32 ChildRelId;
-} __attribute__((packed));
-
-/*
- * Request Offer -- no parameters, SynIC message contains the partition ID
- * Set Snoop -- no parameters, SynIC message contains the partition ID
- * Clear Snoop -- no parameters, SynIC message contains the partition ID
- * All Offers Delivered -- no parameters, SynIC message contains the partition
- *                        ID
- * Flush Client -- no parameters, SynIC message contains the partition ID
- */
-
-/* Open Channel parameters */
-struct vmbus_channel_open_channel {
-       struct vmbus_channel_message_header Header;
-
-       /* Identifies the specific VMBus channel that is being opened. */
-       u32 ChildRelId;
-
-       /* ID making a particular open request at a channel offer unique. */
-       u32 OpenId;
-
-       /* GPADL for the channel's ring buffer. */
-       u32 RingBufferGpadlHandle;
-
-       /* GPADL for the channel's server context save area. */
-       u32 ServerContextAreaGpadlHandle;
-
-       /*
-       * The upstream ring buffer begins at offset zero in the memory
-       * described by RingBufferGpadlHandle. The downstream ring buffer
-       * follows it at this offset (in pages).
-       */
-       u32 DownstreamRingBufferPageOffset;
-
-       /* User-specific data to be passed along to the server endpoint. */
-       unsigned char UserData[MAX_USER_DEFINED_BYTES];
-} __attribute__((packed));
-
-/* Open Channel Result parameters */
-struct vmbus_channel_open_result {
-       struct vmbus_channel_message_header Header;
-       u32 ChildRelId;
-       u32 OpenId;
-       u32 Status;
-} __attribute__((packed));
-
-/* Close channel parameters; */
-struct vmbus_channel_close_channel {
-       struct vmbus_channel_message_header Header;
-       u32 ChildRelId;
-} __attribute__((packed));
-
-/* Channel Message GPADL */
-#define GPADL_TYPE_RING_BUFFER         1
-#define GPADL_TYPE_SERVER_SAVE_AREA    2
-#define GPADL_TYPE_TRANSACTION         8
-
-/*
- * The number of PFNs in a GPADL message is defined by the number of
- * pages that would be spanned by ByteCount and ByteOffset.  If the
- * implied number of PFNs won't fit in this packet, there will be a
- * follow-up packet that contains more.
- */
-struct vmbus_channel_gpadl_header {
-       struct vmbus_channel_message_header Header;
-       u32 ChildRelId;
-       u32 Gpadl;
-       u16 RangeBufLen;
-       u16 RangeCount;
-       struct gpa_range Range[0];
-} __attribute__((packed));
-
-/* This is the followup packet that contains more PFNs. */
-struct vmbus_channel_gpadl_body {
-       struct vmbus_channel_message_header Header;
-       u32 MessageNumber;
-       u32 Gpadl;
-       u64 Pfn[0];
-} __attribute__((packed));
-
-struct vmbus_channel_gpadl_created {
-       struct vmbus_channel_message_header Header;
-       u32 ChildRelId;
-       u32 Gpadl;
-       u32 CreationStatus;
-} __attribute__((packed));
-
-struct vmbus_channel_gpadl_teardown {
-       struct vmbus_channel_message_header Header;
-       u32 ChildRelId;
-       u32 Gpadl;
-} __attribute__((packed));
-
-struct vmbus_channel_gpadl_torndown {
-       struct vmbus_channel_message_header Header;
-       u32 Gpadl;
-} __attribute__((packed));
-
-#ifdef VMBUS_FEATURE_PARENT_OR_PEER_MEMORY_MAPPED_INTO_A_CHILD
-struct vmbus_channel_view_range_add {
-       struct vmbus_channel_message_header Header;
-       PHYSICAL_ADDRESS ViewRangeBase;
-       u64 ViewRangeLength;
-       u32 ChildRelId;
-} __attribute__((packed));
-
-struct vmbus_channel_view_range_remove {
-       struct vmbus_channel_message_header Header;
-       PHYSICAL_ADDRESS ViewRangeBase;
-       u32 ChildRelId;
-} __attribute__((packed));
-#endif
-
-struct vmbus_channel_relid_released {
-       struct vmbus_channel_message_header Header;
-       u32 ChildRelId;
-} __attribute__((packed));
-
-struct vmbus_channel_initiate_contact {
-       struct vmbus_channel_message_header Header;
-       u32 VMBusVersionRequested;
-       u32 Padding2;
-       u64 InterruptPage;
-       u64 MonitorPage1;
-       u64 MonitorPage2;
-} __attribute__((packed));
-
-struct vmbus_channel_version_response {
-       struct vmbus_channel_message_header Header;
-       bool VersionSupported;
-} __attribute__((packed));
-
-enum vmbus_channel_state {
-       CHANNEL_OFFER_STATE,
-       CHANNEL_OPENING_STATE,
-       CHANNEL_OPEN_STATE,
-};
-
-struct vmbus_channel {
-       struct list_head ListEntry;
-
-       struct hv_device *DeviceObject;
-
-       struct timer_list poll_timer; /* SA-111 workaround */
-
-       enum vmbus_channel_state State;
-
-       struct vmbus_channel_offer_channel OfferMsg;
-       /*
-        * These are based on the OfferMsg.MonitorId.
-        * Save it here for easy access.
-        */
-       u8 MonitorGroup;
-       u8 MonitorBit;
-
-       u32 RingBufferGpadlHandle;
-
-       /* Allocated memory for ring buffer */
-       void *RingBufferPages;
-       u32 RingBufferPageCount;
-       RING_BUFFER_INFO Outbound;      /* send to parent */
-       RING_BUFFER_INFO Inbound;       /* receive from parent */
-       spinlock_t inbound_lock;
-       struct workqueue_struct *ControlWQ;
-
-       /* Channel callback are invoked in this workqueue context */
-       /* HANDLE dataWorkQueue; */
-
-       void (*OnChannelCallback)(void *context);
-       void *ChannelCallbackContext;
-};
-
-struct vmbus_channel_debug_info {
-       u32 RelId;
-       enum vmbus_channel_state State;
-       struct hv_guid InterfaceType;
-       struct hv_guid InterfaceInstance;
-       u32 MonitorId;
-       u32 ServerMonitorPending;
-       u32 ServerMonitorLatency;
-       u32 ServerMonitorConnectionId;
-       u32 ClientMonitorPending;
-       u32 ClientMonitorLatency;
-       u32 ClientMonitorConnectionId;
-
-       RING_BUFFER_DEBUG_INFO Inbound;
-       RING_BUFFER_DEBUG_INFO Outbound;
-};
-
-/*
- * Represents each channel msg on the vmbus connection This is a
- * variable-size data structure depending on the msg type itself
- */
-struct vmbus_channel_msginfo {
-       /* Bookkeeping stuff */
-       struct list_head MsgListEntry;
-
-       /* So far, this is only used to handle gpadl body message */
-       struct list_head SubMsgList;
-
-       /* Synchronize the request/response if needed */
-       struct osd_waitevent *WaitEvent;
-
-       union {
-               struct vmbus_channel_version_supported VersionSupported;
-               struct vmbus_channel_open_result OpenResult;
-               struct vmbus_channel_gpadl_torndown GpadlTorndown;
-               struct vmbus_channel_gpadl_created GpadlCreated;
-               struct vmbus_channel_version_response VersionResponse;
-       } Response;
-
-       u32 MessageSize;
-       /*
-        * The channel message that goes out on the "wire".
-        * It will contain at minimum the VMBUS_CHANNEL_MESSAGE_HEADER header
-        */
-       unsigned char Msg[0];
-};
-
-
-struct vmbus_channel *AllocVmbusChannel(void);
-
-void FreeVmbusChannel(struct vmbus_channel *Channel);
-
-void VmbusOnChannelMessage(void *Context);
-
-int VmbusChannelRequestOffers(void);
-
-void VmbusChannelReleaseUnattachedChannels(void);
-
-#endif /* _CHANNEL_MGMT_H_ */
index 685a320..2f9ecd2 100644 (file)
@@ -6,7 +6,7 @@ obj-$(CONFIG_HYPERV_UTILS)      += hv_utils.o
 
 hv_vmbus-objs := vmbus_drv.o osd.o \
                 vmbus.o hv.o connection.o channel.o \
-                ChannelMgmt.o ChannelInterface.o ring_buffer.o
+                channel_mgmt.o ChannelInterface.o ring_buffer.o
 hv_storvsc-objs := storvsc_drv.o storvsc.o
 hv_blkvsc-objs := blkvsc_drv.o blkvsc.o
 hv_netvsc-objs := netvsc_drv.o netvsc.o rndis_filter.o
index d73baff..6e82183 100644 (file)
@@ -28,7 +28,7 @@
 #include "hv.h"
 #include "VmbusApi.h"
 #include "channel.h"
-#include "ChannelMgmt.h"
+#include "channel_mgmt.h"
 #include "ChannelInterface.h"
 #include "ring_buffer.h"
 #include <linux/list.h>
index 6b283ed..acb2c55 100644 (file)
@@ -25,7 +25,7 @@
 #ifndef _CHANNEL_H_
 #define _CHANNEL_H_
 
-#include "ChannelMgmt.h"
+#include "channel_mgmt.h"
 
 /* The format must be the same as struct vmdata_gpa_direct */
 struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER {
diff --git a/drivers/staging/hv/channel_mgmt.c b/drivers/staging/hv/channel_mgmt.c
new file mode 100644 (file)
index 0000000..3698230
--- /dev/null
@@ -0,0 +1,856 @@
+/*
+ * Copyright (c) 2009, Microsoft Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * Authors:
+ *   Haiyang Zhang <haiyangz@microsoft.com>
+ *   Hank Janssen  <hjanssen@microsoft.com>
+ */
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include "osd.h"
+#include "logging.h"
+#include "VmbusPrivate.h"
+#include "utils.h"
+
+struct vmbus_channel_message_table_entry {
+       enum vmbus_channel_message_type messageType;
+       void (*messageHandler)(struct vmbus_channel_message_header *msg);
+};
+
+#define MAX_MSG_TYPES                    2
+#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 6
+
+static const struct hv_guid
+       gSupportedDeviceClasses[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = {
+       /* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
+       /* Storage - SCSI */
+       {
+               .data  = {
+                       0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
+                       0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
+               }
+       },
+
+       /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
+       /* Network */
+       {
+               .data = {
+                       0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
+                       0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E
+               }
+       },
+
+       /* {CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} */
+       /* Input */
+       {
+               .data = {
+                       0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
+                       0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A
+               }
+       },
+
+       /* {32412632-86cb-44a2-9b5c-50d1417354f5} */
+       /* IDE */
+       {
+               .data = {
+                       0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
+                       0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
+               }
+       },
+       /* 0E0B6031-5213-4934-818B-38D90CED39DB */
+       /* Shutdown */
+       {
+               .data = {
+                       0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
+                       0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
+               }
+       },
+       /* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
+       /* TimeSync */
+       {
+               .data = {
+                       0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
+                       0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
+               }
+       },
+};
+
+
+/**
+ * prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
+ * @icmsghdrp: Pointer to msg header structure
+ * @icmsg_negotiate: Pointer to negotiate message structure
+ * @buf: Raw buffer channel data
+ *
+ * @icmsghdrp is of type &struct icmsg_hdr.
+ * @negop is of type &struct icmsg_negotiate.
+ * Set up and fill in default negotiate response message. This response can
+ * come from both the vmbus driver and the hv_utils driver. The current api
+ * will respond properly to both Windows 2008 and Windows 2008-R2 operating
+ * systems.
+ *
+ * Mainly used by Hyper-V drivers.
+ */
+void prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
+                            struct icmsg_negotiate *negop,
+                            u8 *buf)
+{
+       if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
+               icmsghdrp->icmsgsize = 0x10;
+
+               negop = (struct icmsg_negotiate *)&buf[
+                       sizeof(struct vmbuspipe_hdr) +
+                       sizeof(struct icmsg_hdr)];
+
+               if (negop->icframe_vercnt == 2 &&
+                  negop->icversion_data[1].major == 3) {
+                       negop->icversion_data[0].major = 3;
+                       negop->icversion_data[0].minor = 0;
+                       negop->icversion_data[1].major = 3;
+                       negop->icversion_data[1].minor = 0;
+               } else {
+                       negop->icversion_data[0].major = 1;
+                       negop->icversion_data[0].minor = 0;
+                       negop->icversion_data[1].major = 1;
+                       negop->icversion_data[1].minor = 0;
+               }
+
+               negop->icframe_vercnt = 1;
+               negop->icmsg_vercnt = 1;
+       }
+}
+EXPORT_SYMBOL(prep_negotiate_resp);
+
+/**
+ * chn_cb_negotiate() - Default handler for non IDE/SCSI/NETWORK
+ * Hyper-V requests
+ * @context: Pointer to argument structure.
+ *
+ * Set up the default handler for non device driver specific requests
+ * from Hyper-V. This stub responds to the default negotiate messages
+ * that come in for every non IDE/SCSI/Network request.
+ * This behavior is normally overwritten in the hv_utils driver. That
+ * driver handles requests like gracefull shutdown, heartbeats etc.
+ *
+ * Mainly used by Hyper-V drivers.
+ */
+void chn_cb_negotiate(void *context)
+{
+       struct vmbus_channel *channel = context;
+       u8 *buf;
+       u32 buflen, recvlen;
+       u64 requestid;
+
+       struct icmsg_hdr *icmsghdrp;
+       struct icmsg_negotiate *negop = NULL;
+
+       buflen = PAGE_SIZE;
+       buf = kmalloc(buflen, GFP_ATOMIC);
+
+       VmbusChannelRecvPacket(channel, buf, buflen, &recvlen, &requestid);
+
+       if (recvlen > 0) {
+               icmsghdrp = (struct icmsg_hdr *)&buf[
+                       sizeof(struct vmbuspipe_hdr)];
+
+               prep_negotiate_resp(icmsghdrp, negop, buf);
+
+               icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
+                       | ICMSGHDRFLAG_RESPONSE;
+
+               VmbusChannelSendPacket(channel, buf,
+                                      recvlen, requestid,
+                                      VmbusPacketTypeDataInBand, 0);
+       }
+
+       kfree(buf);
+}
+EXPORT_SYMBOL(chn_cb_negotiate);
+
+/*
+ * Function table used for message responses for non IDE/SCSI/Network type
+ * messages. (Such as KVP/Shutdown etc)
+ */
+struct hyperv_service_callback hv_cb_utils[MAX_MSG_TYPES] = {
+       /* 0E0B6031-5213-4934-818B-38D90CED39DB */
+       /* Shutdown */
+       {
+               .msg_type = HV_SHUTDOWN_MSG,
+               .data = {
+                       0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
+                       0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
+               },
+               .callback = chn_cb_negotiate,
+               .log_msg = "Shutdown channel functionality initialized"
+       },
+
+       /* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
+       /* TimeSync */
+       {
+               .msg_type = HV_TIMESYNC_MSG,
+               .data = {
+                       0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
+                       0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
+               },
+               .callback = chn_cb_negotiate,
+               .log_msg = "Timesync channel functionality initialized"
+       },
+};
+EXPORT_SYMBOL(hv_cb_utils);
+
+/*
+ * AllocVmbusChannel - Allocate and initialize a vmbus channel object
+ */
+struct vmbus_channel *AllocVmbusChannel(void)
+{
+       struct vmbus_channel *channel;
+
+       channel = kzalloc(sizeof(*channel), GFP_ATOMIC);
+       if (!channel)
+               return NULL;
+
+       spin_lock_init(&channel->inbound_lock);
+
+       init_timer(&channel->poll_timer);
+       channel->poll_timer.data = (unsigned long)channel;
+       channel->poll_timer.function = VmbusChannelOnTimer;
+
+       channel->ControlWQ = create_workqueue("hv_vmbus_ctl");
+       if (!channel->ControlWQ) {
+               kfree(channel);
+               return NULL;
+       }
+
+       return channel;
+}
+
+/*
+ * ReleaseVmbusChannel - Release the vmbus channel object itself
+ */
+static inline void ReleaseVmbusChannel(void *context)
+{
+       struct vmbus_channel *channel = context;
+
+       DPRINT_ENTER(VMBUS);
+
+       DPRINT_DBG(VMBUS, "releasing channel (%p)", channel);
+       destroy_workqueue(channel->ControlWQ);
+       DPRINT_DBG(VMBUS, "channel released (%p)", channel);
+
+       kfree(channel);
+
+       DPRINT_EXIT(VMBUS);
+}
+
+/*
+ * FreeVmbusChannel - Release the resources used by the vmbus channel object
+ */
+void FreeVmbusChannel(struct vmbus_channel *Channel)
+{
+       del_timer_sync(&Channel->poll_timer);
+
+       /*
+        * We have to release the channel's workqueue/thread in the vmbus's
+        * workqueue/thread context
+        * ie we can't destroy ourselves.
+        */
+       osd_schedule_callback(gVmbusConnection.WorkQueue, ReleaseVmbusChannel,
+                             Channel);
+}
+
+/*
+ * VmbusChannelProcessOffer - Process the offer by creating a channel/device
+ * associated with this offer
+ */
+static void VmbusChannelProcessOffer(void *context)
+{
+       struct vmbus_channel *newChannel = context;
+       struct vmbus_channel *channel;
+       bool fNew = true;
+       int ret;
+       int cnt;
+       unsigned long flags;
+
+       DPRINT_ENTER(VMBUS);
+
+       /* Make sure this is a new offer */
+       spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
+
+       list_for_each_entry(channel, &gVmbusConnection.ChannelList, ListEntry) {
+               if (!memcmp(&channel->OfferMsg.Offer.InterfaceType,
+                           &newChannel->OfferMsg.Offer.InterfaceType,
+                           sizeof(struct hv_guid)) &&
+                   !memcmp(&channel->OfferMsg.Offer.InterfaceInstance,
+                           &newChannel->OfferMsg.Offer.InterfaceInstance,
+                           sizeof(struct hv_guid))) {
+                       fNew = false;
+                       break;
+               }
+       }
+
+       if (fNew)
+               list_add_tail(&newChannel->ListEntry,
+                             &gVmbusConnection.ChannelList);
+
+       spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
+
+       if (!fNew) {
+               DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)",
+                          newChannel->OfferMsg.ChildRelId);
+               FreeVmbusChannel(newChannel);
+               DPRINT_EXIT(VMBUS);
+               return;
+       }
+
+       /*
+        * Start the process of binding this offer to the driver
+        * We need to set the DeviceObject field before calling
+        * VmbusChildDeviceAdd()
+        */
+       newChannel->DeviceObject = VmbusChildDeviceCreate(
+               &newChannel->OfferMsg.Offer.InterfaceType,
+               &newChannel->OfferMsg.Offer.InterfaceInstance,
+               newChannel);
+
+       DPRINT_DBG(VMBUS, "child device object allocated - %p",
+                  newChannel->DeviceObject);
+
+       /*
+        * Add the new device to the bus. This will kick off device-driver
+        * binding which eventually invokes the device driver's AddDevice()
+        * method.
+        */
+       ret = VmbusChildDeviceAdd(newChannel->DeviceObject);
+       if (ret != 0) {
+               DPRINT_ERR(VMBUS,
+                          "unable to add child device object (relid %d)",
+                          newChannel->OfferMsg.ChildRelId);
+
+               spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
+               list_del(&newChannel->ListEntry);
+               spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
+
+               FreeVmbusChannel(newChannel);
+       } else {
+               /*
+                * This state is used to indicate a successful open
+                * so that when we do close the channel normally, we
+                * can cleanup properly
+                */
+               newChannel->State = CHANNEL_OPEN_STATE;
+               cnt = 0;
+
+               while (cnt != MAX_MSG_TYPES) {
+                       if (memcmp(&newChannel->OfferMsg.Offer.InterfaceType,
+                                  &hv_cb_utils[cnt].data,
+                                  sizeof(struct hv_guid)) == 0) {
+                               DPRINT_INFO(VMBUS, "%s",
+                                           hv_cb_utils[cnt].log_msg);
+
+                               if (VmbusChannelOpen(newChannel, 2 * PAGE_SIZE,
+                                                   2 * PAGE_SIZE, NULL, 0,
+                                                   hv_cb_utils[cnt].callback,
+                                                   newChannel) == 0)
+                                       hv_cb_utils[cnt].channel = newChannel;
+                       }
+                       cnt++;
+               }
+       }
+       DPRINT_EXIT(VMBUS);
+}
+
+/*
+ * VmbusChannelProcessRescindOffer - Rescind the offer by initiating a device removal
+ */
+static void VmbusChannelProcessRescindOffer(void *context)
+{
+       struct vmbus_channel *channel = context;
+
+       DPRINT_ENTER(VMBUS);
+       VmbusChildDeviceRemove(channel->DeviceObject);
+       DPRINT_EXIT(VMBUS);
+}
+
+/*
+ * VmbusChannelOnOffer - Handler for channel offers from vmbus in parent partition.
+ *
+ * We ignore all offers except network and storage offers. For each network and
+ * storage offers, we create a channel object and queue a work item to the
+ * channel object to process the offer synchronously
+ */
+static void VmbusChannelOnOffer(struct vmbus_channel_message_header *hdr)
+{
+       struct vmbus_channel_offer_channel *offer;
+       struct vmbus_channel *newChannel;
+       struct hv_guid *guidType;
+       struct hv_guid *guidInstance;
+       int i;
+       int fSupported = 0;
+
+       DPRINT_ENTER(VMBUS);
+
+       offer = (struct vmbus_channel_offer_channel *)hdr;
+       for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
+               if (memcmp(&offer->Offer.InterfaceType,
+                   &gSupportedDeviceClasses[i], sizeof(struct hv_guid)) == 0) {
+                       fSupported = 1;
+                       break;
+               }
+       }
+
+       if (!fSupported) {
+               DPRINT_DBG(VMBUS, "Ignoring channel offer notification for "
+                          "child relid %d", offer->ChildRelId);
+               DPRINT_EXIT(VMBUS);
+               return;
+       }
+
+       guidType = &offer->Offer.InterfaceType;
+       guidInstance = &offer->Offer.InterfaceInstance;
+
+       DPRINT_INFO(VMBUS, "Channel offer notification - "
+                   "child relid %d monitor id %d allocated %d, "
+                   "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
+                   "%02x%02x%02x%02x%02x%02x%02x%02x} "
+                   "instance {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
+                   "%02x%02x%02x%02x%02x%02x%02x%02x}",
+                   offer->ChildRelId, offer->MonitorId,
+                   offer->MonitorAllocated,
+                   guidType->data[3], guidType->data[2],
+                   guidType->data[1], guidType->data[0],
+                   guidType->data[5], guidType->data[4],
+                   guidType->data[7], guidType->data[6],
+                   guidType->data[8], guidType->data[9],
+                   guidType->data[10], guidType->data[11],
+                   guidType->data[12], guidType->data[13],
+                   guidType->data[14], guidType->data[15],
+                   guidInstance->data[3], guidInstance->data[2],
+                   guidInstance->data[1], guidInstance->data[0],
+                   guidInstance->data[5], guidInstance->data[4],
+                   guidInstance->data[7], guidInstance->data[6],
+                   guidInstance->data[8], guidInstance->data[9],
+                   guidInstance->data[10], guidInstance->data[11],
+                   guidInstance->data[12], guidInstance->data[13],
+                   guidInstance->data[14], guidInstance->data[15]);
+
+       /* Allocate the channel object and save this offer. */
+       newChannel = AllocVmbusChannel();
+       if (!newChannel) {
+               DPRINT_ERR(VMBUS, "unable to allocate channel object");
+               return;
+       }
+
+       DPRINT_DBG(VMBUS, "channel object allocated - %p", newChannel);
+
+       memcpy(&newChannel->OfferMsg, offer,
+              sizeof(struct vmbus_channel_offer_channel));
+       newChannel->MonitorGroup = (u8)offer->MonitorId / 32;
+       newChannel->MonitorBit = (u8)offer->MonitorId % 32;
+
+       /* TODO: Make sure the offer comes from our parent partition */
+       osd_schedule_callback(newChannel->ControlWQ, VmbusChannelProcessOffer,
+                             newChannel);
+
+       DPRINT_EXIT(VMBUS);
+}
+
+/*
+ * VmbusChannelOnOfferRescind - Rescind offer handler.
+ *
+ * We queue a work item to process this offer synchronously
+ */
+static void VmbusChannelOnOfferRescind(struct vmbus_channel_message_header *hdr)
+{
+       struct vmbus_channel_rescind_offer *rescind;
+       struct vmbus_channel *channel;
+
+       DPRINT_ENTER(VMBUS);
+
+       rescind = (struct vmbus_channel_rescind_offer *)hdr;
+       channel = GetChannelFromRelId(rescind->ChildRelId);
+       if (channel == NULL) {
+               DPRINT_DBG(VMBUS, "channel not found for relId %d",
+                          rescind->ChildRelId);
+               return;
+       }
+
+       osd_schedule_callback(channel->ControlWQ,
+                             VmbusChannelProcessRescindOffer,
+                             channel);
+
+       DPRINT_EXIT(VMBUS);
+}
+
+/*
+ * VmbusChannelOnOffersDelivered - This is invoked when all offers have been delivered.
+ *
+ * Nothing to do here.
+ */
+static void VmbusChannelOnOffersDelivered(
+                       struct vmbus_channel_message_header *hdr)
+{
+       DPRINT_ENTER(VMBUS);
+       DPRINT_EXIT(VMBUS);
+}
+
+/*
+ * VmbusChannelOnOpenResult - Open result handler.
+ *
+ * This is invoked when we received a response to our channel open request.
+ * Find the matching request, copy the response and signal the requesting
+ * thread.
+ */
+static void VmbusChannelOnOpenResult(struct vmbus_channel_message_header *hdr)
+{
+       struct vmbus_channel_open_result *result;
+       struct list_head *curr;
+       struct vmbus_channel_msginfo *msgInfo;
+       struct vmbus_channel_message_header *requestHeader;
+       struct vmbus_channel_open_channel *openMsg;
+       unsigned long flags;
+
+       DPRINT_ENTER(VMBUS);
+
+       result = (struct vmbus_channel_open_result *)hdr;
+       DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status);
+
+       /*
+        * Find the open msg, copy the result and signal/unblock the wait event
+        */
+       spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
+
+       list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
+/* FIXME: this should probably use list_entry() instead */
+               msgInfo = (struct vmbus_channel_msginfo *)curr;
+               requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
+
+               if (requestHeader->MessageType == ChannelMessageOpenChannel) {
+                       openMsg = (struct vmbus_channel_open_channel *)msgInfo->Msg;
+                       if (openMsg->ChildRelId == result->ChildRelId &&
+                           openMsg->OpenId == result->OpenId) {
+                               memcpy(&msgInfo->Response.OpenResult,
+                                      result,
+                                      sizeof(struct vmbus_channel_open_result));
+                               osd_WaitEventSet(msgInfo->WaitEvent);
+                               break;
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
+
+       DPRINT_EXIT(VMBUS);
+}
+
+/*
+ * VmbusChannelOnGpadlCreated - GPADL created handler.
+ *
+ * This is invoked when we received a response to our gpadl create request.
+ * Find the matching request, copy the response and signal the requesting
+ * thread.
+ */
+static void VmbusChannelOnGpadlCreated(struct vmbus_channel_message_header *hdr)
+{
+       struct vmbus_channel_gpadl_created *gpadlCreated;
+       struct list_head *curr;
+       struct vmbus_channel_msginfo *msgInfo;
+       struct vmbus_channel_message_header *requestHeader;
+       struct vmbus_channel_gpadl_header *gpadlHeader;
+       unsigned long flags;
+
+       DPRINT_ENTER(VMBUS);
+
+       gpadlCreated = (struct vmbus_channel_gpadl_created *)hdr;
+       DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d",
+                  gpadlCreated->CreationStatus);
+
+       /*
+        * Find the establish msg, copy the result and signal/unblock the wait
+        * event
+        */
+       spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
+
+       list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
+/* FIXME: this should probably use list_entry() instead */
+               msgInfo = (struct vmbus_channel_msginfo *)curr;
+               requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
+
+               if (requestHeader->MessageType == ChannelMessageGpadlHeader) {
+                       gpadlHeader = (struct vmbus_channel_gpadl_header *)requestHeader;
+
+                       if ((gpadlCreated->ChildRelId ==
+                            gpadlHeader->ChildRelId) &&
+                           (gpadlCreated->Gpadl == gpadlHeader->Gpadl)) {
+                               memcpy(&msgInfo->Response.GpadlCreated,
+                                      gpadlCreated,
+                                      sizeof(struct vmbus_channel_gpadl_created));
+                               osd_WaitEventSet(msgInfo->WaitEvent);
+                               break;
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
+
+       DPRINT_EXIT(VMBUS);
+}
+
+/*
+ * VmbusChannelOnGpadlTorndown - GPADL torndown handler.
+ *
+ * This is invoked when we received a response to our gpadl teardown request.
+ * Find the matching request, copy the response and signal the requesting
+ * thread.
+ */
+static void VmbusChannelOnGpadlTorndown(
+                       struct vmbus_channel_message_header *hdr)
+{
+       struct vmbus_channel_gpadl_torndown *gpadlTorndown;
+       struct list_head *curr;
+       struct vmbus_channel_msginfo *msgInfo;
+       struct vmbus_channel_message_header *requestHeader;
+       struct vmbus_channel_gpadl_teardown *gpadlTeardown;
+       unsigned long flags;
+
+       DPRINT_ENTER(VMBUS);
+
+       gpadlTorndown = (struct vmbus_channel_gpadl_torndown *)hdr;
+
+       /*
+        * Find the open msg, copy the result and signal/unblock the wait event
+        */
+       spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
+
+       list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
+/* FIXME: this should probably use list_entry() instead */
+               msgInfo = (struct vmbus_channel_msginfo *)curr;
+               requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
+
+               if (requestHeader->MessageType == ChannelMessageGpadlTeardown) {
+                       gpadlTeardown = (struct vmbus_channel_gpadl_teardown *)requestHeader;
+
+                       if (gpadlTorndown->Gpadl == gpadlTeardown->Gpadl) {
+                               memcpy(&msgInfo->Response.GpadlTorndown,
+                                      gpadlTorndown,
+                                      sizeof(struct vmbus_channel_gpadl_torndown));
+                               osd_WaitEventSet(msgInfo->WaitEvent);
+                               break;
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
+
+       DPRINT_EXIT(VMBUS);
+}
+
+/*
+ * VmbusChannelOnVersionResponse - Version response handler
+ *
+ * This is invoked when we received a response to our initiate contact request.
+ * Find the matching request, copy the response and signal the requesting
+ * thread.
+ */
+static void VmbusChannelOnVersionResponse(
+               struct vmbus_channel_message_header *hdr)
+{
+       struct list_head *curr;
+       struct vmbus_channel_msginfo *msgInfo;
+       struct vmbus_channel_message_header *requestHeader;
+       struct vmbus_channel_initiate_contact *initiate;
+       struct vmbus_channel_version_response *versionResponse;
+       unsigned long flags;
+
+       DPRINT_ENTER(VMBUS);
+
+       versionResponse = (struct vmbus_channel_version_response *)hdr;
+       spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
+
+       list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
+/* FIXME: this should probably use list_entry() instead */
+               msgInfo = (struct vmbus_channel_msginfo *)curr;
+               requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
+
+               if (requestHeader->MessageType ==
+                   ChannelMessageInitiateContact) {
+                       initiate = (struct vmbus_channel_initiate_contact *)requestHeader;
+                       memcpy(&msgInfo->Response.VersionResponse,
+                             versionResponse,
+                             sizeof(struct vmbus_channel_version_response));
+                       osd_WaitEventSet(msgInfo->WaitEvent);
+               }
+       }
+       spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
+
+       DPRINT_EXIT(VMBUS);
+}
+
+/* Channel message dispatch table */
+static struct vmbus_channel_message_table_entry
+       gChannelMessageTable[ChannelMessageCount] = {
+       {ChannelMessageInvalid,                 NULL},
+       {ChannelMessageOfferChannel,            VmbusChannelOnOffer},
+       {ChannelMessageRescindChannelOffer,     VmbusChannelOnOfferRescind},
+       {ChannelMessageRequestOffers,           NULL},
+       {ChannelMessageAllOffersDelivered,      VmbusChannelOnOffersDelivered},
+       {ChannelMessageOpenChannel,             NULL},
+       {ChannelMessageOpenChannelResult,       VmbusChannelOnOpenResult},
+       {ChannelMessageCloseChannel,            NULL},
+       {ChannelMessageGpadlHeader,             NULL},
+       {ChannelMessageGpadlBody,               NULL},
+       {ChannelMessageGpadlCreated,            VmbusChannelOnGpadlCreated},
+       {ChannelMessageGpadlTeardown,           NULL},
+       {ChannelMessageGpadlTorndown,           VmbusChannelOnGpadlTorndown},
+       {ChannelMessageRelIdReleased,           NULL},
+       {ChannelMessageInitiateContact,         NULL},
+       {ChannelMessageVersionResponse,         VmbusChannelOnVersionResponse},
+       {ChannelMessageUnload,                  NULL},
+};
+
+/*
+ * VmbusOnChannelMessage - Handler for channel protocol messages.
+ *
+ * This is invoked in the vmbus worker thread context.
+ */
+void VmbusOnChannelMessage(void *Context)
+{
+       struct hv_message *msg = Context;
+       struct vmbus_channel_message_header *hdr;
+       int size;
+
+       DPRINT_ENTER(VMBUS);
+
+       hdr = (struct vmbus_channel_message_header *)msg->u.Payload;
+       size = msg->Header.PayloadSize;
+
+       DPRINT_DBG(VMBUS, "message type %d size %d", hdr->MessageType, size);
+
+       if (hdr->MessageType >= ChannelMessageCount) {
+               DPRINT_ERR(VMBUS,
+                          "Received invalid channel message type %d size %d",
+                          hdr->MessageType, size);
+               print_hex_dump_bytes("", DUMP_PREFIX_NONE,
+                                    (unsigned char *)msg->u.Payload, size);
+               kfree(msg);
+               return;
+       }
+
+       if (gChannelMessageTable[hdr->MessageType].messageHandler)
+               gChannelMessageTable[hdr->MessageType].messageHandler(hdr);
+       else
+               DPRINT_ERR(VMBUS, "Unhandled channel message type %d",
+                          hdr->MessageType);
+
+       /* Free the msg that was allocated in VmbusOnMsgDPC() */
+       kfree(msg);
+       DPRINT_EXIT(VMBUS);
+}
+
+/*
+ * VmbusChannelRequestOffers - Send a request to get all our pending offers.
+ */
+int VmbusChannelRequestOffers(void)
+{
+       struct vmbus_channel_message_header *msg;
+       struct vmbus_channel_msginfo *msgInfo;
+       int ret;
+
+       DPRINT_ENTER(VMBUS);
+
+       msgInfo = kmalloc(sizeof(*msgInfo) +
+                         sizeof(struct vmbus_channel_message_header),
+                         GFP_KERNEL);
+       if (!msgInfo)
+               return -ENOMEM;
+
+       msgInfo->WaitEvent = osd_WaitEventCreate();
+       if (!msgInfo->WaitEvent) {
+               kfree(msgInfo);
+               return -ENOMEM;
+       }
+
+       msg = (struct vmbus_channel_message_header *)msgInfo->Msg;
+
+       msg->MessageType = ChannelMessageRequestOffers;
+
+       /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
+       INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList,
+                        &msgInfo->msgListEntry);
+       SpinlockRelease(gVmbusConnection.channelMsgLock);*/
+
+       ret = VmbusPostMessage(msg,
+                              sizeof(struct vmbus_channel_message_header));
+       if (ret != 0) {
+               DPRINT_ERR(VMBUS, "Unable to request offers - %d", ret);
+
+               /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
+               REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
+               SpinlockRelease(gVmbusConnection.channelMsgLock);*/
+
+               goto Cleanup;
+       }
+       /* osd_WaitEventWait(msgInfo->waitEvent); */
+
+       /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
+       REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
+       SpinlockRelease(gVmbusConnection.channelMsgLock);*/
+
+
+Cleanup:
+       if (msgInfo) {
+               kfree(msgInfo->WaitEvent);
+               kfree(msgInfo);
+       }
+
+       DPRINT_EXIT(VMBUS);
+       return ret;
+}
+
+/*
+ * VmbusChannelReleaseUnattachedChannels - Release channels that are
+ * unattached/unconnected ie (no drivers associated)
+ */
+void VmbusChannelReleaseUnattachedChannels(void)
+{
+       struct vmbus_channel *channel, *pos;
+       struct vmbus_channel *start = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
+
+       list_for_each_entry_safe(channel, pos, &gVmbusConnection.ChannelList,
+                                ListEntry) {
+               if (channel == start)
+                       break;
+
+               if (!channel->DeviceObject->Driver) {
+                       list_del(&channel->ListEntry);
+                       DPRINT_INFO(VMBUS,
+                                   "Releasing unattached device object %p",
+                                   channel->DeviceObject);
+
+                       VmbusChildDeviceRemove(channel->DeviceObject);
+                       FreeVmbusChannel(channel);
+               } else {
+                       if (!start)
+                               start = channel;
+               }
+       }
+
+       spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
+}
+
+/* eof */
diff --git a/drivers/staging/hv/channel_mgmt.h b/drivers/staging/hv/channel_mgmt.h
new file mode 100644 (file)
index 0000000..9219199
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ *
+ * Copyright (c) 2009, Microsoft Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * Authors:
+ *   Haiyang Zhang <haiyangz@microsoft.com>
+ *   Hank Janssen  <hjanssen@microsoft.com>
+ *
+ */
+
+
+#ifndef _CHANNEL_MGMT_H_
+#define _CHANNEL_MGMT_H_
+
+#include <linux/list.h>
+#include <linux/timer.h>
+#include "ring_buffer.h"
+#include "VmbusChannelInterface.h"
+#include "VmbusPacketFormat.h"
+
+/* Version 1 messages */
+enum vmbus_channel_message_type {
+       ChannelMessageInvalid                   =  0,
+       ChannelMessageOfferChannel              =  1,
+       ChannelMessageRescindChannelOffer       =  2,
+       ChannelMessageRequestOffers             =  3,
+       ChannelMessageAllOffersDelivered        =  4,
+       ChannelMessageOpenChannel               =  5,
+       ChannelMessageOpenChannelResult         =  6,
+       ChannelMessageCloseChannel              =  7,
+       ChannelMessageGpadlHeader               =  8,
+       ChannelMessageGpadlBody                 =  9,
+       ChannelMessageGpadlCreated              = 10,
+       ChannelMessageGpadlTeardown             = 11,
+       ChannelMessageGpadlTorndown             = 12,
+       ChannelMessageRelIdReleased             = 13,
+       ChannelMessageInitiateContact           = 14,
+       ChannelMessageVersionResponse           = 15,
+       ChannelMessageUnload                    = 16,
+#ifdef VMBUS_FEATURE_PARENT_OR_PEER_MEMORY_MAPPED_INTO_A_CHILD
+       ChannelMessageViewRangeAdd              = 17,
+       ChannelMessageViewRangeRemove           = 18,
+#endif
+       ChannelMessageCount
+};
+
+struct vmbus_channel_message_header {
+       enum vmbus_channel_message_type MessageType;
+       u32 Padding;
+} __attribute__((packed));
+
+/* Query VMBus Version parameters */
+struct vmbus_channel_query_vmbus_version {
+       struct vmbus_channel_message_header Header;
+       u32 Version;
+} __attribute__((packed));
+
+/* VMBus Version Supported parameters */
+struct vmbus_channel_version_supported {
+       struct vmbus_channel_message_header Header;
+       bool VersionSupported;
+} __attribute__((packed));
+
+/* Offer Channel parameters */
+struct vmbus_channel_offer_channel {
+       struct vmbus_channel_message_header Header;
+       struct vmbus_channel_offer Offer;
+       u32 ChildRelId;
+       u8 MonitorId;
+       bool MonitorAllocated;
+} __attribute__((packed));
+
+/* Rescind Offer parameters */
+struct vmbus_channel_rescind_offer {
+       struct vmbus_channel_message_header Header;
+       u32 ChildRelId;
+} __attribute__((packed));
+
+/*
+ * Request Offer -- no parameters, SynIC message contains the partition ID
+ * Set Snoop -- no parameters, SynIC message contains the partition ID
+ * Clear Snoop -- no parameters, SynIC message contains the partition ID
+ * All Offers Delivered -- no parameters, SynIC message contains the partition
+ *                        ID
+ * Flush Client -- no parameters, SynIC message contains the partition ID
+ */
+
+/* Open Channel parameters */
+struct vmbus_channel_open_channel {
+       struct vmbus_channel_message_header Header;
+
+       /* Identifies the specific VMBus channel that is being opened. */
+       u32 ChildRelId;
+
+       /* ID making a particular open request at a channel offer unique. */
+       u32 OpenId;
+
+       /* GPADL for the channel's ring buffer. */
+       u32 RingBufferGpadlHandle;
+
+       /* GPADL for the channel's server context save area. */
+       u32 ServerContextAreaGpadlHandle;
+
+       /*
+       * The upstream ring buffer begins at offset zero in the memory
+       * described by RingBufferGpadlHandle. The downstream ring buffer
+       * follows it at this offset (in pages).
+       */
+       u32 DownstreamRingBufferPageOffset;
+
+       /* User-specific data to be passed along to the server endpoint. */
+       unsigned char UserData[MAX_USER_DEFINED_BYTES];
+} __attribute__((packed));
+
+/* Open Channel Result parameters */
+struct vmbus_channel_open_result {
+       struct vmbus_channel_message_header Header;
+       u32 ChildRelId;
+       u32 OpenId;
+       u32 Status;
+} __attribute__((packed));
+
+/* Close channel parameters; */
+struct vmbus_channel_close_channel {
+       struct vmbus_channel_message_header Header;
+       u32 ChildRelId;
+} __attribute__((packed));
+
+/* Channel Message GPADL */
+#define GPADL_TYPE_RING_BUFFER         1
+#define GPADL_TYPE_SERVER_SAVE_AREA    2
+#define GPADL_TYPE_TRANSACTION         8
+
+/*
+ * The number of PFNs in a GPADL message is defined by the number of
+ * pages that would be spanned by ByteCount and ByteOffset.  If the
+ * implied number of PFNs won't fit in this packet, there will be a
+ * follow-up packet that contains more.
+ */
+struct vmbus_channel_gpadl_header {
+       struct vmbus_channel_message_header Header;
+       u32 ChildRelId;
+       u32 Gpadl;
+       u16 RangeBufLen;
+       u16 RangeCount;
+       struct gpa_range Range[0];
+} __attribute__((packed));
+
+/* This is the followup packet that contains more PFNs. */
+struct vmbus_channel_gpadl_body {
+       struct vmbus_channel_message_header Header;
+       u32 MessageNumber;
+       u32 Gpadl;
+       u64 Pfn[0];
+} __attribute__((packed));
+
+struct vmbus_channel_gpadl_created {
+       struct vmbus_channel_message_header Header;
+       u32 ChildRelId;
+       u32 Gpadl;
+       u32 CreationStatus;
+} __attribute__((packed));
+
+struct vmbus_channel_gpadl_teardown {
+       struct vmbus_channel_message_header Header;
+       u32 ChildRelId;
+       u32 Gpadl;
+} __attribute__((packed));
+
+struct vmbus_channel_gpadl_torndown {
+       struct vmbus_channel_message_header Header;
+       u32 Gpadl;
+} __attribute__((packed));
+
+#ifdef VMBUS_FEATURE_PARENT_OR_PEER_MEMORY_MAPPED_INTO_A_CHILD
+struct vmbus_channel_view_range_add {
+       struct vmbus_channel_message_header Header;
+       PHYSICAL_ADDRESS ViewRangeBase;
+       u64 ViewRangeLength;
+       u32 ChildRelId;
+} __attribute__((packed));
+
+struct vmbus_channel_view_range_remove {
+       struct vmbus_channel_message_header Header;
+       PHYSICAL_ADDRESS ViewRangeBase;
+       u32 ChildRelId;
+} __attribute__((packed));
+#endif
+
+struct vmbus_channel_relid_released {
+       struct vmbus_channel_message_header Header;
+       u32 ChildRelId;
+} __attribute__((packed));
+
+struct vmbus_channel_initiate_contact {
+       struct vmbus_channel_message_header Header;
+       u32 VMBusVersionRequested;
+       u32 Padding2;
+       u64 InterruptPage;
+       u64 MonitorPage1;
+       u64 MonitorPage2;
+} __attribute__((packed));
+
+struct vmbus_channel_version_response {
+       struct vmbus_channel_message_header Header;
+       bool VersionSupported;
+} __attribute__((packed));
+
+enum vmbus_channel_state {
+       CHANNEL_OFFER_STATE,
+       CHANNEL_OPENING_STATE,
+       CHANNEL_OPEN_STATE,
+};
+
+struct vmbus_channel {
+       struct list_head ListEntry;
+
+       struct hv_device *DeviceObject;
+
+       struct timer_list poll_timer; /* SA-111 workaround */
+
+       enum vmbus_channel_state State;
+
+       struct vmbus_channel_offer_channel OfferMsg;
+       /*
+        * These are based on the OfferMsg.MonitorId.
+        * Save it here for easy access.
+        */
+       u8 MonitorGroup;
+       u8 MonitorBit;
+
+       u32 RingBufferGpadlHandle;
+
+       /* Allocated memory for ring buffer */
+       void *RingBufferPages;
+       u32 RingBufferPageCount;
+       RING_BUFFER_INFO Outbound;      /* send to parent */
+       RING_BUFFER_INFO Inbound;       /* receive from parent */
+       spinlock_t inbound_lock;
+       struct workqueue_struct *ControlWQ;
+
+       /* Channel callback are invoked in this workqueue context */
+       /* HANDLE dataWorkQueue; */
+
+       void (*OnChannelCallback)(void *context);
+       void *ChannelCallbackContext;
+};
+
+struct vmbus_channel_debug_info {
+       u32 RelId;
+       enum vmbus_channel_state State;
+       struct hv_guid InterfaceType;
+       struct hv_guid InterfaceInstance;
+       u32 MonitorId;
+       u32 ServerMonitorPending;
+       u32 ServerMonitorLatency;
+       u32 ServerMonitorConnectionId;
+       u32 ClientMonitorPending;
+       u32 ClientMonitorLatency;
+       u32 ClientMonitorConnectionId;
+
+       RING_BUFFER_DEBUG_INFO Inbound;
+       RING_BUFFER_DEBUG_INFO Outbound;
+};
+
+/*
+ * Represents each channel msg on the vmbus connection This is a
+ * variable-size data structure depending on the msg type itself
+ */
+struct vmbus_channel_msginfo {
+       /* Bookkeeping stuff */
+       struct list_head MsgListEntry;
+
+       /* So far, this is only used to handle gpadl body message */
+       struct list_head SubMsgList;
+
+       /* Synchronize the request/response if needed */
+       struct osd_waitevent *WaitEvent;
+
+       union {
+               struct vmbus_channel_version_supported VersionSupported;
+               struct vmbus_channel_open_result OpenResult;
+               struct vmbus_channel_gpadl_torndown GpadlTorndown;
+               struct vmbus_channel_gpadl_created GpadlCreated;
+               struct vmbus_channel_version_response VersionResponse;
+       } Response;
+
+       u32 MessageSize;
+       /*
+        * The channel message that goes out on the "wire".
+        * It will contain at minimum the VMBUS_CHANNEL_MESSAGE_HEADER header
+        */
+       unsigned char Msg[0];
+};
+
+
+struct vmbus_channel *AllocVmbusChannel(void);
+
+void FreeVmbusChannel(struct vmbus_channel *Channel);
+
+void VmbusOnChannelMessage(void *Context);
+
+int VmbusChannelRequestOffers(void);
+
+void VmbusChannelReleaseUnattachedChannels(void);
+
+#endif /* _CHANNEL_MGMT_H_ */