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