3 * Copyright (c) 2009, Microsoft Corporation.
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.
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
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.
19 * Haiyang Zhang <haiyangz@microsoft.com>
20 * Hank Janssen <hjanssen@microsoft.com>
25 #include <linux/kernel.h>
28 #include "include/logging.h"
30 #include "VmbusPrivate.h"
34 typedef void (*PFN_CHANNEL_MESSAGE_HANDLER)(struct vmbus_channel_message_header *msg);
36 typedef struct _VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY {
37 enum vmbus_channel_message_type messageType;
38 PFN_CHANNEL_MESSAGE_HANDLER messageHandler;
39 } VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY;
41 /* Internal routines */
42 static void VmbusChannelOnOffer(struct vmbus_channel_message_header *hdr);
43 static void VmbusChannelOnOpenResult(struct vmbus_channel_message_header *hdr);
44 static void VmbusChannelOnOfferRescind(struct vmbus_channel_message_header *hdr);
45 static void VmbusChannelOnGpadlCreated(struct vmbus_channel_message_header *hdr);
46 static void VmbusChannelOnGpadlTorndown(struct vmbus_channel_message_header *hdr);
47 static void VmbusChannelOnOffersDelivered(struct vmbus_channel_message_header *hdr);
48 static void VmbusChannelOnVersionResponse(struct vmbus_channel_message_header *hdr);
49 static void VmbusChannelProcessOffer(void * context);
50 static void VmbusChannelProcessRescindOffer(void * context);
55 #define MAX_NUM_DEVICE_CLASSES_SUPPORTED 4
57 static const struct hv_guid gSupportedDeviceClasses[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = {
58 /* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
62 0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
63 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
67 /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
71 0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
72 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E
76 /* {CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} */
80 0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
81 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A
85 /* {32412632-86cb-44a2-9b5c-50d1417354f5} */
89 0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
90 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
95 /* Channel message dispatch table */
96 static VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY gChannelMessageTable[ChannelMessageCount]= {
97 {ChannelMessageInvalid, NULL},
98 {ChannelMessageOfferChannel, VmbusChannelOnOffer},
99 {ChannelMessageRescindChannelOffer, VmbusChannelOnOfferRescind},
100 {ChannelMessageRequestOffers, NULL},
101 {ChannelMessageAllOffersDelivered, VmbusChannelOnOffersDelivered},
102 {ChannelMessageOpenChannel, NULL},
103 {ChannelMessageOpenChannelResult, VmbusChannelOnOpenResult},
104 {ChannelMessageCloseChannel, NULL},
105 {ChannelMessageGpadlHeader, NULL},
106 {ChannelMessageGpadlBody, NULL},
107 {ChannelMessageGpadlCreated, VmbusChannelOnGpadlCreated},
108 {ChannelMessageGpadlTeardown, NULL},
109 {ChannelMessageGpadlTorndown, VmbusChannelOnGpadlTorndown},
110 {ChannelMessageRelIdReleased, NULL},
111 {ChannelMessageInitiateContact, NULL},
112 {ChannelMessageVersionResponse, VmbusChannelOnVersionResponse},
113 {ChannelMessageUnload, NULL},
122 Allocate and initialize a vmbus channel object
125 struct vmbus_channel *AllocVmbusChannel(void)
127 struct vmbus_channel *channel;
129 channel = kzalloc(sizeof(*channel), GFP_ATOMIC);
135 spin_lock_init(&channel->inbound_lock);
137 init_timer(&channel->poll_timer);
138 channel->poll_timer.data = (unsigned long)channel;
139 channel->poll_timer.function = VmbusChannelOnTimer;
141 /* channel->dataWorkQueue = WorkQueueCreate("data"); */
142 channel->ControlWQ = create_workqueue("hv_vmbus_ctl");
143 if (!channel->ControlWQ)
155 ReleaseVmbusChannel()
158 Release the vmbus channel object itself
161 static inline void ReleaseVmbusChannel(void* Context)
163 struct vmbus_channel *channel = Context;
167 DPRINT_DBG(VMBUS, "releasing channel (%p)", channel);
168 destroy_workqueue(channel->ControlWQ);
169 DPRINT_DBG(VMBUS, "channel released (%p)", channel);
182 Release the resources used by the vmbus channel object
185 void FreeVmbusChannel(struct vmbus_channel *Channel)
187 del_timer(&Channel->poll_timer);
189 /* We have to release the channel's workqueue/thread in the vmbus's workqueue/thread context */
190 /* ie we can't destroy ourselves. */
191 osd_schedule_callback(gVmbusConnection.WorkQueue, ReleaseVmbusChannel,
199 VmbusChannelProcessOffer()
202 Process the offer by creating a channel/device associated with this offer
206 VmbusChannelProcessOffer(
211 struct vmbus_channel *newChannel = context;
212 struct vmbus_channel *channel;
220 /* Make sure this is a new offer */
221 spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
223 ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelList)
225 channel = CONTAINING_RECORD(curr, struct vmbus_channel, ListEntry);
227 if (!memcmp(&channel->OfferMsg.Offer.InterfaceType, &newChannel->OfferMsg.Offer.InterfaceType,sizeof(struct hv_guid)) &&
228 !memcmp(&channel->OfferMsg.Offer.InterfaceInstance, &newChannel->OfferMsg.Offer.InterfaceInstance, sizeof(struct hv_guid)))
237 INSERT_TAIL_LIST(&gVmbusConnection.ChannelList, &newChannel->ListEntry);
239 spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
243 DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)", newChannel->OfferMsg.ChildRelId);
244 FreeVmbusChannel(newChannel);
249 /* Start the process of binding this offer to the driver */
250 /* We need to set the DeviceObject field before calling VmbusChildDeviceAdd() */
251 newChannel->DeviceObject = VmbusChildDeviceCreate(
252 &newChannel->OfferMsg.Offer.InterfaceType,
253 &newChannel->OfferMsg.Offer.InterfaceInstance,
256 DPRINT_DBG(VMBUS, "child device object allocated - %p", newChannel->DeviceObject);
259 * Add the new device to the bus. This will kick off device-driver
260 * binding which eventually invokes the device driver's AddDevice()
264 ret = VmbusChildDeviceAdd(newChannel->DeviceObject);
267 DPRINT_ERR(VMBUS, "unable to add child device object (relid %d)",
268 newChannel->OfferMsg.ChildRelId);
270 spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
271 REMOVE_ENTRY_LIST(&newChannel->ListEntry);
272 spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
274 FreeVmbusChannel(newChannel);
279 * This state is used to indicate a successful open
280 * so that when we do close the channel normally, we
281 * can cleanup properly
283 newChannel->State = CHANNEL_OPEN_STATE;
291 VmbusChannelProcessRescindOffer()
294 Rescind the offer by initiating a device removal
298 VmbusChannelProcessRescindOffer(
302 struct vmbus_channel *channel = context;
306 VmbusChildDeviceRemove(channel->DeviceObject);
315 VmbusChannelOnOffer()
318 Handler for channel offers from vmbus in parent partition. We ignore all offers except
319 network and storage offers. For each network and storage offers, we create a channel object
320 and queue a work item to the channel object to process the offer synchronously
323 static void VmbusChannelOnOffer(struct vmbus_channel_message_header *hdr)
325 struct vmbus_channel_offer_channel *offer = (struct vmbus_channel_offer_channel *)hdr;
326 struct vmbus_channel *newChannel;
328 struct hv_guid *guidType;
329 struct hv_guid *guidInstance;
335 for (i=0; i<MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++)
337 if (memcmp(&offer->Offer.InterfaceType, &gSupportedDeviceClasses[i], sizeof(struct hv_guid)) == 0)
346 DPRINT_DBG(VMBUS, "Ignoring channel offer notification for child relid %d", offer->ChildRelId);
352 guidType = &offer->Offer.InterfaceType;
353 guidInstance = &offer->Offer.InterfaceInstance;
355 DPRINT_INFO(VMBUS, "Channel offer notification - child relid %d monitor id %d allocated %d, "
356 "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x} "
357 "instance {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}",
360 offer->MonitorAllocated,
361 guidType->data[3], guidType->data[2], guidType->data[1], guidType->data[0],
362 guidType->data[5], guidType->data[4], guidType->data[7], guidType->data[6],
363 guidType->data[8], guidType->data[9], guidType->data[10], guidType->data[11],
364 guidType->data[12], guidType->data[13], guidType->data[14], guidType->data[15],
365 guidInstance->data[3], guidInstance->data[2], guidInstance->data[1], guidInstance->data[0],
366 guidInstance->data[5], guidInstance->data[4], guidInstance->data[7], guidInstance->data[6],
367 guidInstance->data[8], guidInstance->data[9], guidInstance->data[10], guidInstance->data[11],
368 guidInstance->data[12], guidInstance->data[13], guidInstance->data[14], guidInstance->data[15]);
370 /* Allocate the channel object and save this offer. */
371 newChannel = AllocVmbusChannel();
374 DPRINT_ERR(VMBUS, "unable to allocate channel object");
378 DPRINT_DBG(VMBUS, "channel object allocated - %p", newChannel);
380 memcpy(&newChannel->OfferMsg, offer, sizeof(struct vmbus_channel_offer_channel));
381 newChannel->MonitorGroup = (u8)offer->MonitorId / 32;
382 newChannel->MonitorBit = (u8)offer->MonitorId % 32;
384 /* TODO: Make sure the offer comes from our parent partition */
385 osd_schedule_callback(newChannel->ControlWQ, VmbusChannelProcessOffer,
395 VmbusChannelOnOfferRescind()
398 Rescind offer handler. We queue a work item to process this offer
402 static void VmbusChannelOnOfferRescind(struct vmbus_channel_message_header *hdr)
404 struct vmbus_channel_rescind_offer *rescind = (struct vmbus_channel_rescind_offer *)hdr;
405 struct vmbus_channel *channel;
409 channel = GetChannelFromRelId(rescind->ChildRelId);
412 DPRINT_DBG(VMBUS, "channel not found for relId %d", rescind->ChildRelId);
416 osd_schedule_callback(channel->ControlWQ,
417 VmbusChannelProcessRescindOffer,
427 VmbusChannelOnOffersDelivered()
430 This is invoked when all offers have been delivered.
434 static void VmbusChannelOnOffersDelivered(struct vmbus_channel_message_header *hdr)
444 VmbusChannelOnOpenResult()
447 Open result handler. This is invoked when we received a response
448 to our channel open request. Find the matching request, copy the
449 response and signal the requesting thread.
452 static void VmbusChannelOnOpenResult(struct vmbus_channel_message_header *hdr)
454 struct vmbus_channel_open_result *result = (struct vmbus_channel_open_result *)hdr;
457 struct vmbus_channel_msginfo *msgInfo;
458 struct vmbus_channel_message_header *requestHeader;
459 struct vmbus_channel_open_channel *openMsg;
464 DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status);
466 /* Find the open msg, copy the result and signal/unblock the wait event */
467 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
469 ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList)
471 msgInfo = (struct vmbus_channel_msginfo *)curr;
472 requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
474 if (requestHeader->MessageType == ChannelMessageOpenChannel)
476 openMsg = (struct vmbus_channel_open_channel *)msgInfo->Msg;
477 if (openMsg->ChildRelId == result->ChildRelId &&
478 openMsg->OpenId == result->OpenId)
480 memcpy(&msgInfo->Response.OpenResult, result, sizeof(struct vmbus_channel_open_result));
481 osd_WaitEventSet(msgInfo->WaitEvent);
486 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
495 VmbusChannelOnGpadlCreated()
498 GPADL created handler. This is invoked when we received a response
499 to our gpadl create request. Find the matching request, copy the
500 response and signal the requesting thread.
503 static void VmbusChannelOnGpadlCreated(struct vmbus_channel_message_header *hdr)
505 struct vmbus_channel_gpadl_created *gpadlCreated = (struct vmbus_channel_gpadl_created *)hdr;
508 struct vmbus_channel_msginfo *msgInfo;
509 struct vmbus_channel_message_header *requestHeader;
510 struct vmbus_channel_gpadl_header *gpadlHeader;
515 DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d", gpadlCreated->CreationStatus);
517 /* Find the establish msg, copy the result and signal/unblock the wait event */
518 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
520 ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList)
522 msgInfo = (struct vmbus_channel_msginfo *)curr;
523 requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
525 if (requestHeader->MessageType == ChannelMessageGpadlHeader)
527 gpadlHeader = (struct vmbus_channel_gpadl_header *)requestHeader;
529 if ((gpadlCreated->ChildRelId == gpadlHeader->ChildRelId) &&
530 (gpadlCreated->Gpadl == gpadlHeader->Gpadl))
532 memcpy(&msgInfo->Response.GpadlCreated, gpadlCreated, sizeof(struct vmbus_channel_gpadl_created));
533 osd_WaitEventSet(msgInfo->WaitEvent);
538 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
547 VmbusChannelOnGpadlTorndown()
550 GPADL torndown handler. This is invoked when we received a response
551 to our gpadl teardown request. Find the matching request, copy the
552 response and signal the requesting thread.
555 static void VmbusChannelOnGpadlTorndown(struct vmbus_channel_message_header *hdr)
557 struct vmbus_channel_gpadl_torndown* gpadlTorndown = (struct vmbus_channel_gpadl_torndown *)hdr;
560 struct vmbus_channel_msginfo *msgInfo;
561 struct vmbus_channel_message_header *requestHeader;
562 struct vmbus_channel_gpadl_teardown *gpadlTeardown;
567 /* Find the open msg, copy the result and signal/unblock the wait event */
568 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
570 ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList)
572 msgInfo = (struct vmbus_channel_msginfo *)curr;
573 requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
575 if (requestHeader->MessageType == ChannelMessageGpadlTeardown)
577 gpadlTeardown = (struct vmbus_channel_gpadl_teardown *)requestHeader;
579 if (gpadlTorndown->Gpadl == gpadlTeardown->Gpadl)
581 memcpy(&msgInfo->Response.GpadlTorndown, gpadlTorndown, sizeof(struct vmbus_channel_gpadl_torndown));
582 osd_WaitEventSet(msgInfo->WaitEvent);
587 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
596 VmbusChannelOnVersionResponse()
599 Version response handler. This is invoked when we received a response
600 to our initiate contact request. Find the matching request, copy the
601 response and signal the requesting thread.
604 static void VmbusChannelOnVersionResponse(struct vmbus_channel_message_header *hdr)
608 struct vmbus_channel_msginfo *msgInfo;
609 struct vmbus_channel_message_header *requestHeader;
610 struct vmbus_channel_initiate_contact *initiate;
611 struct vmbus_channel_version_response *versionResponse = (struct vmbus_channel_version_response *)hdr;
616 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
618 ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList)
620 msgInfo = (struct vmbus_channel_msginfo *)curr;
621 requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
623 if (requestHeader->MessageType == ChannelMessageInitiateContact)
625 initiate = (struct vmbus_channel_initiate_contact *)requestHeader;
626 memcpy(&msgInfo->Response.VersionResponse, versionResponse, sizeof(struct vmbus_channel_version_response));
627 osd_WaitEventSet(msgInfo->WaitEvent);
630 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
639 VmbusOnChannelMessage()
642 Handler for channel protocol messages.
643 This is invoked in the vmbus worker thread context.
646 void VmbusOnChannelMessage(void *Context)
648 struct hv_message *msg = Context;
649 struct vmbus_channel_message_header *hdr;
654 hdr = (struct vmbus_channel_message_header *)msg->u.Payload;
655 size=msg->Header.PayloadSize;
657 DPRINT_DBG(VMBUS, "message type %d size %d", hdr->MessageType, size);
659 if (hdr->MessageType >= ChannelMessageCount)
661 DPRINT_ERR(VMBUS, "Received invalid channel message type %d size %d", hdr->MessageType, size);
662 print_hex_dump_bytes("", DUMP_PREFIX_NONE,
663 (unsigned char *)msg->u.Payload, size);
668 if (gChannelMessageTable[hdr->MessageType].messageHandler)
670 gChannelMessageTable[hdr->MessageType].messageHandler(hdr);
674 DPRINT_ERR(VMBUS, "Unhandled channel message type %d", hdr->MessageType);
677 /* Free the msg that was allocated in VmbusOnMsgDPC() */
686 VmbusChannelRequestOffers()
689 Send a request to get all our pending offers.
692 int VmbusChannelRequestOffers(void)
695 struct vmbus_channel_message_header *msg;
696 struct vmbus_channel_msginfo *msgInfo;
700 msgInfo = kmalloc(sizeof(*msgInfo) + sizeof(struct vmbus_channel_message_header), GFP_KERNEL);
701 ASSERT(msgInfo != NULL);
703 msgInfo->WaitEvent = osd_WaitEventCreate();
704 msg = (struct vmbus_channel_message_header *)msgInfo->Msg;
706 msg->MessageType = ChannelMessageRequestOffers;
708 /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
709 INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList, &msgInfo->msgListEntry);
710 SpinlockRelease(gVmbusConnection.channelMsgLock);*/
712 ret = VmbusPostMessage(msg, sizeof(struct vmbus_channel_message_header));
715 DPRINT_ERR(VMBUS, "Unable to request offers - %d", ret);
717 /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
718 REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
719 SpinlockRelease(gVmbusConnection.channelMsgLock);*/
723 /* osd_WaitEventWait(msgInfo->waitEvent); */
725 /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
726 REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
727 SpinlockRelease(gVmbusConnection.channelMsgLock);*/
733 kfree(msgInfo->WaitEvent);
745 VmbusChannelReleaseUnattachedChannels()
748 Release channels that are unattached/unconnected ie (no drivers associated)
751 void VmbusChannelReleaseUnattachedChannels(void)
754 struct vmbus_channel *channel;
755 struct vmbus_channel *start = NULL;
758 spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
760 while (!IsListEmpty(&gVmbusConnection.ChannelList))
762 entry = TOP_LIST_ENTRY(&gVmbusConnection.ChannelList);
763 channel = CONTAINING_RECORD(entry, struct vmbus_channel, ListEntry);
765 if (channel == start)
768 if (!channel->DeviceObject->Driver)
770 REMOVE_ENTRY_LIST(&channel->ListEntry);
771 DPRINT_INFO(VMBUS, "Releasing unattached device object %p", channel->DeviceObject);
773 VmbusChildDeviceRemove(channel->DeviceObject);
774 FreeVmbusChannel(channel);
785 spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);