drm/radeon/kms: enable use of unmappable VRAM V2
[pandora-kernel.git] / drivers / staging / hv / ChannelMgmt.c
1 /*
2  * Copyright (c) 2009, Microsoft Corporation.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License along with
14  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15  * Place - Suite 330, Boston, MA 02111-1307 USA.
16  *
17  * Authors:
18  *   Haiyang Zhang <haiyangz@microsoft.com>
19  *   Hank Janssen  <hjanssen@microsoft.com>
20  */
21 #include <linux/kernel.h>
22 #include <linux/mm.h>
23 #include <linux/list.h>
24 #include "osd.h"
25 #include "logging.h"
26 #include "VmbusPrivate.h"
27
28 struct vmbus_channel_message_table_entry {
29         enum vmbus_channel_message_type messageType;
30         void (*messageHandler)(struct vmbus_channel_message_header *msg);
31 };
32
33 #define MAX_NUM_DEVICE_CLASSES_SUPPORTED 4
34 static const struct hv_guid
35                 gSupportedDeviceClasses[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = {
36         /* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
37         /* Storage - SCSI */
38         {
39                 .data  = {
40                         0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
41                         0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
42                 }
43         },
44
45         /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
46         /* Network */
47         {
48                 .data = {
49                         0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
50                         0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E
51                 }
52         },
53
54         /* {CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} */
55         /* Input */
56         {
57                 .data = {
58                         0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
59                         0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A
60                 }
61         },
62
63         /* {32412632-86cb-44a2-9b5c-50d1417354f5} */
64         /* IDE */
65         {
66                 .data = {
67                         0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
68                         0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
69                 }
70         },
71 };
72
73 /**
74  * AllocVmbusChannel - Allocate and initialize a vmbus channel object
75  */
76 struct vmbus_channel *AllocVmbusChannel(void)
77 {
78         struct vmbus_channel *channel;
79
80         channel = kzalloc(sizeof(*channel), GFP_ATOMIC);
81         if (!channel)
82                 return NULL;
83
84         spin_lock_init(&channel->inbound_lock);
85
86         init_timer(&channel->poll_timer);
87         channel->poll_timer.data = (unsigned long)channel;
88         channel->poll_timer.function = VmbusChannelOnTimer;
89
90         channel->ControlWQ = create_workqueue("hv_vmbus_ctl");
91         if (!channel->ControlWQ) {
92                 kfree(channel);
93                 return NULL;
94         }
95
96         return channel;
97 }
98
99 /**
100  * ReleaseVmbusChannel - Release the vmbus channel object itself
101  */
102 static inline void ReleaseVmbusChannel(void *context)
103 {
104         struct vmbus_channel *channel = context;
105
106         DPRINT_ENTER(VMBUS);
107
108         DPRINT_DBG(VMBUS, "releasing channel (%p)", channel);
109         destroy_workqueue(channel->ControlWQ);
110         DPRINT_DBG(VMBUS, "channel released (%p)", channel);
111
112         kfree(channel);
113
114         DPRINT_EXIT(VMBUS);
115 }
116
117 /**
118  * FreeVmbusChannel - Release the resources used by the vmbus channel object
119  */
120 void FreeVmbusChannel(struct vmbus_channel *Channel)
121 {
122         del_timer_sync(&Channel->poll_timer);
123
124         /*
125          * We have to release the channel's workqueue/thread in the vmbus's
126          * workqueue/thread context
127          * ie we can't destroy ourselves.
128          */
129         osd_schedule_callback(gVmbusConnection.WorkQueue, ReleaseVmbusChannel,
130                               Channel);
131 }
132
133 /**
134  * VmbusChannelProcessOffer - Process the offer by creating a channel/device associated with this offer
135  */
136 static void VmbusChannelProcessOffer(void *context)
137 {
138         struct vmbus_channel *newChannel = context;
139         struct vmbus_channel *channel;
140         bool fNew = true;
141         int ret;
142         unsigned long flags;
143
144         DPRINT_ENTER(VMBUS);
145
146         /* Make sure this is a new offer */
147         spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
148
149         list_for_each_entry(channel, &gVmbusConnection.ChannelList, ListEntry) {
150                 if (!memcmp(&channel->OfferMsg.Offer.InterfaceType,
151                             &newChannel->OfferMsg.Offer.InterfaceType,
152                             sizeof(struct hv_guid)) &&
153                     !memcmp(&channel->OfferMsg.Offer.InterfaceInstance,
154                             &newChannel->OfferMsg.Offer.InterfaceInstance,
155                             sizeof(struct hv_guid))) {
156                         fNew = false;
157                         break;
158                 }
159         }
160
161         if (fNew)
162                 list_add_tail(&newChannel->ListEntry,
163                               &gVmbusConnection.ChannelList);
164
165         spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
166
167         if (!fNew) {
168                 DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)",
169                            newChannel->OfferMsg.ChildRelId);
170                 FreeVmbusChannel(newChannel);
171                 DPRINT_EXIT(VMBUS);
172                 return;
173         }
174
175         /*
176          * Start the process of binding this offer to the driver
177          * We need to set the DeviceObject field before calling
178          * VmbusChildDeviceAdd()
179          */
180         newChannel->DeviceObject = VmbusChildDeviceCreate(
181                 &newChannel->OfferMsg.Offer.InterfaceType,
182                 &newChannel->OfferMsg.Offer.InterfaceInstance,
183                 newChannel);
184
185         DPRINT_DBG(VMBUS, "child device object allocated - %p",
186                    newChannel->DeviceObject);
187
188         /*
189          * Add the new device to the bus. This will kick off device-driver
190          * binding which eventually invokes the device driver's AddDevice()
191          * method.
192          */
193         ret = VmbusChildDeviceAdd(newChannel->DeviceObject);
194         if (ret != 0) {
195                 DPRINT_ERR(VMBUS,
196                            "unable to add child device object (relid %d)",
197                            newChannel->OfferMsg.ChildRelId);
198
199                 spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
200                 list_del(&newChannel->ListEntry);
201                 spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
202
203                 FreeVmbusChannel(newChannel);
204         } else {
205                 /*
206                  * This state is used to indicate a successful open
207                  * so that when we do close the channel normally, we
208                  * can cleanup properly
209                  */
210                 newChannel->State = CHANNEL_OPEN_STATE;
211         }
212         DPRINT_EXIT(VMBUS);
213 }
214
215 /**
216  * VmbusChannelProcessRescindOffer - Rescind the offer by initiating a device removal
217  */
218 static void VmbusChannelProcessRescindOffer(void *context)
219 {
220         struct vmbus_channel *channel = context;
221
222         DPRINT_ENTER(VMBUS);
223         VmbusChildDeviceRemove(channel->DeviceObject);
224         DPRINT_EXIT(VMBUS);
225 }
226
227 /**
228  * VmbusChannelOnOffer - Handler for channel offers from vmbus in parent partition.
229  *
230  * We ignore all offers except network and storage offers. For each network and
231  * storage offers, we create a channel object and queue a work item to the
232  * channel object to process the offer synchronously
233  */
234 static void VmbusChannelOnOffer(struct vmbus_channel_message_header *hdr)
235 {
236         struct vmbus_channel_offer_channel *offer;
237         struct vmbus_channel *newChannel;
238         struct hv_guid *guidType;
239         struct hv_guid *guidInstance;
240         int i;
241         int fSupported = 0;
242
243         DPRINT_ENTER(VMBUS);
244
245         offer = (struct vmbus_channel_offer_channel *)hdr;
246         for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
247                 if (memcmp(&offer->Offer.InterfaceType,
248                     &gSupportedDeviceClasses[i], sizeof(struct hv_guid)) == 0) {
249                         fSupported = 1;
250                         break;
251                 }
252         }
253
254         if (!fSupported) {
255                 DPRINT_DBG(VMBUS, "Ignoring channel offer notification for "
256                            "child relid %d", offer->ChildRelId);
257                 DPRINT_EXIT(VMBUS);
258                 return;
259         }
260
261         guidType = &offer->Offer.InterfaceType;
262         guidInstance = &offer->Offer.InterfaceInstance;
263
264         DPRINT_INFO(VMBUS, "Channel offer notification - "
265                     "child relid %d monitor id %d allocated %d, "
266                     "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
267                     "%02x%02x%02x%02x%02x%02x%02x%02x} "
268                     "instance {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
269                     "%02x%02x%02x%02x%02x%02x%02x%02x}",
270                     offer->ChildRelId, offer->MonitorId,
271                     offer->MonitorAllocated,
272                     guidType->data[3], guidType->data[2],
273                     guidType->data[1], guidType->data[0],
274                     guidType->data[5], guidType->data[4],
275                     guidType->data[7], guidType->data[6],
276                     guidType->data[8], guidType->data[9],
277                     guidType->data[10], guidType->data[11],
278                     guidType->data[12], guidType->data[13],
279                     guidType->data[14], guidType->data[15],
280                     guidInstance->data[3], guidInstance->data[2],
281                     guidInstance->data[1], guidInstance->data[0],
282                     guidInstance->data[5], guidInstance->data[4],
283                     guidInstance->data[7], guidInstance->data[6],
284                     guidInstance->data[8], guidInstance->data[9],
285                     guidInstance->data[10], guidInstance->data[11],
286                     guidInstance->data[12], guidInstance->data[13],
287                     guidInstance->data[14], guidInstance->data[15]);
288
289         /* Allocate the channel object and save this offer. */
290         newChannel = AllocVmbusChannel();
291         if (!newChannel) {
292                 DPRINT_ERR(VMBUS, "unable to allocate channel object");
293                 return;
294         }
295
296         DPRINT_DBG(VMBUS, "channel object allocated - %p", newChannel);
297
298         memcpy(&newChannel->OfferMsg, offer,
299                sizeof(struct vmbus_channel_offer_channel));
300         newChannel->MonitorGroup = (u8)offer->MonitorId / 32;
301         newChannel->MonitorBit = (u8)offer->MonitorId % 32;
302
303         /* TODO: Make sure the offer comes from our parent partition */
304         osd_schedule_callback(newChannel->ControlWQ, VmbusChannelProcessOffer,
305                               newChannel);
306
307         DPRINT_EXIT(VMBUS);
308 }
309
310 /**
311  * VmbusChannelOnOfferRescind - Rescind offer handler.
312  *
313  * We queue a work item to process this offer synchronously
314  */
315 static void VmbusChannelOnOfferRescind(struct vmbus_channel_message_header *hdr)
316 {
317         struct vmbus_channel_rescind_offer *rescind;
318         struct vmbus_channel *channel;
319
320         DPRINT_ENTER(VMBUS);
321
322         rescind = (struct vmbus_channel_rescind_offer *)hdr;
323         channel = GetChannelFromRelId(rescind->ChildRelId);
324         if (channel == NULL) {
325                 DPRINT_DBG(VMBUS, "channel not found for relId %d",
326                            rescind->ChildRelId);
327                 return;
328         }
329
330         osd_schedule_callback(channel->ControlWQ,
331                               VmbusChannelProcessRescindOffer,
332                               channel);
333
334         DPRINT_EXIT(VMBUS);
335 }
336
337 /**
338  * VmbusChannelOnOffersDelivered - This is invoked when all offers have been delivered.
339  *
340  * Nothing to do here.
341  */
342 static void VmbusChannelOnOffersDelivered(
343                         struct vmbus_channel_message_header *hdr)
344 {
345         DPRINT_ENTER(VMBUS);
346         DPRINT_EXIT(VMBUS);
347 }
348
349 /**
350  * VmbusChannelOnOpenResult - Open result handler.
351  *
352  * This is invoked when we received a response to our channel open request.
353  * Find the matching request, copy the response and signal the requesting
354  * thread.
355  */
356 static void VmbusChannelOnOpenResult(struct vmbus_channel_message_header *hdr)
357 {
358         struct vmbus_channel_open_result *result;
359         struct list_head *curr;
360         struct vmbus_channel_msginfo *msgInfo;
361         struct vmbus_channel_message_header *requestHeader;
362         struct vmbus_channel_open_channel *openMsg;
363         unsigned long flags;
364
365         DPRINT_ENTER(VMBUS);
366
367         result = (struct vmbus_channel_open_result *)hdr;
368         DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status);
369
370         /*
371          * Find the open msg, copy the result and signal/unblock the wait event
372          */
373         spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
374
375         list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
376 /* FIXME: this should probably use list_entry() instead */
377                 msgInfo = (struct vmbus_channel_msginfo *)curr;
378                 requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
379
380                 if (requestHeader->MessageType == ChannelMessageOpenChannel) {
381                         openMsg = (struct vmbus_channel_open_channel *)msgInfo->Msg;
382                         if (openMsg->ChildRelId == result->ChildRelId &&
383                             openMsg->OpenId == result->OpenId) {
384                                 memcpy(&msgInfo->Response.OpenResult,
385                                        result,
386                                        sizeof(struct vmbus_channel_open_result));
387                                 osd_WaitEventSet(msgInfo->WaitEvent);
388                                 break;
389                         }
390                 }
391         }
392         spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
393
394         DPRINT_EXIT(VMBUS);
395 }
396
397 /**
398  * VmbusChannelOnGpadlCreated - GPADL created handler.
399  *
400  * This is invoked when we received a response to our gpadl create request.
401  * Find the matching request, copy the response and signal the requesting
402  * thread.
403  */
404 static void VmbusChannelOnGpadlCreated(struct vmbus_channel_message_header *hdr)
405 {
406         struct vmbus_channel_gpadl_created *gpadlCreated;
407         struct list_head *curr;
408         struct vmbus_channel_msginfo *msgInfo;
409         struct vmbus_channel_message_header *requestHeader;
410         struct vmbus_channel_gpadl_header *gpadlHeader;
411         unsigned long flags;
412
413         DPRINT_ENTER(VMBUS);
414
415         gpadlCreated = (struct vmbus_channel_gpadl_created *)hdr;
416         DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d",
417                    gpadlCreated->CreationStatus);
418
419         /*
420          * Find the establish msg, copy the result and signal/unblock the wait
421          * event
422          */
423         spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
424
425         list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
426 /* FIXME: this should probably use list_entry() instead */
427                 msgInfo = (struct vmbus_channel_msginfo *)curr;
428                 requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
429
430                 if (requestHeader->MessageType == ChannelMessageGpadlHeader) {
431                         gpadlHeader = (struct vmbus_channel_gpadl_header *)requestHeader;
432
433                         if ((gpadlCreated->ChildRelId ==
434                              gpadlHeader->ChildRelId) &&
435                             (gpadlCreated->Gpadl == gpadlHeader->Gpadl)) {
436                                 memcpy(&msgInfo->Response.GpadlCreated,
437                                        gpadlCreated,
438                                        sizeof(struct vmbus_channel_gpadl_created));
439                                 osd_WaitEventSet(msgInfo->WaitEvent);
440                                 break;
441                         }
442                 }
443         }
444         spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
445
446         DPRINT_EXIT(VMBUS);
447 }
448
449 /**
450  * VmbusChannelOnGpadlTorndown - GPADL torndown handler.
451  *
452  * This is invoked when we received a response to our gpadl teardown request.
453  * Find the matching request, copy the response and signal the requesting
454  * thread.
455  */
456 static void VmbusChannelOnGpadlTorndown(
457                         struct vmbus_channel_message_header *hdr)
458 {
459         struct vmbus_channel_gpadl_torndown *gpadlTorndown;
460         struct list_head *curr;
461         struct vmbus_channel_msginfo *msgInfo;
462         struct vmbus_channel_message_header *requestHeader;
463         struct vmbus_channel_gpadl_teardown *gpadlTeardown;
464         unsigned long flags;
465
466         DPRINT_ENTER(VMBUS);
467
468         gpadlTorndown = (struct vmbus_channel_gpadl_torndown *)hdr;
469
470         /*
471          * Find the open msg, copy the result and signal/unblock the wait event
472          */
473         spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
474
475         list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
476 /* FIXME: this should probably use list_entry() instead */
477                 msgInfo = (struct vmbus_channel_msginfo *)curr;
478                 requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
479
480                 if (requestHeader->MessageType == ChannelMessageGpadlTeardown) {
481                         gpadlTeardown = (struct vmbus_channel_gpadl_teardown *)requestHeader;
482
483                         if (gpadlTorndown->Gpadl == gpadlTeardown->Gpadl) {
484                                 memcpy(&msgInfo->Response.GpadlTorndown,
485                                        gpadlTorndown,
486                                        sizeof(struct vmbus_channel_gpadl_torndown));
487                                 osd_WaitEventSet(msgInfo->WaitEvent);
488                                 break;
489                         }
490                 }
491         }
492         spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
493
494         DPRINT_EXIT(VMBUS);
495 }
496
497 /**
498  * VmbusChannelOnVersionResponse - Version response handler
499  *
500  * This is invoked when we received a response to our initiate contact request.
501  * Find the matching request, copy the response and signal the requesting
502  * thread.
503  */
504 static void VmbusChannelOnVersionResponse(
505                 struct vmbus_channel_message_header *hdr)
506 {
507         struct list_head *curr;
508         struct vmbus_channel_msginfo *msgInfo;
509         struct vmbus_channel_message_header *requestHeader;
510         struct vmbus_channel_initiate_contact *initiate;
511         struct vmbus_channel_version_response *versionResponse;
512         unsigned long flags;
513
514         DPRINT_ENTER(VMBUS);
515
516         versionResponse = (struct vmbus_channel_version_response *)hdr;
517         spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
518
519         list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
520 /* FIXME: this should probably use list_entry() instead */
521                 msgInfo = (struct vmbus_channel_msginfo *)curr;
522                 requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
523
524                 if (requestHeader->MessageType ==
525                     ChannelMessageInitiateContact) {
526                         initiate = (struct vmbus_channel_initiate_contact *)requestHeader;
527                         memcpy(&msgInfo->Response.VersionResponse,
528                               versionResponse,
529                               sizeof(struct vmbus_channel_version_response));
530                         osd_WaitEventSet(msgInfo->WaitEvent);
531                 }
532         }
533         spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
534
535         DPRINT_EXIT(VMBUS);
536 }
537
538 /* Channel message dispatch table */
539 static struct vmbus_channel_message_table_entry
540         gChannelMessageTable[ChannelMessageCount] = {
541         {ChannelMessageInvalid,                 NULL},
542         {ChannelMessageOfferChannel,            VmbusChannelOnOffer},
543         {ChannelMessageRescindChannelOffer,     VmbusChannelOnOfferRescind},
544         {ChannelMessageRequestOffers,           NULL},
545         {ChannelMessageAllOffersDelivered,      VmbusChannelOnOffersDelivered},
546         {ChannelMessageOpenChannel,             NULL},
547         {ChannelMessageOpenChannelResult,       VmbusChannelOnOpenResult},
548         {ChannelMessageCloseChannel,            NULL},
549         {ChannelMessageGpadlHeader,             NULL},
550         {ChannelMessageGpadlBody,               NULL},
551         {ChannelMessageGpadlCreated,            VmbusChannelOnGpadlCreated},
552         {ChannelMessageGpadlTeardown,           NULL},
553         {ChannelMessageGpadlTorndown,           VmbusChannelOnGpadlTorndown},
554         {ChannelMessageRelIdReleased,           NULL},
555         {ChannelMessageInitiateContact,         NULL},
556         {ChannelMessageVersionResponse,         VmbusChannelOnVersionResponse},
557         {ChannelMessageUnload,                  NULL},
558 };
559
560 /**
561  * VmbusOnChannelMessage - Handler for channel protocol messages.
562  *
563  * This is invoked in the vmbus worker thread context.
564  */
565 void VmbusOnChannelMessage(void *Context)
566 {
567         struct hv_message *msg = Context;
568         struct vmbus_channel_message_header *hdr;
569         int size;
570
571         DPRINT_ENTER(VMBUS);
572
573         hdr = (struct vmbus_channel_message_header *)msg->u.Payload;
574         size = msg->Header.PayloadSize;
575
576         DPRINT_DBG(VMBUS, "message type %d size %d", hdr->MessageType, size);
577
578         if (hdr->MessageType >= ChannelMessageCount) {
579                 DPRINT_ERR(VMBUS,
580                            "Received invalid channel message type %d size %d",
581                            hdr->MessageType, size);
582                 print_hex_dump_bytes("", DUMP_PREFIX_NONE,
583                                      (unsigned char *)msg->u.Payload, size);
584                 kfree(msg);
585                 return;
586         }
587
588         if (gChannelMessageTable[hdr->MessageType].messageHandler)
589                 gChannelMessageTable[hdr->MessageType].messageHandler(hdr);
590         else
591                 DPRINT_ERR(VMBUS, "Unhandled channel message type %d",
592                            hdr->MessageType);
593
594         /* Free the msg that was allocated in VmbusOnMsgDPC() */
595         kfree(msg);
596         DPRINT_EXIT(VMBUS);
597 }
598
599 /**
600  * VmbusChannelRequestOffers - Send a request to get all our pending offers.
601  */
602 int VmbusChannelRequestOffers(void)
603 {
604         struct vmbus_channel_message_header *msg;
605         struct vmbus_channel_msginfo *msgInfo;
606         int ret;
607
608         DPRINT_ENTER(VMBUS);
609
610         msgInfo = kmalloc(sizeof(*msgInfo) +
611                           sizeof(struct vmbus_channel_message_header),
612                           GFP_KERNEL);
613         ASSERT(msgInfo != NULL);
614
615         msgInfo->WaitEvent = osd_WaitEventCreate();
616         msg = (struct vmbus_channel_message_header *)msgInfo->Msg;
617
618         msg->MessageType = ChannelMessageRequestOffers;
619
620         /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
621         INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList,
622                          &msgInfo->msgListEntry);
623         SpinlockRelease(gVmbusConnection.channelMsgLock);*/
624
625         ret = VmbusPostMessage(msg,
626                                sizeof(struct vmbus_channel_message_header));
627         if (ret != 0) {
628                 DPRINT_ERR(VMBUS, "Unable to request offers - %d", ret);
629
630                 /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
631                 REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
632                 SpinlockRelease(gVmbusConnection.channelMsgLock);*/
633
634                 goto Cleanup;
635         }
636         /* osd_WaitEventWait(msgInfo->waitEvent); */
637
638         /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
639         REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
640         SpinlockRelease(gVmbusConnection.channelMsgLock);*/
641
642
643 Cleanup:
644         if (msgInfo) {
645                 kfree(msgInfo->WaitEvent);
646                 kfree(msgInfo);
647         }
648
649         DPRINT_EXIT(VMBUS);
650         return ret;
651 }
652
653 /**
654  * VmbusChannelReleaseUnattachedChannels - Release channels that are unattached/unconnected ie (no drivers associated)
655  */
656 void VmbusChannelReleaseUnattachedChannels(void)
657 {
658         struct vmbus_channel *channel, *pos;
659         struct vmbus_channel *start = NULL;
660         unsigned long flags;
661
662         spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
663
664         list_for_each_entry_safe(channel, pos, &gVmbusConnection.ChannelList,
665                                  ListEntry) {
666                 if (channel == start)
667                         break;
668
669                 if (!channel->DeviceObject->Driver) {
670                         list_del(&channel->ListEntry);
671                         DPRINT_INFO(VMBUS,
672                                     "Releasing unattached device object %p",
673                                     channel->DeviceObject);
674
675                         VmbusChildDeviceRemove(channel->DeviceObject);
676                         FreeVmbusChannel(channel);
677                 } else {
678                         if (!start)
679                                 start = channel;
680                 }
681         }
682
683         spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
684 }
685
686 /* eof */