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