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