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